From c65f3f1ddae805f5e8ee4744a8ffa50b07795941 Mon Sep 17 00:00:00 2001
From: Christopher Pietsch <cpietsch@gmail.com>
Date: Tue, 2 Oct 2018 15:25:03 +0200
Subject: [PATCH] cleanup

---
 js/canvas.js | 1569 +++++++++++++++++++++++---------------------------
 js/viz.js    |  135 +++--
 2 files changed, 796 insertions(+), 908 deletions(-)

diff --git a/js/canvas.js b/js/canvas.js
index 0c42864..db6c5c1 100644
--- a/js/canvas.js
+++ b/js/canvas.js
@@ -4,914 +4,805 @@
 
 
 function Canvas() {
-  var margin = {
-      top: 20,
-      right: 50,
-      bottom: 30,
-      left: 50
-  };
-
-  var minHeight = 400;
-  var width = window.innerWidth - margin.left - margin.right;
-  var widthOuter = window.innerWidth;
-  var height = window.innerHeight < minHeight ? minHeight : window.innerHeight;
-
-  var scale;
-  var scale1 = 1;
-  var scale2 = 1;
-  var scale3 = 1;
-  var allData = [];
-
-  var translate = [0, 0];
-  var scale = 1;
-  var timeDomain = [];
-  var loadImagesCue = [];
-
-  var x = d3.scale.ordinal()
-      .rangeBands([margin.left, width + margin.left], 0.2);
-
-  var Quadtree = d3.geom.quadtree()
-      .x(function(d) {
-          return d.x;
-      })
-      .y(function(d) {
-          return d.y;
-      });
-
-  var quadtree;
-
-  var maxZoomLevel = utils.isMobile() ? 5000 : 2500;
-
-  var zoom = d3.behavior.zoom()
-      .scaleExtent([1, maxZoomLevel])
-      .size([width,height])
-      .on("zoom", zoomed)
-      .on("zoomend", zoomend)
-      .on("zoomstart", zoomstart);
-
-  // d3.select("body")
-  //     .on("keydown", keydown);
-
-  var canvas;
-  var config;
-  var container;
-  var entries;
-  var years;
-  var data;
-  var rangeBand = 0;
-  var rangeBandImage = 0;
-  // var imageSize = 50;
-  var imageSize = 256;
-  var imageSize2 = 1024;
-  var imageSize3 = 4000;
-  var collumns = 4;
-  var renderer, stage;
-  
-  var svgscale, voronoi;
-
-  var selectedImageDistance = 0;
-  var selectedImage = null;
-
-  var drag = false;
-
-  var stagePadding = 40;
-  var imgPadding;
-
-  var bottomPadding = 70;
-  var extent = [0, 0];
-  var bottomZooming = true;
-
-  var touchstart = 0;
-  var vizContainer;
-  var spriteClick = false
-
-  var state = { 
-    lastZoomed:0,
-    zoomingToImage: false,
-    mode: "time",
-    init: false
-  };
-
-  var zoomedToImage = false;
-  var zoomedToImageScale = 117;
-  var zoomBarrier = 2;
-
-  var startTranslate = [0, 0];
-  var startScale = 0;
-  var zooming = false;
-  var detailContainer = d3.select(".sidebar")
-  var timelineData;
-  var stage, stage1, stage2, stage3, stage4, stage5;
-
-
-  function canvas() {}
-
-  canvas.rangeBand = function() { return rangeBand }
-  canvas.width = function() { return width }
-  canvas.height = function() { return height }
-  canvas.rangeBandImage = function() { return rangeBandImage }
-  canvas.zoom = zoom
-  canvas.selectedImage = function() { return selectedImage }
-  canvas.x = x
-
-  canvas.resize = function() {
-      if(!state.init) return;
-      // console.log("resize")
-      width = window.innerWidth - margin.left - margin.right;
-      height = window.innerHeight < minHeight ? minHeight : window.innerHeight;
-      widthOuter = window.innerWidth;
-
-      renderer.resize(width + margin.left + margin.right, height);
-
-      canvas.makeScales();
-      canvas.project();
-  }
-
-  canvas.makeScales = function() {
-      x.rangeBands([margin.left, width + margin.left], 0.2)
-
-      rangeBand = x.rangeBand();
-      rangeBandImage = x.rangeBand() / collumns;
-
-      imgPadding = rangeBand / collumns / 2;
-
-      scale1 = imageSize / (x.rangeBand() / collumns);
-      scale2 = imageSize2 / (x.rangeBand() / collumns);
-      scale3 = imageSize3 / (x.rangeBand() / collumns);
-
-      stage3.scale.x = 1 / scale1;
-      stage3.scale.y = 1 / scale1;
-      stage3.y = height;
-
-      stage4.scale.x = 1 / scale2;
-      stage4.scale.y = 1 / scale2;
-      stage4.y = height;
-
-      stage5.scale.x = 1 / scale3;
-      stage5.scale.y = 1 / scale3;
-      stage5.y = height;
-
-      timeline.rescale(scale1)
-
-      zoomedToImageScale = 0.8 / (x.rangeBand() / collumns / width)
-  }
-
-  canvas.init = function(_data,_timeline, _config) {
-      data = _data;
-      config = _config;
-
-      container = d3.select(".page").append("div").classed("viz", true);
-      detailVue._data.structure = config.detail.structure
-
-
-      collumns = config.projection.columns;
-      imageSize = config.loader.textures.medium.size;
-      imageSize2 = config.loader.textures.detail.size;
-      
-      if(config.loader.textures.big){
-        imageSize3 = config.loader.textures.big.size;
-      }
-      
-      PIXI.settings.SCALE_MODE = 1
-
-      var renderOptions = {
-          resolution: 1,
-          antialiasing: false
-      };
-      renderer = new PIXI.WebGLRenderer(width + margin.left + margin.right, height, renderOptions);
-      renderer.backgroundColor = parseInt(config.style.canvasBackground.substring(1), 16)
-      window.renderer = renderer;
-     
-      var renderElem = d3.select(container.node().appendChild(renderer.view));
-
-      stage = new PIXI.Container();
-      stage2 = new PIXI.Container();
-      stage3 = new PIXI.Container();
-      stage4 = new PIXI.Container();
-      stage5 = new PIXI.Container();
-
-      stage.addChild(stage2);
-      stage2.addChild(stage3);
-      stage2.addChild(stage4);
-      stage2.addChild(stage5);
-
-      // timeline cleaning
-      _timeline.forEach(function(d) {
-          d.type = "timeline";
-      });
-
-      var canvasDomain = d3.nest()
-        .key(function(d){ return d.year; })
-        .entries(_data.concat(_timeline))
-        .sort(function(a, b) { return a.key - b.key; })
-        // .sort(function(a, b) { return d3.descending(a.key, b.key) })
-        .map(function(d){ return d.key; })
-
-      timeDomain = canvasDomain.map(function(d){
-        return {
-          key: d,
-          values: _timeline.filter(function(e){ return d == e.year; })
-        }
-      })
-
-      timeline.init(timeDomain)
-      x.domain(canvasDomain);
-      canvas.makeScales();
-
-      // add preview pics
-      data.forEach(function(d, i) {
-          var sprite = new PIXI.Sprite(PIXI.Texture.WHITE);
-          
-          sprite.anchor.x = 0.5;
-          sprite.anchor.y = 0.5;
-
-          sprite.scale.x = d.scaleFactor;
-          sprite.scale.y = d.scaleFactor;
-
-          sprite._data = d;
-          d.sprite = sprite;
-
-          stage3.addChild(sprite);
-
-      })
-      
-
-      vizContainer = d3.select(".viz")
-          .call(zoom)
-          .on("mousemove", mousemove)
-          .on("dblclick.zoom", null)
-          .on("touchstart", function(d){
-            mousemove(d);
-            touchstart = new Date()*1;
-          })
-          .on("touchend", function(d){
-            var touchtime = (new Date()*1) - touchstart;
-            if(touchtime > 250) return;
-            if(selectedImageDistance > 15) return;
-            if (selectedImage && !selectedImage.id) return;
-            if (selectedImage && !selectedImage.active) return;
-            if(drag) return;
-
-            zoomToImage(selectedImage, 1400 / Math.sqrt(Math.sqrt(scale)))
-          })
-          .on("click", function() {
-               console.log("click");
-              if (spriteClick) { spriteClick = false; return; }
-              if (selectedImage && !selectedImage.id) return;
-              if (drag) return;
-              if (selectedImageDistance > 15) return;
-              if (selectedImage && !selectedImage.active) return;
-              if(timelineHover) return;
-              // console.log(selectedImage)
-              
-
-              if (Math.abs(zoomedToImageScale - scale) < 0.1) {
-                  canvas.resetZoom();
-              } else {
-                zoomToImage(selectedImage, 1400 / Math.sqrt(Math.sqrt(scale)));
-              }
-
-          })
-
-      canvas.project();
-      animate();
-
-
-      // selectedImage = data.find(d => d.id == 88413)
-      // showDetail(selectedImage)
-      state.init = true;
-  };
-
-
-  function mousemove(d) {
-      if(timelineHover) return;
-
-      var mouse = d3.mouse(vizContainer.node());
-      var p = toScreenPoint(mouse);
- 
-      var best = nearest(p[0] - imgPadding, p[1] - imgPadding, {
-          d: 200,
-          p: null
-      }, quadtree);
-
-      selectedImageDistance = best.d;
-
-      if(bottomZooming && best.p && best.p.ii < 3 && selectedImageDistance > 7){
-        // console.log("bottom");
-        selectedImage = null;
-        zoom.center(null);
-        container.style("cursor", "default");
-      } else {
-        if (best.p && !zoomedToImage) {
-            var d = best.p;
-            // todo iprove that bitch
-            var center = [((d.x + imgPadding) * scale) + translate[0], (height + d.y + imgPadding) * scale + translate[1]];
-            zoom.center(center);
-
-            selectedImage = d;
-        }
-
-        container.style("cursor", function() {
-            return ((best.d < 5) && selectedImage.active) ? "pointer" : "default";
+    var margin = {
+        top: 20,
+        right: 50,
+        bottom: 30,
+        left: 50
+    };
+
+    var minHeight = 400;
+    var width = window.innerWidth - margin.left - margin.right;
+    var widthOuter = window.innerWidth;
+    var height = window.innerHeight < minHeight ? minHeight : window.innerHeight;
+
+    var scale;
+    var scale1 = 1;
+    var scale2 = 1;
+    var scale3 = 1;
+    var allData = [];
+
+    var translate = [0, 0];
+    var scale = 1;
+    var timeDomain = [];
+    var loadImagesCue = [];
+
+    var x = d3.scale.ordinal()
+        .rangeBands([margin.left, width + margin.left], 0.2);
+
+    var Quadtree = d3.geom.quadtree()
+        .x(function(d) {
+            return d.x;
+        })
+        .y(function(d) {
+            return d.y;
         });
-      }
-
-  } 
-
 
-  function stackLayout(data, invert) {
+    var quadtree;
+
+    var maxZoomLevel = utils.isMobile() ? 5000 : 2500;
+
+    var zoom = d3.behavior.zoom()
+        .scaleExtent([1, maxZoomLevel])
+        .size([width, height])
+        .on("zoom", zoomed)
+        .on("zoomend", zoomend)
+        .on("zoomstart", zoomstart);
+
+    var canvas;
+    var config;
+    var container;
+    var entries;
+    var years;
+    var data;
+    var rangeBand = 0;
+    var rangeBandImage = 0;
+    var imageSize = 256;
+    var imageSize2 = 1024;
+    var imageSize3 = 4000;
+    var collumns = 4;
+    var renderer, stage;
+
+    var svgscale, voronoi;
+
+    var selectedImageDistance = 0;
+    var selectedImage = null;
+
+    var drag = false;
+    var sleep = false
+
+    var stagePadding = 40;
+    var imgPadding;
+
+    var bottomPadding = 70;
+    var extent = [0, 0];
+    var bottomZooming = true;
+
+    var touchstart = 0;
+    var vizContainer;
+    var spriteClick = false
+
+    var state = {
+        lastZoomed: 0,
+        zoomingToImage: false,
+        mode: "time",
+        init: false
+    };
+
+    var zoomedToImage = false;
+    var zoomedToImageScale = 117;
+    var zoomBarrier = 2;
+
+    var startTranslate = [0, 0];
+    var startScale = 0;
+    var zooming = false;
+    var detailContainer = d3.select(".sidebar")
+    var timelineData;
+    var stage, stage1, stage2, stage3, stage4, stage5;
+    var timelineHover = false;
+
+    function canvas() {}
+
+    canvas.rangeBand = function() { return rangeBand }
+    canvas.width = function() { return width }
+    canvas.height = function() { return height }
+    canvas.rangeBandImage = function() { return rangeBandImage }
+    canvas.zoom = zoom
+    canvas.selectedImage = function() { return selectedImage }
+    canvas.x = x
+
+    canvas.resize = function() {
+        if (!state.init) return;
+        width = window.innerWidth - margin.left - margin.right;
+        height = window.innerHeight < minHeight ? minHeight : window.innerHeight;
+        widthOuter = window.innerWidth;
+        renderer.resize(width + margin.left + margin.right, height);
+        canvas.makeScales();
+        canvas.project();
+    }
+
+    canvas.makeScales = function() {
+        x.rangeBands([margin.left, width + margin.left], 0.2)
+
+        rangeBand = x.rangeBand();
+        rangeBandImage = x.rangeBand() / collumns;
+
+        imgPadding = rangeBand / collumns / 2;
+
+        scale1 = imageSize / (x.rangeBand() / collumns);
+        scale2 = imageSize2 / (x.rangeBand() / collumns);
+        scale3 = imageSize3 / (x.rangeBand() / collumns);
+
+        stage3.scale.x = 1 / scale1;
+        stage3.scale.y = 1 / scale1;
+        stage3.y = height;
+
+        stage4.scale.x = 1 / scale2;
+        stage4.scale.y = 1 / scale2;
+        stage4.y = height;
+
+        stage5.scale.x = 1 / scale3;
+        stage5.scale.y = 1 / scale3;
+        stage5.y = height;
+
+        timeline.rescale(scale1)
+
+        zoomedToImageScale = 0.8 / (x.rangeBand() / collumns / width)
+    }
+
+    canvas.init = function(_data, _timeline, _config) {
+        data = _data;
+        config = _config;
+
+        container = d3.select(".page").append("div").classed("viz", true);
+        detailVue._data.structure = config.detail.structure
+
+        collumns = config.projection.columns;
+        imageSize = config.loader.textures.medium.size;
+        imageSize2 = config.loader.textures.detail.size;
 
-      var years = d3.nest()
-          .key(function(d) {
-              return d.year;
-          })
-          // .sortKeys(d3.ascending)
-          .entries(data)
-
-      years.forEach(function(year) {
-          var startX = x(year.key);
-          var total = year.values.length;
-          year.values.sort(function(a,b){
-            return b.keywords.length - a.keywords.length;
-          })
-          //console.log(year.values)
+        if (config.loader.textures.big) {
+            imageSize3 = config.loader.textures.big.size;
+        }
 
-          year.values.forEach(function(d, i) {
-              var row = (Math.floor(i / collumns) +2);
-              d.ii = i;
+        PIXI.settings.SCALE_MODE = 1
 
-              d.x = startX + ((i % collumns) * (rangeBand / collumns));
-              d.y = (invert ? 1 : -1) * (row * (rangeBand / collumns));
+        var renderOptions = {
+            resolution: 1,
+            antialiasing: false
+        };
+        renderer = new PIXI.WebGLRenderer(width + margin.left + margin.right, height, renderOptions);
+        renderer.backgroundColor = parseInt(config.style.canvasBackground.substring(1), 16)
+        window.renderer = renderer;
 
-              d.x1 = d.x * scale1 + imageSize / 2;
-              d.y1 = d.y * scale1 + imageSize / 2;
+        var renderElem = d3.select(container.node().appendChild(renderer.view));
 
-              if (d.sprite.position.x == 0) {
-                  d.sprite.position.x = d.x1;
-                  d.sprite.position.y = d.y1;
-              }
+        stage = new PIXI.Container();
+        stage2 = new PIXI.Container();
+        stage3 = new PIXI.Container();
+        stage4 = new PIXI.Container();
+        stage5 = new PIXI.Container();
 
-              if (d.sprite2) {
-                  d.sprite2.position.x = d.x * scale2 + imageSize2 / 2;
-                  d.sprite2.position.y = d.y * scale2 + imageSize2 / 2;
-              }
+        stage.addChild(stage2);
+        stage2.addChild(stage3);
+        stage2.addChild(stage4);
+        stage2.addChild(stage5);
 
-              d.order = (invert ? 1 : 1) * (total - i);
-          })
-      })
-  }
+        _timeline.forEach(function(d) {
+            d.type = "timeline";
+        });
 
-  canvas.distance = function(a, b) {
-      return Math.sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]));
-  }
+        var canvasDomain = d3.nest()
+            .key(function(d) { return d.year; })
+            .entries(_data.concat(_timeline))
+            .sort(function(a, b) { return a.key - b.key; })
+            .map(function(d) { return d.key; })
+
+        timeDomain = canvasDomain.map(function(d) {
+            return {
+                key: d,
+                values: _timeline.filter(function(e) { return d == e.year; })
+            }
+        })
 
-  function toScreenPoint(p) {
-      var p2 = [0, 0];
+        timeline.init(timeDomain)
+        x.domain(canvasDomain);
+        canvas.makeScales();
 
-      // console.log("t",translate,scale)
+        // add preview pics
+        data.forEach(function(d, i) {
+            var sprite = new PIXI.Sprite(PIXI.Texture.WHITE);
 
-      p2[0] = p[0] / scale - translate[0] / scale;
-      p2[1] = (p[1] / scale - height) - translate[1] / scale;
+            sprite.anchor.x = 0.5;
+            sprite.anchor.y = 0.5;
 
-      return p2;
-  }
+            sprite.scale.x = d.scaleFactor;
+            sprite.scale.y = d.scaleFactor;
 
-  function imageAnimation() {
-      var sleep = true
+            sprite._data = d;
+            d.sprite = sprite;
 
-      data.forEach(function(d, i) {
-          var diff;
-          diff = (d.x1 - d.sprite.position.x);
-          if (Math.abs(diff) > 0.1) {
-            d.sprite.position.x += diff * 0.1;
-            sleep = false;
-          }
+            stage3.addChild(sprite);
 
-          diff = (d.y1 - d.sprite.position.y);
-          if (Math.abs(diff) > 0.1) {
-            d.sprite.position.y += diff * 0.1
-            sleep = false;
-          }
+        })
 
-          diff = (d.alpha - d.sprite.alpha);
-          if (Math.abs(diff) > 0.01) {
-            d.sprite.alpha += diff * 0.2
-            sleep = false;
-          }
 
-          d.sprite.visible = d.sprite.alpha > 0.1;
+        vizContainer = d3.select(".viz")
+            .call(zoom)
+            .on("mousemove", mousemove)
+            .on("dblclick.zoom", null)
+            .on("touchstart", function(d) {
+                mousemove(d);
+                touchstart = new Date() * 1;
+            })
+            .on("touchend", function(d) {
+                var touchtime = (new Date() * 1) - touchstart;
+                if (touchtime > 250) return;
+                if (selectedImageDistance > 15) return;
+                if (selectedImage && !selectedImage.id) return;
+                if (selectedImage && !selectedImage.active) return;
+                if (drag) return;
+
+                zoomToImage(selectedImage, 1400 / Math.sqrt(Math.sqrt(scale)))
+            })
+            .on("click", function() {
+                console.log("click");
+                if (spriteClick) { spriteClick = false; return; }
+                if (selectedImage && !selectedImage.id) return;
+                if (drag) return;
+                if (selectedImageDistance > 15) return;
+                if (selectedImage && !selectedImage.active) return;
+                if (timelineHover) return;
+                // console.log(selectedImage)
+
+                if (Math.abs(zoomedToImageScale - scale) < 0.1) {
+                    canvas.resetZoom();
+                } else {
+                    zoomToImage(selectedImage, 1400 / Math.sqrt(Math.sqrt(scale)));
+                }
+
+            })
+
+        canvas.project();
+        animate();
+
+        // selectedImage = data.find(d => d.id == 88413)
+        // showDetail(selectedImage)
+        state.init = true;
+    };
+
+
+    function mousemove(d) {
+        if (timelineHover) return;
+
+        var mouse = d3.mouse(vizContainer.node());
+        var p = toScreenPoint(mouse);
+
+        var best = nearest(p[0] - imgPadding, p[1] - imgPadding, {
+            d: 200,
+            p: null
+        }, quadtree);
+
+        selectedImageDistance = best.d;
+
+        if (bottomZooming && best.p && best.p.ii < 3 && selectedImageDistance > 7) {
+            selectedImage = null;
+            zoom.center(null);
+            container.style("cursor", "default");
+        } else {
+            if (best.p && !zoomedToImage) {
+                var d = best.p;
+                // todo iprove that bitch
+                var center = [((d.x + imgPadding) * scale) + translate[0], (height + d.y + imgPadding) * scale + translate[1]];
+                zoom.center(center);
+                selectedImage = d;
+            }
+
+            container.style("cursor", function() {
+                return ((best.d < 5) && selectedImage.active) ? "pointer" : "default";
+            });
+        }
 
-          if (d.sprite2) {
-              diff = (d.alpha2 - d.sprite2.alpha);
-              if (Math.abs(diff) > 0.01) {
-                d.sprite2.alpha += diff * 0.2
-                sleep = false;
-              }
+    }
 
-              d.sprite2.visible = d.sprite2.alpha > 0.1;
-              //else d.sprite2.visible = d.visible;
-          }
-      });
-    return sleep
-  }
 
