1
1
mirror of https://github.com/rsms/inter.git synced 2024-11-26 23:56:59 +03:00
inter/docs/index-var.js
Rasmus Andersson ba49662904 release 3.8
2019-08-04 19:35:36 -07:00

200 lines
4.9 KiB
JavaScript

(function(){
var root = document.querySelector('div.variable')
var sample = document.querySelector('.variable-sample')
var animateCheckbox = document.querySelector('[name="animate"]')
var ui = {
state: {
weight: 0,
slant: 0,
size: 0, // px
letterSpacing: 0, // em
lineHeight: 0,
},
variable: {
weight: true,
slant: true,
},
formatters: {
size(v) { return `${v}px` },
letterSpacing(v) { return `${v}em` },
},
inputs: {
// populated by init()
},
init() {
let s = getComputedStyle(sample)
// We test for variable-font support by, in CSS, conditionally using
// a different font family name when VF is supported. Then we test for
// what font family name is in effect. If it's the "var" one, we can be
// fairly certain that variable fonts are supported by the user agent.
let supportsVF = s.fontFamily.indexOf('Inter var') != -1
// hook up input controls
for (let k in this.state) {
let value = parseFloat(s.getPropertyValue(`--var-${k}`))
this.state[k] = value
let input = root.querySelector(`[name="${k}"]`)
if (input) {
this.inputs[k] = input
input.value = value
if (!supportsVF && this.variable[k]) {
input.disabled = true
input.parentElement.classList.add('disabled')
} else if (input.type == 'range') {
this.bindRangeControl(input, v => {
this.state[k] = v
this.update()
})
}
}
}
if (!supportsVF) {
animateCheckbox.disabled = true
animateCheckbox.parentElement.classList.add('disabled')
let unsupportedMessage = root.querySelector(`.unsupported-message`)
if (unsupportedMessage) {
unsupportedMessage.classList.add('active')
}
} else {
this.state.size = window.innerWidth / 10
root.querySelector(`[name="size"]`).value = this.state.size
this.update()
}
},
bindRangeControl(rangeInput, handler) {
rangeInput.addEventListener('input',
rangeInput.valueAsNumber !== undefined ? ev => {
handler(rangeInput.valueAsNumber)
} : ev => {
handler(parseFloat(rangeInput.value))
}
)
},
setState(props) {
for (let k in props) {
if (k in this.state) {
this.state[k] = props[k]
}
}
this.update()
},
update() {
let s = sample.style
for (let k in this.state) {
let f = this.formatters[k]
let v = this.state[k]
if (k == "slant") {
// negate slant value (negative values causes positive grades)
v = -v
}
s.setProperty(`--var-${k}`, f ? f(v) : v)
}
},
}
// 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()
}
)
var isAnimating = false
function startAnimation() {
if (isAnimating) {
return
}
ui.inputs.weight.disabled = true
ui.inputs.slant.disabled = true
isAnimating = true
let v = 0
let wmin = parseFloat(ui.inputs.weight.min)
, wmax = parseFloat(ui.inputs.weight.max)
, imin = parseFloat(ui.inputs.slant.min)
, imax = parseFloat(ui.inputs.slant.max)
, wspeed = 800 // lower is faster; time divisor
, ispeed = 1600
, clamp = 0.001
, startTime = monotime()
function update() {
let r = 0, v = 0
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.state.weight = v
ui.inputs.weight.value = v
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.state.slant = v
ui.inputs.slant.value = v
ui.update()
if (isAnimating) {
requestAnimationFrame(update)
}
}
update()
}
function stopAnimation() {
isAnimating = false
ui.inputs.weight.disabled = false
ui.inputs.slant.disabled = false
ui.inputs.weight.value = String(ui.state.weight)
ui.inputs.slant.value = String(ui.state.slant)
}
// UI control: animate
if (!window.requestAnimationFrame) {
animateCheckbox.disabled = true
animateCheckbox.title = "Not supported by browser"
} else {
animateCheckbox.addEventListener('change', ev => {
if (animateCheckbox.checked) {
startAnimation()
} else {
stopAnimation()
}
})
}
// UI control: invert colors ("Black/White")
document.querySelector('[name="invert"]').addEventListener('change', ev => {
if (ev.target.checked) {
sample.parentElement.classList.add('black')
sample.parentElement.classList.remove('white')
} else {
sample.parentElement.classList.remove('black')
sample.parentElement.classList.add('white')
}
})
ui.init()
})();