mirror of
https://github.com/rsms/inter.git
synced 2024-12-12 15:22:36 +03:00
253 lines
6.2 KiB
HTML
253 lines
6.2 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<link href="../inter.css" rel="stylesheet">
|
|
<style type="text/css">
|
|
|
|
:root {
|
|
--weight: 400;
|
|
--slant: 0;
|
|
--size: 80px;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Inter var';
|
|
font-weight: 100 900;
|
|
font-style: oblique 0deg 10deg;
|
|
src: url('fonts/var/Inter.var.woff2') format("woff2-variations"),
|
|
url('../font-files/Inter.var.woff2') format("woff2-variations");
|
|
}
|
|
|
|
html {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 14px;
|
|
letter-spacing: 0;
|
|
}
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.sample {
|
|
padding: 40px 40px 40px 35px;
|
|
font-size: var(--size);
|
|
letter-spacing: -0.03em;
|
|
font-variation-settings: 'wght' var(--weight), 'slnt' calc(-1 * var(--slant));
|
|
}
|
|
|
|
@supports (font-variation-settings: normal) {
|
|
html {
|
|
font-family: 'Inter var', sans-serif;
|
|
}
|
|
}
|
|
|
|
label {
|
|
user-select: none;
|
|
}
|
|
|
|
.ctrl {
|
|
display: flex;
|
|
/*justify-content:center;*/
|
|
align-items:center;
|
|
background: #e5e5e5;
|
|
color: #333;
|
|
padding:20px 20px 20px 40px;
|
|
}
|
|
.ctrl input {
|
|
margin:0 8px;
|
|
}
|
|
.ctrl label {
|
|
display: flex;
|
|
/*justify-content:center;*/
|
|
align-items:center;
|
|
margin-right:20px;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="ctrl">
|
|
<label>Weight: <input type="range" value="400" min="100" max="900" name="weight"></label>
|
|
<label>Slant: <input type="range" value="0" min="0" max="10" step="0.01" name="slant"></label>
|
|
<label>Size: <input type="range" value="96" min="6" max="400" name="size"></label>
|
|
<select name="animate">
|
|
<option value="" default>Animation: off</option>
|
|
<option value="weight">Animation: weight</option>
|
|
<option value="slant">Animation: slant</option>
|
|
<option value="weight,slant">Animation: weight & slant</option>
|
|
</select>
|
|
<select name="align">
|
|
<option value="left" default>Align: left</option>
|
|
<option value="center">Align: center</option>
|
|
<option value="right">Align: right</option>
|
|
</select>
|
|
</div>
|
|
<div class="sample" contenteditable>
|
|
Inter Typeface Family<br>
|
|
Variable weight axis<br>
|
|
Variable slant/oblique axis<br>
|
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
|
abcdefghijklmnopqrstuvwxyz<br>
|
|
1234567890?!()[]{}&*^%$#@~<><br>
|
|
</div>
|
|
<script type="text/javascript">
|
|
|
|
|
|
|
|
var samples = document.querySelectorAll('div.sample')
|
|
var weightInput = document.querySelector('[name="weight"]')
|
|
var slantInput = document.querySelector('[name="slant"]')
|
|
var sizeInput = document.querySelector('[name="size"]')
|
|
|
|
|
|
var ui = {
|
|
weight: parseFloat(weightInput.value),
|
|
slant: parseFloat(slantInput.value),
|
|
size: parseFloat(sizeInput.value),
|
|
|
|
setState(props) {
|
|
for (let k in props) {
|
|
if (k in this) {
|
|
this[k] = props[k]
|
|
}
|
|
}
|
|
this.update()
|
|
},
|
|
|
|
update() {
|
|
let s = document.body.style
|
|
s.setProperty(`--weight`, this.weight)
|
|
s.setProperty(`--slant`, this.slant)
|
|
s.setProperty(`--size`, `${this.size}px`)
|
|
// for (let i = 0; i < samples.length; i++) {
|
|
// let sample = samples[i]
|
|
// // sample.style.fontVariationSettings =
|
|
// // `'wght' ${ui.weight}, 'ital' ${ui.slant}`
|
|
// sample.style.fontVariationSettings =
|
|
// `'wght' ${ui.weight}, 'slnt' ${ui.slant}`
|
|
// }
|
|
},
|
|
}
|
|
|
|
ui.update()
|
|
|
|
// monotime() :float milliseconds
|
|
//
|
|
var monotime = (
|
|
window.performance !== undefined && window.performance.now ? function() {
|
|
return window.performance.now()
|
|
} : Date.now ? function() {
|
|
return Date.now()
|
|
} : function() {
|
|
return (new Date()).getTime()
|
|
}
|
|
)
|
|
|
|
|
|
// animation state
|
|
var isAnimating = false
|
|
var animateWeight = false
|
|
var animateSlant = false
|
|
|
|
function startAnimation(animateAxes) {
|
|
animateWeight = animateAxes.indexOf('weight') != -1
|
|
animateSlant = animateAxes.indexOf('slant') != -1
|
|
weightInput.disabled = animateWeight
|
|
slantInput.disabled = animateSlant
|
|
if (isAnimating) {
|
|
return
|
|
}
|
|
if (!animateWeight && !animateSlant) {
|
|
throw new Error('!animateWeight && !animateSlant')
|
|
stopAnimation()
|
|
}
|
|
isAnimating = true
|
|
let v = 0
|
|
let wmin = parseFloat(weightInput.min)
|
|
, wmax = parseFloat(weightInput.max)
|
|
, imin = parseFloat(slantInput.min)
|
|
, imax = parseFloat(slantInput.max)
|
|
, wspeed = 800 // lower is faster; time divisor
|
|
, ispeed = 600
|
|
, clamp = 0.001
|
|
, startTime = monotime()
|
|
function update() {
|
|
let r = 0, v = 0
|
|
|
|
if (animateWeight) {
|
|
r = (1 + Math.sin((monotime() - startTime) / wspeed)) * 0.5
|
|
v = (wmin * (1 - clamp)) + (((wmax * (1 + clamp)) - (wmin * (1 - clamp))) * r)
|
|
v = Math.max(wmin, Math.min(wmax, v))
|
|
ui.weight = v
|
|
weightInput.value = v
|
|
}
|
|
|
|
if (animateSlant) {
|
|
r = (1 + Math.sin((monotime() - startTime) / ispeed)) * 0.5
|
|
v = (imin * (1 - clamp)) + (((imax * (1 + clamp)) - (imin * (1 - clamp))) * r)
|
|
v = Math.max(imin, Math.min(imax, v))
|
|
ui.slant = v
|
|
slantInput.value = v
|
|
}
|
|
|
|
ui.update()
|
|
|
|
if (isAnimating) {
|
|
requestAnimationFrame(update)
|
|
}
|
|
}
|
|
update()
|
|
}
|
|
|
|
function stopAnimation() {
|
|
isAnimating = false
|
|
weightInput.disabled = false
|
|
slantInput.disabled = false
|
|
weightInput.value = String(ui.weight)
|
|
slantInput.value = String(ui.slant)
|
|
}
|
|
|
|
function bindRangeControl(rangeInput, handler) {
|
|
rangeInput.addEventListener('input',
|
|
rangeInput.valueAsNumber !== undefined ? ev => {
|
|
handler(rangeInput.valueAsNumber)
|
|
} : ev => {
|
|
handler(parseFloat(rangeInput.value))
|
|
}
|
|
)
|
|
}
|
|
|
|
// UI controls
|
|
bindRangeControl(weightInput, weight => ui.setState({ weight }) )
|
|
bindRangeControl(slantInput, slant => ui.setState({ slant }) )
|
|
bindRangeControl(sizeInput, size => ui.setState({ size }) )
|
|
|
|
// UI control: alignment
|
|
var alignInput = document.querySelector('[name="align"]')
|
|
var updateAlignment = function() {
|
|
for (let s of samples) {
|
|
s.style.textAlign = alignInput.value
|
|
}
|
|
}
|
|
alignInput.addEventListener('change', updateAlignment)
|
|
updateAlignment()
|
|
|
|
// UI control: animate
|
|
var animateInput = document.querySelector('[name="animate"]')
|
|
if (!window.requestAnimationFrame) {
|
|
animateInput.disabled = true
|
|
} else {
|
|
animateInput.addEventListener('change', ev => {
|
|
if (animateInput.value.length == 0) {
|
|
stopAnimation()
|
|
} else {
|
|
console.log('x', animateInput.value.split(','))
|
|
startAnimation(animateInput.value.split(','))
|
|
}
|
|
})
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html> |