-  var sleep = false
-  canvas.wakeup = function() { sleep = false }
+    function stackLayout(data, invert) {
 
-  function animate(time) {
-      requestAnimationFrame(animate);
-      loadImages();
-      if(sleep) return
-      sleep = imageAnimation();
-      renderer.render(stage);
-  }
+        var years = d3.nest()
+            .key(function(d) {
+                return d.year;
+            })
+            .entries(data)
 
-  function zoomToYear(d) {
+        years.forEach(function(year) {
+            var startX = x(year.key);
+            var total = year.values.length;
+            year.values.sort(function(a, b) {
+                return b.keywords.length - a.keywords.length;
+            })
 
-      var xYear = x(d.year);
-      var scale = 1 / (rangeBand*4 / width);
-      var padding = rangeBand*1.5
-      var translateNow = [-scale * (xYear - padding), -scale * (height + d.y)];
+            year.values.forEach(function(d, i) {
+                var row = (Math.floor(i / collumns) + 2);
+                d.ii = i;
 
-      vizContainer
-          .call(zoom.translate(translate).event)
-          .transition().duration(2000)
-          .call(zoom.scale(scale).translate(translateNow).event)
-  }
-
-  function zoomToImage(d, duration) {
+                d.x = startX + ((i % collumns) * (rangeBand / collumns));
+                d.y = (invert ? 1 : -1) * (row * (rangeBand / collumns));
 
-      // console.log("detail", d)
+                d.x1 = d.x * scale1 + imageSize / 2;
+                d.y1 = d.y * scale1 + imageSize / 2;
 
-      state.zoomingToImage = true;
+                if (d.sprite.position.x == 0) {
+                    d.sprite.position.x = d.x1;
+                    d.sprite.position.y = d.y1;
+                }
 
-      zoom.center(null);
+                if (d.sprite2) {
+                    d.sprite2.position.x = d.x * scale2 + imageSize2 / 2;
+                    d.sprite2.position.y = d.y * scale2 + imageSize2 / 2;
+                }
 
-      loadMiddleImage(d);
+                d.order = (invert ? 1 : 1) * (total - i);
+            })
+        })
+    }
 
-      d3.select(".tagcloud").classed("hide", true);
+    canvas.distance = function(a, b) {
+        return Math.sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]));
+    }
 
