Home | History | Annotate | Download | only in imp
      1 <script type="text/javascript" charset="utf-8">
      2   /**
      3    * A reusable HTML Import to enable zooming on images.
      4    *
      5    * To use, simply include this HTML Import and add the class 'zoom' to any
      6    * images you want zoomable.
      7    *
      8    *     <link rel='import' type='text/html' href='/res/imp/zoom.html'>
      9    *
     10    *     <img src="http://..." class="zoom"/>
     11    *
     12    * Any number of images on a page can be zoomable.
     13    *
     14    * If you want to display the rgb colors of the pixel at the center of the
     15    * zoom then add an id of 'zoomHex' to any element that supports
     16    * textContent, such as a div, p, span, etc.
     17    *
     18    *     <p id=zoomHex></p>
     19    *
     20    * Note that HTML Imports need to be polyfilled in the near term.
     21    */
     22   (function () {
     23     function onLoad() {
     24       var PIXELS       = 20; // The number of pixels in width and height in a zoom.
     25       var clientX      = 0;
     26       var clientY      = 0;
     27       var lastClientX  = 0;
     28       var lastClientY  = 0;
     29       var ctx          = null; // The 2D canvas context of the zoom.
     30       var currentImage = null; // The img node we are zooming for, otherwise null.
     31       var hex          = document.getElementById('zoomHex');
     32       var canvasCopy   = null;
     33       function zoomMove(e) {
     34         clientX = e.clientX;
     35         clientY = e.clientY;
     36       }
     37       function zoomMouseDown(e) {
     38         e.preventDefault();
     39         // Only do zooming on the primary mouse button.
     40         if (e.button != 0) {
     41           return
     42         }
     43         currentImage = e.target;
     44         clientX = e.clientX;
     45         clientY = e.clientY;
     46         lastClientX = clientX-1;
     47         lastClientY = clientY-1;
     48         document.body.style.cursor = 'crosshair';
     49         canvas = document.createElement('canvas');
     50         canvas.width = 1024;
     51         canvas.height = 1024;
     52         canvas.classList.add('zoomCanvas');
     53         ctx = canvas.getContext('2d');
     54         ctx.imageSmoothingEnabled = false;
     55         this.parentNode.insertBefore(canvas, this);
     56         // Copy the image over to a canvas so we can read RGBA values for each point.
     57         if (hex) {
     58           canvasCopy = document.createElement('canvas');
     59           canvasCopy.width = currentImage.width;
     60           canvasCopy.height = currentImage.height;
     61           canvasCopy.id = 'zoomCopy';
     62           canvasCopy.getContext('2d').drawImage(currentImage, 0, 0, currentImage.width, currentImage.height);
     63           this.parentNode.insertBefore(canvasCopy, this);
     64         }
     65         document.body.addEventListener('pointermove',   zoomMove,     true);
     66         document.body.addEventListener('pointerup',     zoomFinished);
     67         document.body.addEventListener('pointerleave',  zoomFinished);
     68         // Kick off the drawing.
     69         setTimeout(drawZoom, 1);
     70       }
     71       function hexify(i) {
     72         var s = i.toString(16).toUpperCase();
     73         // Pad out to two hex digits if necessary.
     74         if (s.length < 2) {
     75           s = '0' + s;
     76         }
     77         return s;
     78       }
     79       function drawZoom() {
     80         if (currentImage) {
     81           // Only draw if the mouse has moved from the last time we drew.
     82           if (lastClientX != clientX || lastClientY != clientY) {
     83             ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
     84             var x = clientX - currentImage.x;
     85             var y = clientY - currentImage.y;
     86             var dx = Math.floor(ctx.canvas.width/PIXELS);
     87             var dy = Math.floor(ctx.canvas.height/PIXELS);
     88             ctx.lineWidth = 1;
     89             ctx.strokeStyle = '#000';
     90             // Draw out each pixel as a rect on the target canvas, as this works around
     91             // FireFox doing a blur as it copies from one canvas to another.
     92             var colors = canvasCopy.getContext('2d').getImageData(x, y, PIXELS, PIXELS).data;
     93             for (var i=0; i<PIXELS; i++) {
     94               for (var j=0; j<PIXELS; j++) {
     95                 var offset = (j*PIXELS+i)*4; // Offset into the colors array.
     96                 ctx.fillStyle = 'rgba(' + colors[offset] + ', ' + colors[offset+1] + ', ' + colors[offset+2] + ', ' + colors[offset+3]/255.0 + ')';
     97                 ctx.fillRect(i*dx, j*dy, dx-1, dy-1);
     98                 // Box and label one selected pixel with its rgba values.
     99                 if (hex && i==PIXELS/2 && j == PIXELS/2) {
    100                   ctx.strokeRect(i*dx, j*dy, dx-1, dy-1);
    101                   hex.textContent = 'rgba('
    102                     + colors[offset] + ', '
    103                     + colors[offset+1] + ', '
    104                     + colors[offset+2] + ', '
    105                     + colors[offset+3] + ') '
    106                     + hexify(colors[offset])
    107                     + hexify(colors[offset+1])
    108                     + hexify(colors[offset+2])
    109                     + hexify(colors[offset+3]);
    110                 }
    111               }
    112             }
    113             lastClientX = clientX;
    114             lastClientY = clientY;
    115           }
    116           setTimeout(drawZoom, 1000/30);
    117         }
    118       }
    119       function zoomFinished() {
    120         currentImage = null;
    121         if (hex) {
    122           hex.textContent = '';
    123         }
    124         document.body.style.cursor = 'default';
    125         ctx.canvas.parentNode.removeChild(ctx.canvas);
    126         canvasCopy.parentNode.removeChild(canvasCopy);
    127         document.body.removeEventListener('pointermove',  zoomMove,     true);
    128         document.body.removeEventListener('pointerup',    zoomFinished);
    129         document.body.removeEventListener('pointerleave', zoomFinished);
    130       }
    131 
    132       var zoomables = document.body.querySelectorAll('.zoom');
    133       for (var i=0; i<zoomables.length; i++) {
    134         zoomables[i].addEventListener('pointerdown', zoomMouseDown);
    135       }
    136     }
    137 
    138     // If loaded via HTML Imports then DOMContentLoaded will be long done.
    139     if (document.readyState != "loading") {
    140       onLoad();
    141     } else {
    142       this.addEventListener('DOMContentLoaded', onLoad);
    143     }
    144   })();
    145 </script>
    146 
    147 <style type="text/css" media="screen">
    148   .zoom {
    149     cursor: crosshair;
    150   }
    151 
    152   .zoomCanvas {
    153     position: absolute;
    154     width: vmin;
    155     height: vmin;
    156     top: 3em;
    157     right: 1em;
    158     z-index: -1;
    159   }
    160 
    161   #zoomCopy {
    162     display: none;
    163   }
    164 
    165   #zoomHex {
    166     text-shadow: 1px 1px #eee;
    167   }
    168 </style>
    169 
    170