From 94a20f2b348e38f3e64a4e2e460ff9390058a925 Mon Sep 17 00:00:00 2001 From: Roland Rytz Date: Sat, 8 Apr 2017 05:57:12 +0200 Subject: [PATCH] Make zooming more fluid, fix font by including DejaVu Sans as a webfont --- allCharacters.py | 19 +++++ allCharacters.txt | 2 + shrinkFont.py | 29 ++++++++ web/_css/style.css | 27 +++++-- web/_js/main.js | 173 +++++++++++++++++++++++++++++++++------------ web/_js/view.js | 94 ++++++++++++------------ 6 files changed, 246 insertions(+), 98 deletions(-) create mode 100644 allCharacters.py create mode 100644 allCharacters.txt create mode 100644 shrinkFont.py diff --git a/allCharacters.py b/allCharacters.py new file mode 100644 index 00000000..2e2d9af4 --- /dev/null +++ b/allCharacters.py @@ -0,0 +1,19 @@ + +outfile = open('allCharacters.txt', 'w') + +chars = set() + +with open('./web/_js/atlas.js') as f: + while True: + c = f.read(1) + if not c: + chars = list(chars) + chars = sorted(chars) + string = "" + for i in chars: + string += i + outfile.write(string) + break + + chars.add(c) + diff --git a/allCharacters.txt b/allCharacters.txt new file mode 100644 index 00000000..2d14f0ba --- /dev/null +++ b/allCharacters.txt @@ -0,0 +1,2 @@ + + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~ÅÍÑ×äåèéíñõöøúāćŌōūŵμТбзиру​–—’“”•™☆❤カガゴスズタハブモラルンー人友合夏帳日本百目茜野국김녀대마무민설소스시아오와이트한현️ \ No newline at end of file diff --git a/shrinkFont.py b/shrinkFont.py new file mode 100644 index 00000000..8d94a824 --- /dev/null +++ b/shrinkFont.py @@ -0,0 +1,29 @@ +#!/usr/bin/python2 + + +# By StackOverflow user SadaleNet: +# https://stackoverflow.com/questions/14557944/downsizing-an-otf-font-by-removing-glyphs/34132900#34132900 + + +import sys +import fontforge + +if len(sys.argv) == 4: + font = fontforge.open(sys.argv[1]) + + f = open(sys.argv[2], "r") + + for i in f.read().decode("UTF-8"): + font.selection[ord(i)] = True + f.close() + + font.selection.invert() + + for i in font.selection.byGlyphs: + font.removeGlyph(i) + + font.generate(sys.argv[3]) +else: + print "WARNING: Check the license of the source font\nbefore distributing the output font generated by this script.\nI'm not responsible for any legal issue caused by\ninappropriate use of this script!\n" + print "Usage: {} [source font] [file with glyphs NOT to be removed] [output]".format(sys.argv[0]) + print "Example: {} /path/to/ukai.ttc chineseTranslation.txt ukaiStripped.ttf".format(sys.argv[0]) diff --git a/web/_css/style.css b/web/_css/style.css index e1351bc9..16b95274 100644 --- a/web/_css/style.css +++ b/web/_css/style.css @@ -24,6 +24,15 @@ */ +@font-face { + font-family: 'dejavu'; + src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); + font-weight: normal; + font-style: normal; + +} + + *{ margin: 0px; padding: 0px; @@ -48,9 +57,11 @@ body{ overflow-x: hidden; overflow-y: hidden; - font-family: Sans-Serif, sans; + font-family: dejavu, sans, Sans-Serif; background-color: #111111; color: #FFFFFF; + + line-height: 1.15; } #wrapper{ @@ -83,6 +94,7 @@ #drawBackButton{ display: inline-block; padding: 5px; cursor: pointer; + text-shadow: 1px 1px 0px #444444; } button::-moz-focus-inner { @@ -136,9 +148,14 @@ @media (max-width: 600px) { } @media (max-width: 400px) { + header h1{ + font-size: 28px; + } +} + +@media (max-width: 350px) { header h1{ font-size: 20px; - vertical-align: middle; } } @@ -164,10 +181,11 @@ #logo{ } h1{ - font-weight: 300; + font-weight: 200; padding: 0px 10px; display: inline-block; - vertical-align: center; + margin-top: -5px; + text-shadow: 1px 1px 0px #000000; } select{ @@ -633,6 +651,7 @@ #entriesListContainer > nav > a{ cursor: pointer; width: 130px; margin-right: 10px; + text-shadow: 1px 1px 0px #444444; } #entriesListContainer > nav > a:last-child{ diff --git a/web/_js/main.js b/web/_js/main.js index 132db201..e7b71b4f 100644 --- a/web/_js/main.js +++ b/web/_js/main.js @@ -35,6 +35,9 @@ if(window.devicePixelRatio){ zoom = 1/window.devicePixelRatio; } +var maxZoom = 128; +var minZoom = 0.1; + var zoomOrigin = [0, 0]; var scaleZoomOrigin = [0, 0]; @@ -67,6 +70,9 @@ function init(){ var initialPinchZoom = 0; var initialPinchZoomOrigin = [0, 0]; + var desiredZoom; + var zoomAnimationFrame; + var mode = "view"; var args = window.location.search; @@ -118,38 +124,51 @@ function init(){ window.location = "./about.html"; } - function zoomOut(x, y){ - - zoomOrigin[0] += x - container.clientWidth/2; - zoomOrigin[1] += y - container.clientHeight/2; - - zoomOrigin[0] = zoomOrigin[0]/2; - zoomOrigin[1] = zoomOrigin[1]/2; - - zoom = zoom / 2; - - applyView(); - } - - function zoomIn(x, y){ - - zoomOrigin[0] = zoomOrigin[0]*2; - zoomOrigin[1] = zoomOrigin[1]*2; - - zoomOrigin[0] -= x - container.clientWidth/2; - zoomOrigin[1] -= y - container.clientHeight/2; - - zoom = zoom * 2; - - applyView(); - } - document.getElementById("zoomInButton").addEventListener("click", function(e){ - zoomIn(container.clientWidth/2, container.clientHeight/2); + + if(zoomAnimationFrame){ + window.cancelAnimationFrame(zoomAnimationFrame); + } + + var x = container.clientWidth/2; + var y = container.clientHeight/2; + + initialPinchZoomOrigin = [ + scaleZoomOrigin[0], + scaleZoomOrigin[1] + ]; + + initialPinchZoom = zoom; + + lastPosition = [x, y]; + var desiredZoom = zoom * 2; + desiredZoom = Math.max(minZoom, Math.min(maxZoom, desiredZoom)); + + setDesiredZoom(x, y, desiredZoom); + }); document.getElementById("zoomOutButton").addEventListener("click", function(e){ - zoomOut(container.clientWidth/2, container.clientHeight/2); + + if(zoomAnimationFrame){ + window.cancelAnimationFrame(zoomAnimationFrame); + } + + var x = container.clientWidth/2; + var y = container.clientHeight/2; + + initialPinchZoomOrigin = [ + scaleZoomOrigin[0], + scaleZoomOrigin[1] + ]; + + initialPinchZoom = zoom; + + lastPosition = [x, y]; + var desiredZoom = zoom / 2; + desiredZoom = Math.max(minZoom, Math.min(maxZoom, desiredZoom)); + + setDesiredZoom(x, y, desiredZoom); }); document.getElementById("zoomResetButton").addEventListener("click", function(e){ @@ -159,33 +178,89 @@ function init(){ }); container.addEventListener("dblclick", function(e){ + if(zoomAnimationFrame){ + window.cancelAnimationFrame(zoomAnimationFrame); + } + + var x = e.layerX; + var y = e.layerY; + + initialPinchZoomOrigin = [ + scaleZoomOrigin[0], + scaleZoomOrigin[1] + ]; + + initialPinchZoom = zoom; + + lastPosition = [x, y]; + + var desiredZoom = 0; + if(e.ctrlKey){ - zoomOut(e.layerX, e.layerY); + desiredZoom = zoom / 2; } else { - zoomIn(e.layerX, e.layerY); + desiredZoom = zoom * 2; } - + + desiredZoom = Math.max(minZoom, Math.min(maxZoom, desiredZoom)); + setDesiredZoom(x, y, desiredZoom); + e.preventDefault(); }); container.addEventListener("wheel", function(e){ + + if(zoomAnimationFrame){ + window.cancelAnimationFrame(zoomAnimationFrame); + } + + var x = e.layerX; + var y = e.layerY; + + initialPinchZoomOrigin = [ + scaleZoomOrigin[0], + scaleZoomOrigin[1] + ]; + + initialPinchZoom = zoom; + + lastPosition = [x, y]; + + var desiredZoom = 0; if(e.deltaY > 0){ - zoomOut(e.layerX, e.layerY); + desiredZoom = zoom / 2; } else if(e.deltaY < 0){ - zoomIn(e.layerX, e.layerY); + desiredZoom = zoom * 2; } + desiredZoom = Math.max(minZoom, Math.min(maxZoom, desiredZoom)); + setDesiredZoom(x, y, desiredZoom); + e.preventDefault(); }); + function setDesiredZoom(x, y, target){ + zoom = (zoom*2 + target)/3; + console.log(zoom); + if(Math.abs(1 - zoom/target) <= 0.01){ + zoom = target; + } + applyZoom(x, y, zoom); + if(zoom != target){ + zoomAnimationFrame = window.requestAnimationFrame(function(){ + setDesiredZoom(x, y, target); + }); + } + } + container.addEventListener("mousedown", function(e){ mousedown(e.clientX, e.clientY); e.preventDefault(); @@ -266,24 +341,30 @@ function init(){ var x = (e.touches[0].clientX + e.touches[1].clientX)/2 - container.offsetLeft; var y = (e.touches[0].clientY + e.touches[1].clientY)/2 - container.offsetTop; - var deltaX = x - lastPosition[0]; - var deltaY = y - lastPosition[1]; - - var pinchTranslateX = (x - container.clientWidth/2 - deltaX) - var pinchTranslateY = (y - container.clientHeight/2 - deltaY) - - scaleZoomOrigin[0] = initialPinchZoomOrigin[0] + deltaX/zoom + pinchTranslateX/zoom - pinchTranslateX/initialPinchZoom; - scaleZoomOrigin[1] = initialPinchZoomOrigin[1] + deltaY/zoom + pinchTranslateY/zoom - pinchTranslateY/initialPinchZoom; - - zoomOrigin[0] = scaleZoomOrigin[0]*zoom; - zoomOrigin[1] = scaleZoomOrigin[1]*zoom; - - applyView(); + applyZoom(x, y, zoom); } } + function applyZoom(x, y, zoom){ + + var deltaX = x - lastPosition[0]; + var deltaY = y - lastPosition[1]; + + var pinchTranslateX = (x - container.clientWidth/2 - deltaX); + var pinchTranslateY = (y - container.clientHeight/2 - deltaY); + + scaleZoomOrigin[0] = initialPinchZoomOrigin[0] + deltaX/zoom + pinchTranslateX/zoom - pinchTranslateX/initialPinchZoom; + scaleZoomOrigin[1] = initialPinchZoomOrigin[1] + deltaY/zoom + pinchTranslateY/zoom - pinchTranslateY/initialPinchZoom; + + zoomOrigin[0] = scaleZoomOrigin[0]*zoom; + zoomOrigin[1] = scaleZoomOrigin[1]*zoom; + + applyView(); + updateLines(); + } + window.addEventListener("mouseup", function(e){ mouseup(e.clientX, e.clientY); e.preventDefault(); diff --git a/web/_js/view.js b/web/_js/view.js index e2fb7c4d..49c26eb5 100644 --- a/web/_js/view.js +++ b/web/_js/view.js @@ -22,6 +22,52 @@ ======================================================================== */ +var linesCanvas = document.getElementById("linesCanvas"); +var linesContext = linesCanvas.getContext("2d"); +var hovered = []; + +function updateLines(){ + + linesCanvas.width = linesCanvas.clientWidth; + linesCanvas.height = linesCanvas.clientHeight; + linesContext.lineCap = "round"; + linesContext.lineWidth = Math.max(Math.min(zoom*1.5, 16*1.5), 6); + linesContext.strokeStyle = "#000000"; + + for(var i = 0; i < hovered.length; i++){ + var element = hovered[i].element; + + linesContext.beginPath(); + //linesContext.moveTo(element.offsetLeft + element.clientWidth - 10, element.offsetTop + 20); + linesContext.moveTo( + element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2 + ,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20 + ); + linesContext.lineTo( + ~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft + ,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop + ); + linesContext.stroke(); + } + + linesContext.lineWidth = Math.max(Math.min(zoom, 16), 4); + linesContext.strokeStyle = "#FFFFFF"; + + for(var i = 0; i < hovered.length; i++){ + var element = hovered[i].element; + + linesContext.beginPath(); + linesContext.moveTo( + element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2 + ,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20 + ); + linesContext.lineTo( + ~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft + ,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop + ); + linesContext.stroke(); + } +} function initView(){ @@ -29,9 +75,6 @@ function initView(){ var objectsContainer = document.getElementById("objectsList"); - var linesCanvas = document.getElementById("linesCanvas"); - var linesContext = linesCanvas.getContext("2d"); - var backgroundCanvas = document.createElement("canvas"); backgroundCanvas.width = 1000; backgroundCanvas.height = 1000; @@ -54,8 +97,6 @@ function initView(){ var viewportWidth = document.documentElement.clientWidth; - var hovered = []; - var lastPos = [0, 0]; var previousZoomOrigin = [0, 0]; @@ -471,49 +512,6 @@ function initView(){ } } - function updateLines(){ - - linesCanvas.width = linesCanvas.clientWidth; - linesCanvas.height = linesCanvas.clientHeight; - linesContext.lineCap = "round"; - linesContext.lineWidth = Math.max(Math.min(zoom*1.5, 16*1.5), 6); - linesContext.strokeStyle = "#000000"; - - for(var i = 0; i < hovered.length; i++){ - var element = hovered[i].element; - - linesContext.beginPath(); - //linesContext.moveTo(element.offsetLeft + element.clientWidth - 10, element.offsetTop + 20); - linesContext.moveTo( - element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2 - ,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20 - ); - linesContext.lineTo( - ~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft - ,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop - ); - linesContext.stroke(); - } - - linesContext.lineWidth = Math.max(Math.min(zoom, 16), 4); - linesContext.strokeStyle = "#FFFFFF"; - - for(var i = 0; i < hovered.length; i++){ - var element = hovered[i].element; - - linesContext.beginPath(); - linesContext.moveTo( - element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2 - ,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20 - ); - linesContext.lineTo( - ~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft - ,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop - ); - linesContext.stroke(); - } - } - window.addEventListener("resize", updateLines); window.addEventListener("mousemove", updateLines); window.addEventListener("dblClick", updateLines);