-      var padding = x.rangeBand() / collumns / 2;
-      var sidbar = width / 8;
-      // var padding = 0;
-      var scale = 0.8 / (x.rangeBand() / collumns / width);
-      var translateNow = [(-scale * (d.x - padding/2)) - sidbar, -scale * (height + d.y)];
+    function toScreenPoint(p) {
+        var p2 = [0, 0];
 
-      //console.log(scale, translateNow);
+        p2[0] = p[0] / scale - translate[0] / scale;
+        p2[1] = (p[1] / scale - height) - translate[1] / scale;
 
-      zoomedToImageScale = scale;
+        return p2;
+    }
 
-      setTimeout(function() {
-          hideTheRest(d);
-      }, duration / 2);
+    function imageAnimation() {
+        var sleep = true
 
-      vizContainer
-          .call(zoom.translate(translate).event)
-          .transition().duration(duration)
-          .call(zoom.scale(scale).translate(translateNow).event)
-          .each("end", function() {
+        data.forEach(function(d, i) {
+            var diff;
+            diff = (d.x1 - d.sprite.position.x);
+            if (Math.abs(diff) > 0.1) {
+                d.sprite.position.x += diff * 0.1;
+                sleep = false;
+            }
 
-              zoomedToImage = true;
-              selectedImage = d;
+            diff = (d.y1 - d.sprite.position.y);
+            if (Math.abs(diff) > 0.1) {
+                d.sprite.position.y += diff * 0.1
+                sleep = false;
+            }
 
-              hideTheRest(d);
+            diff = (d.alpha - d.sprite.alpha);
+            if (Math.abs(diff) > 0.01) {
+                d.sprite.alpha += diff * 0.2
+                sleep = false;
+            }
 
-              showDetail(d);
+            d.sprite.visible = d.sprite.alpha > 0.1;
 
-              loadBigImage(d, "click");
+            if (d.sprite2) {
+                diff = (d.alpha2 - d.sprite2.alpha);
+                if (Math.abs(diff) > 0.01) {
+                    d.sprite2.alpha += diff * 0.2
+                    sleep = false;
+                }
 
-              state.zoomingToImage = false;
-          })
-  }
+                d.sprite2.visible = d.sprite2.alpha > 0.1;
+                //else d.sprite2.visible = d.visible;
+            }
+        });
+        return sleep
+    }
 
