OLD | NEW |
(Empty) | |
| 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 zo
om. |
| 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 nul
l. |
| 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 p
oint. |
| 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 |
OLD | NEW |