diff options
Diffstat (limited to 'docs/dynmetrics/index.html')
-rw-r--r-- | docs/dynmetrics/index.html | 684 |
1 files changed, 9 insertions, 675 deletions
diff --git a/docs/dynmetrics/index.html b/docs/dynmetrics/index.html index 07cf908c9..2c9cc54cd 100644 --- a/docs/dynmetrics/index.html +++ b/docs/dynmetrics/index.html @@ -1,683 +1,17 @@ --- layout: default -title: Dynamic Metrics +title: 404 not found +custom_html_header: | + <link rel="canonical" href="https://d.rsms.me/inter-website/v3/dynmetrics/"> + <meta name="robots" content="noindex"> --- -{% - -if site.safe == false %}{% -assign url_root = "/" %}{% else %}{% -assign url_root = "/inter/" %}{% endif %}{% - -for file in site.static_files %}{% - assign _path = file.path | remove_first: "/inter" %}{% - if _path == "/dynmetrics/index.css" %}{% - assign index_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% - elsif _path == "/res/bindings.js" %}{% - assign bindings_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% - elsif _path == "/res/graphplot.js" %}{% - assign graphplot_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% - endif %}{% -endfor - -%} -<link rel="stylesheet" href="index.css?v={{ index_css_v }}"> -<script src="{{url_root}}res/bindings.js?v={{ bindings_js_v }}"></script> -<script src="{{url_root}}res/graphplot.js?v={{ graphplot_js_v }}"></script> - -<div class="row first"><div> - <h1>Dynamic Metrics</h1> +<div class="row"><div> + <h1>404 not found</h1> <p> - There's of course no absolute right or wrong when it comes to expressing - yourself with typography, but Inter Dynamic Metrics provides guidelines - for how to best use Inter. - You simply provide the optical font size, - and the tracking and line height is calculated for you through the following - formula: + This page used to exist, but is no longer.<br> </p> <p> - <formula> - tracking = - <const>a</const> + <const>b</const> × - <const title="Base of natural logarithm; ≈2.718">e</const><sup>(<const>c</const> × <const>z</const>)</sup> - </formula> - <!--formula> - line height = <num data-binding="var-l">1.4</num> × <const>z</const> - </formula--> - <formula title="Values for Inter"> - <g><const title="Constant a">a</const> = <num data-binding="var-a">-0.0223</num></g> - <g><const title="Constant b">b</const> = <num data-binding="var-b">0.185</num></g> - <g><const title="Constant c">c</const> = <num data-binding="var-c">-0.1745</num></g> - <g><const>z</const> = font size</g> - </formula> - </p> - <p class="wide-window"> - The controls below can be used to play around with the - <const>a</const>, <const>b</const> and <const>c</const> constants to discover - how they affect tracking. - </p> - <p class="narrow-window"> - <small>View this on a larger screen to enable interactive control.</small> + You can visit an archived version of the old website: + <a href="https://d.rsms.me/inter-website/v3/dynmetrics/">https://d.rsms.me/inter-website/v3/dynmetrics/</a> </p> </div></div> - -<div class="white full-width row with-sidebar"> - - <div class="samples"> - <p class="sample"> - <span class="di"><span></span></span> - <span class="info" - title="size, tracking, (ideal tracking) — progress bar shows distance from ideal" - >15 0.0 ( 0.0 )</span> - <span contenteditable spellcheck="false" class="content"> - Such a riot of sea and wind strews the whole extent of beach with whatever has been lost or thrown overboard, or torn out of sunken ships. Many a man has made a good week’s work in a single day by what he has found while walking along the Beach when the surf was down. - </span> - </p> - </div> - - <div class="sidebar controls"> - - <div class="control"> - <img title="Style" class="icon" src="icons/style.svg"> - <select data-binding="style"> - <option value="thin">Thin</option> - <option value="extra-light">Extra Light</option> - <option value="light">Light</option> - <option value="regular" default selected>Regular</option> - <option value="medium">Medium</option> - <option value="semi-bold">Semi Bold</option> - <option value="bold">Bold</option> - <option value="extra-bold">Extra Bold</option> - <option value="black">Black</option> - <option disabled>————————————</option> - <option value="thin-italic">Thin Italic</option> - <option value="extra-light-italic">Extra Light Italic</option> - <option value="light-italic">Light Italic</option> - <option value="italic">Italic</option> - <option value="medium-italic">Medium Italic</option> - <option value="semi-bold-italic">Semi Bold Italic</option> - <option value="bold-italic">Bold Italic</option> - <option value="extra-bold-italic">Extra Bold Italic</option> - <option value="black-italic">Black Italic</option> - </select> - </div> - <div class="control"> - <img title="Base tracking" class="icon" src="icons/letter-spacing.svg"> - <input type="range" min="-0.05" max="0.06" step="0.001" data-binding="base-tracking"> - <input type="number" min="-0.15" max="1" step="0.001" data-binding="base-tracking"> - </div> - <div class="control"> - <img title="Line height" class="icon" src="icons/line-height.svg"> - <input type="range" min="1" max="2" step="0.01" data-binding="var-l"> - <input type="number" min="1" max="2" step="0.01" data-binding="var-l"> - </div> - - <hr> - - <div class="control"> - <label title="Constant a">a</label> - <input type="range" min="-0.05" max="0" step="0.001" data-binding="var-a"> - <input type="number" min="-0.05" max="0" step="0.0001" data-binding="var-a"> - </div> - <div class="control"> - <label title="Constant b">b</label> - <input type="range" min="0" max="1" step="0.01" data-binding="var-b"> - <input type="number" min="0" max="1" step="0.001" data-binding="var-b"> - </div> - <div class="control"> - <label title="Constant c">c</label> - <input type="range" min="-1" max="0" step="0.01" data-binding="var-c"> - <input type="number" min="-1" max="0" step="0.001" data-binding="var-c"> - </div> - - <hr> - - <div class="control"> - <label title="Number of ideal matches">ni</label> - <input title="Number of ideal matches" type="number" readonly data-binding="ideal-count"> - <label title="Distance from ideal">di</label> - <input title="Distance from ideal" type="number" class="wide" readonly data-binding="ideal-distance"> - </div> - - <hr class="without-bottom-margin"> - - <canvas class="graphplot">Canvas not Supported</canvas> - - <hr class="when-selection without-top-margin"> - <h3 class="when-selection">CSS</h3> - <textarea class="when-selection" readonly id="code-output"></textarea> - - <hr class="without-top-margin"> - <h3>Ideal values</h3> - <textarea id="ideal-values"></textarea> - <hr class="without-top-margin"> - </div> - -</div> - - -<script type="text/javascript">(function(){ - -// internal variables that are user-controllable, but are not part of -// Dynamic Metrics -var baseTracking = 0 -var weightClass = 400 - -function round(num, prec) { - return parseFloat(num.toFixed(prec)) -} - -// Ideal values designed one by one, by hand. -// font size => tracking -var idealValues = {} -var idealValuesList = [] -var idealValuesTextArea = $('textarea#ideal-values') - -function setIdealValues(valueMap) { - idealValues = valueMap - idealValuesList = [] - Object.keys(idealValues).forEach(function(fontSize) { - idealValuesList.push([fontSize, idealValues[fontSize]]) - }) - if (idealValuesTextArea.value == '') { - idealValuesTextArea.value = idealValuesList.map(function(t){ - return t[0] + '\t' + t[1] - }).join('\n') - } -} - -function parseValues(s) { - var values = {} - s = s.replace(/^[\s\r\t\n]+|[\s\r\t\n]+$/g, '') // trim whitespace - s.split(/\s*\r?\n\s*/).map(function(line) { - var t = line.split(/\s+/) - if (t.length == 2) { - t[0] = parseInt(t[0]) - t[1] = parseFloat(t[1]) - values[t[0]] = t[1] - } - }) - return values -} - -setIdealValues({ - // // 2018 - // 6: 0.021, - // 7: 0.017, - // 8: 0.013, - // 9: 0.01, - // 10: 0.007, - // 11: 0.005, - // 12: 0.002, - // 13: 0, - // 14: -0.002, - // 15: -0.004, - // 16: -0.005, - // 17: -0.007, - // 18: -0.008, - // 20: -0.01, - // 24: -0.013, - // 30: -0.016, - // 40: -0.02, - // 80: -0.02, - - // 2019-02-02 - // 6: 0.066, - // 7: 0.05, - // 8: 0.036, - // 9: 0.025, - // 10: 0.015, - // 11: 0.007, - // 12: 0, - // 13: -0.005, - // 14: -0.01, - // 15: -0.014, - // 16: -0.017, - // 17: -0.02, - // 18: -0.022, - // 20: -0.026, - // 24: -0.03, - // 30: -0.033, - // 40: -0.034, - // 80: -0.034, - - // // 2019-02-06 - // 6: 0.04, - // 7: 0.032, - // 8: 0.024, - // 9: 0.017, - // 10: 0.01, - // 11: 0.005, - // 12: 0, - // 13: -0.004, - // 14: -0.008, - // 15: -0.011, - // 16: -0.014, - // 17: -0.017, - // 18: -0.019, - // 20: -0.023, - // 24: -0.029, - // 30: -0.034, - // 40: -0.037, - // 80: -0.038, - - // 2019-02-07 - 6: 0.043, - 7: 0.032, - 8: 0.024, - 9: 0.016, - 10: 0.01, - 11: 0.005, - 12: 0, - 13: -0.0025, - 14: -0.006, - 15: -0.009, - 16: -0.011, - 17: -0.013, - 18: -0.014, - 20: -0.017, - 24: -0.019, - 30: -0.021, - 40: -0.022, - 80: -0.022, -}) - - -// Variables for constants involved in Dynamic Metrics - -// var a = -0.012, b = 0.23, c = -0.21; // di=0.002514 on set-2018-02-18 -// var a = -0.013, b = 0.251, c = -0.222 // di=0.001742 on set-2018-02-18 -// var a = -0.015, b = 0.283, c = -0.23; // di=0.00221 on set-2018-02-18 -// var a = -0.0149, b = 0.298, c = -0.23; // di=0.000484 on set-2018-02-19 -// var a = -0.018, b = 0.21, c = -0.18; // di=0.000532 on set-2018-02-20 -// var a = -0.017, b = 0.202, c = -0.175; // 2018-09-28 -// var a = -0.02, b = 0.0755, c = -0.102 // 2019-02-02 -// var a = -0.038, b = 0.161, c = -0.12 // 2019-02-06 -var a = -0.0223, b = 0.185, c = -0.1745 // 2019-02-07 - - -var l = 1.4 - - -// _InterDynamicTracking is a version of InterDynamicTracking that -// uses some global variables that are adjustable. -// -function _InterDynamicTracking(fontSize, weightClass) { - // Note: weightClass is currently unused - // - // y = -0.01021241 + 0.3720623 * e ^ (-0.2808687 * x) - // [6-35] 0.05877 .. -0.0101309 (13==0; stops growing around 30-35) - // See https://gist.github.com/rsms/8efdbca5f8145a584ed08a7c3d6e5788 - // - return a + b * Math.pow(Math.E, c * fontSize) -} - - -function InterDynamicLineHeight(fontSize, weightClass) { - return Math.round(fontSize * l) -} - - -var NPOS = Number.MAX_SAFE_INTEGER - -function Sample(fontSize) { - this.rootEl = sampleTemplate.cloneNode(true) - this.infoEl = $('.info', this.rootEl) - this.contentEl = $('.content', this.rootEl) - this.diEl = $('.di', this.rootEl) - this.diEl.classList.add('unavailable') - this.style = this.rootEl.style - this.maxBoxWidth = 0 - this.fontSize = 0 - this.tracking = 0 - this.lineHeight = 0 - this.idealTracking = NPOS - this.matchesIdeal = false - this.setFontSize(fontSize) - this.render() - - // listen for focus events on the editable content - var s = this - this.contentEl.addEventListener( - 'focus', - function(){ s.onReceivedFocus() }, - {passive:true, capture:false} - ) - this.contentEl.addEventListener( - 'blur', - function(){ s.onLostFocus() }, - {passive:true, capture:false} - ) -} - -Sample.prototype.onReceivedFocus = function() {} -Sample.prototype.onLostFocus = function() {} - -Sample.prototype.idealDistance = function(fontSize) { - // returns the distance from the ideal (or NPOS if no "ideal" data available) - if (this.idealTracking == NPOS) { - return NPOS - } - return ( - Math.max(this.tracking, this.idealTracking) - - Math.min(this.tracking, this.idealTracking) - ) -} - -Sample.prototype.setFontSize = function(fontSize) { - this.fontSize = fontSize - this.tracking = baseTracking + _InterDynamicTracking(fontSize, weightClass) - this.lineHeight = InterDynamicLineHeight(fontSize, weightClass) - this.maxBoxWidth = Math.round(fontSize * (this.tracking + 1) * 25) - - var idealTracking = idealValues[this.fontSize] - if (idealTracking === undefined) { - if (this.idealTracking != NPOS) { - this.diEl.classList.add('unavailable') - } - this.idealTracking = NPOS - this.matchesIdeal = false - } else { - if (this.idealTracking == NPOS) { - this.diEl.classList.remove('unavailable') - } - this.idealTracking = idealTracking - // match to a precision of 3 - this.matchesIdeal = this.tracking.toFixed(3) == idealTracking.toFixed(3) - var di = 1 - if (this.matchesIdeal) { - this.diEl.classList.add('match') - } else { - this.diEl.classList.remove('match') - di = 1 - Math.min(1, this.idealDistance() * 50) - } - this.diEl.firstChild.style.width = (di * this.maxBoxWidth) + 'px' - } -} - -Sample.prototype.cssProperties = function() { - return [ - ['font-size', round(this.fontSize, 3) + 'px'], - ['letter-spacing', round(this.tracking, 3) + 'em'], - ['line-height', round(this.lineHeight, 3) + 'px'], - ] -} - -Sample.prototype.setText = function(text) { - this.contentEl.innerText = text - this.render() -} - -Sample.prototype.render = function() { - this.style.fontSize = this.fontSize + 'px' - this.style.letterSpacing = this.tracking + 'em' - this.style.lineHeight = this.lineHeight + 'px' - - var SP = '\u00A0\u00A0\u00A0' - this.infoEl.innerText = ( - this.fontSize + - SP + this.tracking.toFixed(3) + - // SP + this.lineHeight.toFixed(3) + - ( - this.idealTracking != NPOS ? ( - SP + '( ' + this.idealTracking + - (this.matchesIdeal ? ' \u2713' : '') + - ' )' - ) : '' - ) - ) - - this.style.maxWidth = this.maxBoxWidth + 'px' -} - - -var bindings = new Bindings() -var samplesEl = $('.samples') -var sampleTemplate -var samples = [] // Sample[] -var focusedSample = null // Sample | null -var graph = new GraphPlot($('canvas.graphplot')) -graph.setOrigin(-0.2, 0.8) -graph.setScale(0.049, 5) - -function addChildren(targetNode, children) { - targetNode.style.visibility = 'hidden' - var i = 0; - for (; i < children.length; i++) { - targetNode.appendChild(children[i]) - } - targetNode.style.visibility = null -} - -function initSamples() { - sampleTemplate = $('.sample', samplesEl) - samplesEl.removeChild(sampleTemplate) - - // small and medium sizes - var i, fontSize = 6, endFontSize = 16 - for (; fontSize <= endFontSize; fontSize++) { - samples.push(new Sample(fontSize)) - } - - // a few select large samples - samples.push(new Sample(17)) - samples.push(new Sample(18)) - samples.push(new Sample(20)) - samples.push(new Sample(24)) - samples.push(new Sample(30)) - samples.push(new Sample(40)) - samples.push(new Sample(80)) - - // connect focus events - var onSampleReceivedFocus = function() { setSelectedSample(this) } - samples.forEach(function(s) { - s.onReceivedFocus = onSampleReceivedFocus - }) - - // add to dom in one go - addChildren(samplesEl, samples.map(function(s) { return s.rootEl })) -} - -function setSelectedSample(sample) { - if (focusedSample !== sample) { - if (focusedSample) { - focusedSample.rootEl.classList.remove('selected') - } - if (sample) { - sample.rootEl.classList.add('selected') - } - focusedSample = sample - updateSelection() - } -} - -function updateSample(sample) { - sample.setFontSize(sample.fontSize) // updates derived values - sample.render() -} - -function updateSamples() { - samples.forEach(updateSample) - updateIdealMatches() - updateGraphPlot() - updateCodeView() -} - -function updateIdealMatches() { - // ideal-distance - var idealCount = 0 - var distance = 0 - var ndistances = 0 - samples.forEach(function(sample) { - if (sample.matchesIdeal) { - idealCount++ - } - var di = sample.idealDistance() - if (di != NPOS) { - distance += di - ndistances++ - } - }) - - distance = distance / ndistances - - bindings.setValue('ideal-distance', distance.toFixed(6)) - bindings.setValue('ideal-count', idealCount) -} - -function updateGraphPlot() { - graph.clear() - graph.plotLine(idealValuesList, '#0d3') - graph.plotf( - x => _InterDynamicTracking(x, weightClass), - 'rgba(0, 0, 0, 0.5)' - ) - if (focusedSample) { - var graphedFontSize = Math.min(24, focusedSample.fontSize) // clamp to [-inf,24] - graph.plotPoints([ - [graphedFontSize, focusedSample.tracking] - ], 'rgb(45, 143, 255)') - } -} - -var codeOutput = $('#code-output') -codeOutput.addEventListener('focus', function(ev) { - ev.preventDefault() - ev.stopPropagation() - codeOutput.select() -}, {passive:false,capture:true}) - -codeOutput.addEventListener('pointerdown', function(ev) { - // TODO: don't do this if codeOutput is focused - ev.preventDefault() - ev.stopPropagation() - codeOutput.select() - document.execCommand("copy") - HUDNotification.show('Copied to clipboard') -}, {passive:false,capture:true}) - -function updateCodeView() { - var s = '' - if (focusedSample) { - var props = focusedSample.cssProperties() - props.forEach(function(prop, i) { - var name = prop[0], value = prop[1] - s += name + ': ' + value + ';' - if (i != props.length-1) { - s += '\n' - } - }) - } - codeOutput.value = s -} - -function updateSelection() { - var controlsEl = $('.controls') - if (focusedSample) { - controlsEl.classList.add('has-selected-sample') - } else { - controlsEl.classList.remove('has-selected-sample') - } - - updateGraphPlot() - updateCodeView() -} - - -bindings.configure('base-tracking', 0, 'float', function (tracking) { - baseTracking = tracking - updateSamples() -}) - -bindings.configure('var-a', a, 'float', function (v) { - a = v - updateSamples() -}) - -bindings.configure('var-b', b, 'float', function (v) { - b = v - updateSamples() -}) - -bindings.configure('var-c', c, 'float', function (v) { - c = v - updateSamples() -}) - -bindings.configure('var-l', l, 'float', function (v) { - l = v - updateSamples() -}) - -bindings.configure('ideal-count', 0, 'int', function (v) {}) -bindings.configure('ideal-distance', 0, 'float', function (v) {}) - -bindings.configure('style', null, null, function (style) { - var cl = samplesEl.classList - cl.remove('font-style-regular') - cl.remove('font-style-italic') - cl.remove('font-style-medium') - cl.remove('font-style-medium-italic') - cl.remove('font-style-semi-bold') - cl.remove('font-style-semi-bold-italic') - cl.remove('font-style-bold') - cl.remove('font-style-bold-italic') - cl.remove('font-style-extra-bold') - cl.remove('font-style-extra-bold-italic') - cl.remove('font-style-black') - cl.remove('font-style-black-italic') - cl.add('font-style-' + style) - weightClass = ( - style.indexOf('black') != -1 ? 900 : - style.indexOf('bold') != -1 ? 700 : - style.indexOf('medium') != -1 ? 500 : - 400 - ) - updateSamples() -}) - - -bindings.bindAllInputs('[data-binding]') - -// double-click base tracking to reset -$('input[type="range"][data-binding="base-tracking"]').addEventListener( - 'dblclick', - function(ev) { bindings.setValue('base-tracking', 0) } -) - -;[ - ['var-a',a], - ['var-b',b], - ['var-c',c], - ['var-l',l], - ['base-tracking', 0] -].forEach(p => { - let bindname = p[0], defval = p[1] - $$('input[type="range"][data-binding="'+bindname+'"]').forEach(e => { - e.addEventListener('dblclick', ev => - bindings.setValue(bindname, defval)) - }) -}) - -// allow editing of ideal values -idealValuesTextArea.addEventListener('input', function(ev) { - setIdealValues(parseValues(idealValuesTextArea.value)) - updateSamples() -}) - -// listen for clicks onto "background", to deselect any selected sample -document.body.addEventListener('pointerdown', function(ev){ - if ( - ev.target === document.body || - ev.target === samplesEl || - ev.target.classList && ev.target.classList.contains('row') - ) { - setSelectedSample(null) - } -}) - - -// start -initSamples() -updateSamples() - -})();</script> |