-  function showDetail(d) {
-      console.log("show detail", d)
+    
+    canvas.wakeup = function() { sleep = false }
+
+    function animate(time) {
+        requestAnimationFrame(animate);
+        loadImages();
+        if (sleep) return
+        sleep = imageAnimation();
+        renderer.render(stage);
+    }
+
+    function zoomToYear(d) {
+
+        var xYear = x(d.year);
+        var scale = 1 / (rangeBand * 4 / width);
+        var padding = rangeBand * 1.5
+        var translateNow = [-scale * (xYear - padding), -scale * (height + d.y)];
+
+        vizContainer
+            .call(zoom.translate(translate).event)
+            .transition().duration(2000)
+            .call(zoom.scale(scale).translate(translateNow).event)
+    }
+
+    function zoomToImage(d, duration) {
+        state.zoomingToImage = true;
+        zoom.center(null);
+        loadMiddleImage(d);
+        d3.select(".tagcloud").classed("hide", true);
+        var padding = x.rangeBand() / collumns / 2;
+        var sidbar = width / 8;
+        var scale = 0.8 / (x.rangeBand() / collumns / width);
+        var translateNow = [(-scale * (d.x - padding / 2)) - sidbar, -scale * (height + d.y)];
+
+        zoomedToImageScale = scale;
+
+        setTimeout(function() {
+            hideTheRest(d);
+        }, duration / 2);
+
+        vizContainer
+            .call(zoom.translate(translate).event)
+            .transition().duration(duration)
+            .call(zoom.scale(scale).translate(translateNow).event)
+            .each("end", function() {
+                zoomedToImage = true;
+                selectedImage = d;
+                hideTheRest(d);
+                showDetail(d);
+                loadBigImage(d, "click");
+                state.zoomingToImage = false;
+            })
+    }
+
+    function showDetail(d) {
+        console.log("show detail", d)
+
+        detailContainer
+            .select(".outer")
+            .node()
+            .scrollTop = 0;
+
+        detailContainer
+            .classed("hide", false)
+            .classed("sneak", utils.isMobile())
+
+        // needs to be done better
+        var detailData = {}
+        for (field in selectedImage) {
+            if (field[0] === '_') detailData[field] = selectedImage[field]
+        }
+        detailData['_id'] = selectedImage.id
+        detailData['_keywords'] = selectedImage.keywords
+        detailData['_year'] = selectedImage.year
+        detailData['_imagenum'] = selectedImage.imagenum || 1
+        detailVue._data.item = detailData
+        detailVue._data.id = d.id
+        detailVue._data.page = d.page
+
+    }
+
+    canvas.changePage = function(id, page) {
+        console.log("changePage", id, page, selectedImage);
+        selectedImage.page = page
+        detailVue._data.page = page
+        clearBigImages();
+        loadBigImage(selectedImage)
+    }
+
+
+    function hideTheRest(d) {
+        data.forEach(function(d2) {
+            if (d2.id !== d.id) {
+                d2.alpha = 0;
+                d2.alpha2 = 0;
+
+            }
+        })
+    }
 
-      detailContainer
-       .select(".outer")
-       .node()
-       .scrollTop = 0;
+    function showAllImages() {
+        data.forEach(function(d) {
+            d.alpha = d.active ? 1 : 0.2;;
+            d.alpha2 = d.visible ? 1 : 0;
+        })
+    }
+
+    function zoomed() {
+        translate = d3.event.translate;
+        scale = d3.event.scale;
+        if (!startTranslate) startTranslate = translate
+        drag = startTranslate && translate !== startTranslate;
+        // check borders
+        var x1 = -1 * translate[0] / scale;
+        var x2 = (x1 + (widthOuter / scale));
+
+        if (d3.event.sourceEvent != null) {
+            if (x1 < 0) {
+                translate[0] = 0;
+            } else if (x2 > widthOuter) {
+                translate[0] = ((widthOuter * scale) - widthOuter) * -1;
+            }
+
+            zoom.translate([translate[0], translate[1]]);
+
+            x1 = -1 * translate[0] / scale;
+            x2 = (x1 + (width / scale))
+        }
 
-      detailContainer
-          .classed("hide", false)
-          .classed("sneak", utils.isMobile() )
+        if (zoomedToImageScale != 0 && scale > zoomedToImageScale && !zoomedToImage && selectedImage && selectedImage.type == "image") {
 
-      // needs to be done better
-      var detailData = {}
-      for ( field in selectedImage ){
-        if(field[0] === '_') detailData[field] = selectedImage[field]
-      }
-      detailData['_id'] = selectedImage.id
-      detailData['_keywords'] = selectedImage.keywords
-      detailData['_year'] = selectedImage.year
-      detailData['_imagenum'] = selectedImage.imagenum || 1
-      detailVue._data.item = detailData
-      detailVue._data.id = d.id
-      detailVue._data.page = d.page
+            zoomedToImage = true;
+            zoom.center(null);
+            zoomedToImageScale = scale;
+            hideTheRest(selectedImage);
+            showDetail(selectedImage)
+        }
 
-  }
+        if (zoomedToImage && zoomedToImageScale - 20 > scale) {
+            // c("clear")
+            zoomedToImage = false;
+            state.lastZoomed = 0;
+            showAllImages();
+            clearBigImages();
+            detailContainer.classed("hide", true)
+        }
 
-  canvas.changePage = function (id, page){
-    console.log("changePage", id, page, selectedImage);
-    selectedImage.page = page
-    detailVue._data.page = page
-    clearBigImages();
-    loadBigImage(selectedImage)
-  }
+        timeline.update(x1, x2, scale, translate, scale1);
 
+        // toggle zoom overlays
+        if (scale > zoomBarrier) {
+            d3.select(".tagcloud").classed("hide", true);
+            d3.select(".searchbar").classed("hide", true);
+            d3.select(".infobar").classed("sneak", true);
+        } else {
+            d3.select(".tagcloud").classed("hide", false);
+            d3.select(".searchbar").classed("hide", false);
+        }
 
-  function hideTheRest(d) {
-      // c("hide", d.id)
-      data.forEach(function(d2) {
-          if (d2.id !== d.id) {
-              // d2.sprite.alpha = 0;
-              // d2.sprite.visible = false;
-              d2.alpha = 0;
-              d2.alpha2 = 0;
 
-          }
-      })
-  }
+        stage2.scale.x = d3.event.scale;
+        stage2.scale.y = d3.event.scale;
+        stage2.x = d3.event.translate[0];
+        stage2.y = d3.event.translate[1];
 
-  function showAllImages() {
-      data.forEach(function(d) {
-          d.alpha = d.active ? 1 : 0.2;;
-          //d.visible = d.active;
-          d.alpha2 = d.visible ? 1 : 0;
-          //d.sprite.visible = true;  
+        sleep = false
+    }
+
+    function zoomstart(d) {
+        zooming = true;
+        startTranslate = false;
+        drag = false
+        startScale = scale;
+    }
+
+    function zoomend(d) {
+        drag = startTranslate && translate !== startTranslate;
+        zooming = false;
+        filterVisible();
+
+        if (zoomedToImage && !selectedImage.big && state.lastZoomed != selectedImage.id && !state.zoomingToImage) {
+            loadBigImage(selectedImage, "zoom");
+        }
+    }
 
-      })
-  }
+    canvas.highlight = function() {
+        data.forEach(function(d, i) {
+            d.alpha = d.highlight ? 1 : 0.2;
+        });
+        canvas.wakeup();
+    }
 
