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 |