+    canvas.project = function() {
+        sleep = false
+        canvas.split();
+        canvas.resetZoom();
+    }
+
+    canvas.resetZoom = function() {
+        var duration = 1400;
+        console.log(translate)
+        extent = d3.extent(data, function(d) { return d.y; });
+
+        var y = -extent[1] - bottomPadding;
+        y = (extent[1] / -3) - bottomPadding
+
+        vizContainer
+            .call(zoom.translate(translate).event)
+            .transition().duration(duration)
+            .call(zoom.translate([0, y]).scale(1).event)
+    }
+
+    canvas.split = function() {
+        var active = data.filter(function(d) {
+            return d.active;
+        })
+        stackLayout(active, false);
+        var inactive = data.filter(function(d) {
+            return !d.active;
+        })
+        stackLayout(inactive, true);
+        quadtree = Quadtree(data);
+    }
+
+    function filterVisible() {
+        var zoomScale = scale;
+        if (zoomedToImage) return;
+
+        data.forEach(function(d, i) {
+            var p = d.sprite.position;
+            var x = (p.x / scale1) + translate[0] / zoomScale;
+            var y = ((p.y / scale1) + (translate[1]) / zoomScale);
+            var padding = 5;
+
+            if (x > (-padding) && x < ((width / zoomScale) + padding) && y + height < (height / zoomScale + padding) && y > (height * -1) - padding) {
+                d.visible = true;
+            } else {
+                d.visible = false;
+            }
+        });
 
-  var timelineHover = false;
+        var visible = data.filter(function(d) {
+            return d.visible;
+        });
 
+        if (visible.length < 40) {
+            data.forEach(function(d) {
+                if (d.visible && d.loaded && d.active) d.alpha2 = 1;
+                else if (d.visible && !d.loaded && d.active) loadImagesCue.push(d);
+                else d.alpha2 = 0;
+            })
+        } else {
+            data.forEach(function(d) {
+                d.alpha2 = 0;
+            })
+        }
+    }
 
-  function zoomed() {
+    function loadMiddleImage(d) {
+        if (d.loaded) {
+            d.alpha2 = 1;
+            return;
+        }
 
-      translate = d3.event.translate;
-      scale = d3.event.scale;
-      if(!startTranslate) startTranslate = translate
-      drag = startTranslate && translate !== startTranslate;
-      // check borders
+        // console.log("load", d)
+        var texture = new PIXI.Texture.fromImage(config.loader.textures.detail.url + d.id + '.jpg', true)
+        var sprite = new PIXI.Sprite(texture);
 
-      var x1 = -1 * translate[0] / scale;
-      var x2 = (x1 + (widthOuter / scale));
+        var update = function() {
+            sleep = false
+        }
 
-      var y1 = (translate[1] + height * scale);
-
-      var e1 = -extent[1] - bottomPadding;
-      var y2 = (e1 - height) * scale + height;
-
-      var e2 = extent[0] - bottomPadding;
-      var y3 = (e2 + height) * -scale;
-
-      // console.log(translate[1],e2, y3);
-
-      if (d3.event.sourceEvent != null) {
-          if (x1 < 0) {
-              translate[0] = 0;
-          } else if (x2 > widthOuter) {
-              translate[0] = ((widthOuter * scale) - widthOuter) * -1;
-          }
-
-          if (translate[1] < y2) {
-              // translate[1] = y2;
-          }
-
-          zoom.translate([translate[0], translate[1]]);
-
-          x1 = -1 * translate[0] / scale;
-          x2 = (x1 + (width / scale))
-      }
-
-      if (zoomedToImageScale != 0 && scale > zoomedToImageScale && !zoomedToImage && selectedImage && selectedImage.type == "image") {
-          
-          zoomedToImage = true;
-          zoom.center(null);
-          zoomedToImageScale = scale;
-          hideTheRest(selectedImage);
-          showDetail(selectedImage)
-      }
-
-      if (zoomedToImage && zoomedToImageScale - 20 > scale) {
-          // c("clear")
-          zoomedToImage = false;
-          state.lastZoomed = 0;
-          showAllImages();
-          clearBigImages();
-          detailContainer.classed("hide", true)
-      }
-
-      timeline.update(x1, x2, scale, translate, scale1);
-    
-      // toggle zoom overlays
-      if (scale > zoomBarrier) {
-          d3.select(".tagcloud").classed("hide", true);
-          d3.select(".searchbar").classed("hide", true);
-          d3.select(".infobar").classed("sneak", true);
-      } else {
-          d3.select(".tagcloud").classed("hide", false);
-          d3.select(".searchbar").classed("hide", false);
-      }
-
-
-      stage2.scale.x = d3.event.scale;
-      stage2.scale.y = d3.event.scale;
-      stage2.x = d3.event.translate[0];
-      stage2.y = d3.event.translate[1];
-
-      sleep = false
-  }
-
-  function zoomstart(d) {
-      zooming = true;
-      startTranslate = false;
-      drag = false
-      startScale = scale;
-  }
-
-  function zoomend(d) {
-      drag = startTranslate && translate !== startTranslate;
-      zooming = false;
-      filterVisible();
-
-      if (zoomedToImage && !selectedImage.big && state.lastZoomed != selectedImage.id && !state.zoomingToImage) {
-          //c("loadbig after zoom")
-          loadBigImage(selectedImage, "zoom");
-      }
-  }
-
-  canvas.highlight = function() {
-      data.forEach(function(d, i) {
-          d.alpha = d.highlight ? 1 : 0.2;
-      });
-      canvas.wakeup();
-  }
-
-  canvas.project = function(){
-    sleep = false
-    canvas.split();
-    canvas.resetZoom();
-  }
-
-  canvas.resetZoom = function() {
-      var duration = 1400;
-      console.log(translate)
-      extent = d3.extent(data, function(d) { return d.y; });
-
-      var y = -extent[1] - bottomPadding;
-      // console.log(extent, y)
-      y =  (extent[1] / -3) - bottomPadding
-      // y =  - bottomPadding
-      //bottomZooming = (y<-30 && y>-40);      
-
-      vizContainer
-          .call(zoom.translate(translate).event)
-          .transition().duration(duration)
-          .call(zoom.translate([0, y]).scale(1).event)
-          //.each("end", canvas.split)
-  }
-
-  canvas.split = function() {
-      var active = data.filter(function(d) {
-          return d.active;
-      })
-      stackLayout(active, false);
-
-      var inactive = data.filter(function(d) {
-          return !d.active;
-      })
-      stackLayout(inactive, true);
-
-      // console.time("Quadtree")
-      quadtree = Quadtree(data);
-      // console.timeEnd("Quadtree");
- 
-  }
-
-  function filterVisible() {
-
-      var zoomScale = scale;
-
-      if (zoomedToImage) return;
-
-      data.forEach(function(d, i) {
-          var p = d.sprite.position;
-          var x = (p.x / scale1) + translate[0] / zoomScale;
-          var y = ((p.y / scale1) + (translate[1]) / zoomScale);
-          var padding = 5;
-
-          // c(x,y,p, translate, zoomScale, scale, height/zoomScale, y+height)
-
-          if (x > (-padding) && x < ((width / zoomScale) + padding) && y + height < (height / zoomScale + padding) && y > (height * -1) - padding) {
-              //d.sprite.alpha = 1;
-              d.visible = true;
-              // d.alpha = 1;
-          } else {
-              //d.sprite.alpha = 0.5;
-              d.visible = false;
-              // d.alpha = 0;
-          }
-      });
-
-      var visible = data.filter(function(d) {
-          return d.visible;
-      });
-      //c(visible.length);
-
-
-      if (visible.length < 40) {
-          data.forEach(function(d) {
-              if (d.visible && d.loaded && d.active) d.alpha2 = 1;
-              else if (d.visible && !d.loaded && d.active) loadImagesCue.push(d);
-              else d.alpha2 = 0;
-          })
-      } else {
-          data.forEach(function(d) {
-              d.alpha2 = 0;
-              //if(d.sprite2) d.sprite2.visible = false;
-          })
-      }
-
-
-  }
-
-  function loadMiddleImage(d) {
-      if (d.loaded) {
-          d.alpha2 = 1;
-          return;
-      }
-
-      // console.log("load", d)
-      var texture = new PIXI.Texture.fromImage(config.loader.textures.detail.url + d.id + '.jpg', true)
-      var sprite = new PIXI.Sprite(texture);
-
-      var update = function() {
+        sprite.on('added', update)
+        texture.once('update', update)
+
+        sprite.scale.x = d.scaleFactor;
+        sprite.scale.y = d.scaleFactor;
+
+        sprite.anchor.x = 0.5;
+        sprite.anchor.y = 0.5;
+        sprite.position.x = d.x * scale2 + imageSize2 / 2;
+        sprite.position.y = d.y * scale2 + imageSize2 / 2;
+        sprite._data = d;
+        stage4.addChild(sprite);
+        d.sprite2 = sprite;
+        d.alpha2 = d.highlight;
+        d.loaded = true;
         sleep = false
-      }
+    }
 
-      sprite.on('added', update)
-      texture.once('update', update)
+    function loadBigImage(d) {
+        if (!config.loader.textures.big) {
+            loadMiddleImage(d)
+            return
+        }
 
-      sprite.scale.x = d.scaleFactor;
-      sprite.scale.y = d.scaleFactor;
+        state.lastZoomed = d.id;
+        var page = d.page ? '_' + d.page : ''
+        var url = config.loader.textures.big.url + d.id + page + ".jpg";
 
-      sprite.anchor.x = 0.5;
-      sprite.anchor.y = 0.5;
-      sprite.position.x = d.x * scale2 + imageSize2 / 2;
-      sprite.position.y = d.y * scale2 + imageSize2 / 2;
-      sprite._data = d;
+        var texture = new PIXI.Texture.fromImage(url, true)
+        var sprite = new PIXI.Sprite(texture);
+        var res = config.loader.textures.big.size
 
-      stage4.addChild(sprite);
+        var updateSize = function() {
+            var size = Math.max(texture.width, texture.height)
+            sprite.scale.x = sprite.scale.y = (imageSize3 / size) * d.scaleFactor;
+            sleep = false
+        }
 
-      d.sprite2 = sprite;
-      d.alpha2 = d.highlight;
-   
+        sprite.on('added', updateSize)
+        texture.once('update', updateSize)
+
+        if (d.imagenum) {
+            sprite.on("mousemove", function(s) {
+                var pos = s.data.getLocalPosition(s.currentTarget)
+                s.currentTarget.cursor = pos.x > 0 ? "e-resize" : "w-resize"
+            })
+            sprite.on("click", function(s) {
+                if (drag) return
+
+                s.stopPropagation()
+                spriteClick = true
+                var pos = s.data.getLocalPosition(s.currentTarget)
+                var dir = pos.x > 0 ? 1 : -1
+                var page = d.page + dir
+                var nextPage = page
+                if (page > d.imagenum - 1) nextPage = 0
+                if (page < 0) nextPage = d.imagenum - 1
+
+                canvas.changePage(d.id, nextPage)
+            })
+            sprite.interactive = true;
+        }
 
-      d.loaded = true;
-      sleep = false
-  }
+        sprite.anchor.x = 0.5;
+        sprite.anchor.y = 0.5;
+        sprite.position.x = d.x * scale3 + imageSize3 / 2;
+        sprite.position.y = d.y * scale3 + imageSize3 / 2;
+        sprite._data = d;
+        d.big = true;
+        stage5.addChild(sprite);
+        sleep = false
+    }
 
-  function loadBigImage(d) {
-      if(!config.loader.textures.big) {
-        loadMiddleImage(d)
-        return
-      }
+    function clearBigImages() {
+        while (stage5.children[0]) {
+            stage5.children[0]._data.big = false;
+            stage5.removeChild(stage5.children[0]);
+            sleep = false
+        }
+    }
 
-      state.lastZoomed = d.id;
-      var page = d.page ? '_' + d.page : ''
-      var url = config.loader.textures.big.url + d.id + page + ".jpg";
+    function loadImages() {
+        if (zooming) return;
+        if (zoomedToImage) return;
 
-      var texture = new PIXI.Texture.fromImage(url, true)
-      var sprite = new PIXI.Sprite(texture);
-      var res = config.loader.textures.big.size
+        if (loadImagesCue.length) {
+            var d = loadImagesCue.pop();
+            if (!d.loaded) {
+                loadMiddleImage(d);
+            }
+        }
+    }
+
+    function nearest(x, y, best, node) {
+        // mike bostock https://bl.ocks.org/mbostock/4343214
+        var x1 = node.x1,
+            y1 = node.y1,
+            x2 = node.x2,
+            y2 = node.y2;
+        node.visited = true;
+        //console.log(node, x , x1 , best.d);
+        //return;
+        // exclude node if point is farther away than best distance in either axis
+        if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) {
+            return best;
+        }
+        // test point if there is one, potentially updating best
+        var p = node.point;
+        if (p) {
+            p.scanned = true;
+            var dx = p.x - x,
+                dy = p.y - y,
+                d = Math.sqrt(dx * dx + dy * dy);
+            if (d < best.d) {
+                best.d = d;
+                best.p = p;
+            }
+        }
+        // check if kid is on the right or left, and top or bottom
+        // and then recurse on most likely kids first, so we quickly find a 
+        // nearby point and then exclude many larger rectangles later
+        var kids = node.nodes;
+        var rl = (2 * x > x1 + x2),
+            bt = (2 * y > y1 + y2);
+        if (kids[bt * 2 + rl]) best = nearest(x, y, best, kids[bt * 2 + rl]);
+        if (kids[bt * 2 + (1 - rl)]) best = nearest(x, y, best, kids[bt * 2 + (1 - rl)]);
+        if (kids[(1 - bt) * 2 + rl]) best = nearest(x, y, best, kids[(1 - bt) * 2 + rl]);
+        if (kids[(1 - bt) * 2 + (1 - rl)]) best = nearest(x, y, best, kids[(1 - bt) * 2 + (1 - rl)]);
 
-      var updateSize = function() {
-        var size = Math.max(texture.width, texture.height)
-        sprite.scale.x = sprite.scale.y = (imageSize3 / size) * d.scaleFactor;
-        sleep = false
-      }
+        return best;
+    }
 
-      sprite.on('added', updateSize)
-      texture.once('update', updateSize)
 
-      if(d.imagenum) {
-        sprite.on("mousemove", function (s) {
-          var pos = s.data.getLocalPosition(s.currentTarget)
-          s.currentTarget.cursor = pos.x > 0 ? "e-resize" : "w-resize"
-        })
-        sprite.on("click", function (s) {
-          if(drag) return
-
-          s.stopPropagation()
-          spriteClick = true
-          var pos = s.data.getLocalPosition(s.currentTarget)
-          var dir = pos.x > 0 ? 1 : -1
-          var page = d.page + dir
-          // var nextPage = Math.min(Math.max(page, 0), d.imagenum-1)
-          var nextPage = page
-          if(page > d.imagenum-1) nextPage = 0
-          if(page < 0) nextPage = d.imagenum-1
-
-          canvas.changePage(d.id, nextPage)
-        })
-        sprite.interactive = true;
-      }
-
-      sprite.anchor.x = 0.5;
-      sprite.anchor.y = 0.5;
-      sprite.position.x = d.x * scale3 + imageSize3 / 2;
-      sprite.position.y = d.y * scale3 + imageSize3 / 2;
-      sprite._data = d;
-      d.big = true;
-
-      // console.log(sprite, "done")
-
-      stage5.addChild(sprite);
-      sleep = false
-  }
-
-  function clearBigImages() {
-      while (stage5.children[0]) {
-          stage5.children[0]._data.big = false;
-          stage5.removeChild(stage5.children[0]);
-          sleep = false
-      }
-  }
-
-  function loadImages() {
-      if (zooming) return;
-      if (zoomedToImage) return;
-
-      if (loadImagesCue.length) {
-          var d = loadImagesCue.pop();
-          if (!d.loaded) {
-              loadMiddleImage(d);
-          }
-      }
-  }
-
-
-  // function translateUpDown(dir) {
-
-  //     var translateNow = [translate[0], translate[1] + dir * 10 * scale];
-
-  //     svg
-  //         .call(zoom.translate(translate).event)
-  //         .transition().duration(1000)
-  //         .call(zoom.translate(translateNow).event)
-  // }
-
-  // function getSiblingImage(active, dir) {
-  //     if (!active) return;
-
-  //     return data.filter(function(d) {
-  //         return (d.order == active.order + dir && d.year == active.year);
-  //     })[0];
-
-  // }
-
-  function nearest(x, y, best, node) {
-      // mike bostock https://bl.ocks.org/mbostock/4343214
-      var x1 = node.x1,
-          y1 = node.y1,
-          x2 = node.x2,
-          y2 = node.y2;
-      node.visited = true;
-      //console.log(node, x , x1 , best.d);
-      //return;
-      // exclude node if point is farther away than best distance in either axis
-      if (x < x1 - best.d || x > x2 + best.d || y < y1 - best.d || y > y2 + best.d) {
-          return best;
-      }
-      // test point if there is one, potentially updating best
-      var p = node.point;
-      if (p) {
-          p.scanned = true;
-          var dx = p.x - x,
-              dy = p.y - y,
-              d = Math.sqrt(dx * dx + dy * dy);
-          if (d < best.d) {
-              best.d = d;
-              best.p = p;
-          }
-      }
-      // check if kid is on the right or left, and top or bottom
-      // and then recurse on most likely kids first, so we quickly find a 
-      // nearby point and then exclude many larger rectangles later
-      var kids = node.nodes;
-      var rl = (2 * x > x1 + x2),
-          bt = (2 * y > y1 + y2);
-      if (kids[bt * 2 + rl]) best = nearest(x, y, best, kids[bt * 2 + rl]);
-      if (kids[bt * 2 + (1 - rl)]) best = nearest(x, y, best, kids[bt * 2 + (1 - rl)]);
-      if (kids[(1 - bt) * 2 + rl]) best = nearest(x, y, best, kids[(1 - bt) * 2 + rl]);
-      if (kids[(1 - bt) * 2 + (1 - rl)]) best = nearest(x, y, best, kids[(1 - bt) * 2 + (1 - rl)]);
-
-      return best;
-  }
-
-
-  return canvas;
-
-}
+    return canvas;
+
+}
\ No newline at end of file
diff --git a/js/viz.js b/js/viz.js
index 0db8aaf..26db617 100644
--- a/js/viz.js
+++ b/js/viz.js
@@ -1,4 +1,3 @@
-
 //                            ,--.                                     
 //                ,---,   ,--/  /|               .--.--.               
 //        ,---.,`--.' |,---,': / '         ,--, /  /    '.             
@@ -26,7 +25,7 @@
 //      :   \ |;   |.' |   :   .'    :   '  |--" |   :   .':   : :-'   
 //       '---" '---'   |   | ,'       \   \ ;    |   | ,'  |   |.'     
 //                     `----'          '---"     `----'    `---'       
-                                                                    
+
 
 // christopher pietsch
 // @chrispiecom
@@ -42,77 +41,75 @@ var search;
 var ping;
 
 if (Modernizr.webgl && !utils.isMobile()) {
-  init();
+		init();
 }
 
 
 function init() {
 
-    tags = Tags();
-    canvas = Canvas();
-    search = Search();
-    timeline = Timeline()
-    ping = utils.ping();
-
-    d3.json("data/config.json", function(config) {
-
-      utils.initConfig(config)
-      
-      d3.csv(config.loader.timeline, function(timeline) {
-          Loader(config.loader.items).finished(function(data) {
-
-              utils.clean(data);
-
-              tags.init(data, config);
-              search.init();
-              canvas.init(data, timeline, config);
-
-              LoaderSprites()
-                .progress(function(textures){
-                  Object.keys(textures).forEach(function(id){
-                    data
-                      .filter(function (d) { return d.id === id })
-                      .forEach(function(d) { 
-                        d.sprite.texture = textures[id]
-                      })
-                  })
-                  canvas.wakeup()
-                })
-                .load(config.loader.textures.medium.url)
-          });
-        });
-    });
-
-    d3.select(window)
-        .on("resize", function() {
-          if(canvas !== undefined && tags !== undefined) {
-            clearTimeout(window.resizedFinished);
-            window.resizedFinished = setTimeout(function() {
-                canvas.resize();
-                tags.resize();
-            }, 250);
-          }
-        })
-        .on("keydown", function(e) {
-          if(d3.event.keyCode != 27) return
-          search.reset();
-          tags.reset();
-          canvas.split();
-        })
+		tags = Tags();
+		canvas = Canvas();
+		search = Search();
+		timeline = Timeline()
+		ping = utils.ping();
+
+		d3.json("data/config.json", function(config) {
+
+				utils.initConfig(config)
+
+				d3.csv(config.loader.timeline, function(timeline) {
+						Loader(config.loader.items).finished(function(data) {
+
+								utils.clean(data);
+
+								tags.init(data, config);
+								search.init();
+								canvas.init(data, timeline, config);
+
+								LoaderSprites()
+										.progress(function(textures) {
+												Object.keys(textures).forEach(function(id) {
+														data
+																.filter(function(d) { return d.id === id })
+																.forEach(function(d) {
+																		d.sprite.texture = textures[id]
+																})
+												})
+												canvas.wakeup()
+										})
+										.load(config.loader.textures.medium.url)
+						});
+				});
+		});
+
+		d3.select(window)
+				.on("resize", function() {
+						if (canvas !== undefined && tags !== undefined) {
+								clearTimeout(window.resizedFinished);
+								window.resizedFinished = setTimeout(function() {
+										canvas.resize();
+										tags.resize();
+								}, 250);
+						}
+				})
+				.on("keydown", function(e) {
+						if (d3.event.keyCode != 27) return
+						search.reset();
+						tags.reset();
+						canvas.split();
+				})
+
+		d3.select(".slidebutton")
+				.on("click", function() {
+						var s = !d3.select(".sidebar").classed("sneak");
+						d3.select(".sidebar").classed("sneak", s);
+				})
+
+		d3.select(".infobutton")
+				.on("click", function() {
+						var s = !d3.select(".infobar").classed("sneak");
+						d3.select(".infobar").classed("sneak", s)
+				})
 }
 
-
-d3.select(".slidebutton")
-  .on("click", function(){
-    var s = !d3.select(".sidebar").classed("sneak");
-    d3.select(".sidebar").classed("sneak", s);
-  })
-
-d3.select(".infobutton")
-  .on("click", function(){
-    var s = !d3.select(".infobar").classed("sneak");
-    d3.select(".infobar").classed("sneak", s)
-  })
-
-
-d3.select(".browserInfo").classed("show", utils.isMobile());
+d3.select(".browserInfo").classed("show", utils.isMobile());
\ No newline at end of file
-- 
GitLab