OLD | NEW |
1 var MAX_SWAP_IMG_SIZE = 400; | 1 var MAX_SWAP_IMG_SIZE = 400; |
| 2 var MAGNIFIER_WIDTH = 200; |
| 3 var MAGNIFIER_HEIGHT = 200; |
| 4 var MAGNIFIER_HALF_WIDTH = MAGNIFIER_WIDTH * 0.5; |
| 5 var MAGNIFIER_HALF_HEIGHT = MAGNIFIER_HEIGHT * 0.5; |
| 6 // TODO add support for a magnified scale factor |
| 7 var MAGNIFIER_SCALE_FACTOR = 2.0; |
2 | 8 |
3 angular.module('diff_viewer', []). | 9 angular.module('diff_viewer', []). |
4 config(['$routeProvider', function($routeProvider) { | 10 directive('imgCompare', function() { |
5 // Show the list of differences by default | 11 // Custom directive for comparing (3-way) images |
6 $routeProvider. | 12 return { |
7 otherwise({ templateUrl: '/diff_list.html', controller: DiffListController})
; | 13 restrict: 'E', // The directive can be used as an element name |
8 }]). | 14 replace: true, // The directive replaces itself with the template |
9 directive('swapImg', function() { | 15 template: '<canvas/>', |
10 // Custom directive for showing an image that gets swapped my mouseover. | 16 scope: true, |
11 return { | 17 link: function(scope, elm, attrs, ctrl) { |
12 restrict: 'E', // The directive can be used as an element name | 18 var image = new Image(); |
13 replace: true, // The directive replaces itself with the template | 19 var canvas = elm[0]; |
14 template: '<canvas ng-mouseenter="swap()" ng-mouseleave="swap()"></canva
s>', | 20 var ctx = canvas.getContext('2d'); |
15 scope: { // The attributes below are bound to the scope | |
16 leftSrc: '@', | |
17 rightSrc: '@', | |
18 side: '@' | |
19 }, | |
20 link: function(scope, elm, attrs, ctrl) { | |
21 var leftImage = new Image(); | |
22 var rightImage = new Image(); | |
23 var ctx = elm[0].getContext('2d'); | |
24 | 21 |
25 scope.render = function() { | 22 var magnifyContent = false; |
26 var image; | |
27 if (scope.side == "left") { | |
28 image = leftImage; | |
29 } else { | |
30 image = rightImage; | |
31 } | |
32 | 23 |
33 // Make it so the maximum size of an image is MAX_SWAP_IMG_SIZE,
and the images are | 24 // When the type attribute changes, load the image and then render |
34 // scaled down in halves. | 25 attrs.$observe('type', function(value) { |
35 var divisor = 1; | 26 switch(value) { |
36 while ((image.width / divisor) > MAX_SWAP_IMG_SIZE) { | 27 case "alphaMask": |
37 divisor *= 2; | 28 image.src = scope.record.differencePath; |
38 } | 29 break; |
| 30 case "baseline": |
| 31 image.src = scope.record.baselinePath; |
| 32 magnifyContent = true; |
| 33 break; |
| 34 case "test": |
| 35 image.src = scope.record.testPath; |
| 36 magnifyContent = true; |
| 37 break; |
| 38 default: |
| 39 console.log("Unknown type attribute on <img-compare>: " + va
lue); |
| 40 return; |
| 41 } |
39 | 42 |
40 // Set canvas to correct size and draw the image into it | 43 image.onload = function() { |
41 elm[0].width = image.width / divisor; | 44 // compute the scaled image width/height for image and canvas |
42 elm[0].height = image.height / divisor; | 45 var divisor = 1; |
43 ctx.drawImage(image, 0, 0, elm[0].width, elm[0].height); | 46 // Make it so the maximum size of an image is MAX_SWAP_IMG_SIZ
E, |
| 47 // and the images are scaled down in halves. |
| 48 while ((image.width / divisor) > MAX_SWAP_IMG_SIZE) { |
| 49 divisor *= 2; |
| 50 } |
| 51 |
| 52 scope.setImgScaleFactor(1 / divisor); |
| 53 |
| 54 // Set canvas to correct size |
| 55 canvas.width = image.width * scope.imgScaleFactor; |
| 56 canvas.height = image.height * scope.imgScaleFactor; |
| 57 |
| 58 // render the image onto the canvas |
| 59 scope.renderImage(); |
| 60 } |
| 61 }); |
| 62 |
| 63 // When the magnify attribute changes, render the magnified rect at |
| 64 // the default zoom level. |
| 65 scope.$watch('magnifyCenter', function(magCenter) { |
| 66 if (!magnifyContent) { |
| 67 return; |
| 68 } |
| 69 |
| 70 scope.renderImage(); |
| 71 |
| 72 if (!magCenter) { |
| 73 return; |
| 74 } |
| 75 |
| 76 var magX = magCenter.x - MAGNIFIER_HALF_WIDTH; |
| 77 var magY = magCenter.y - MAGNIFIER_HALF_HEIGHT; |
| 78 |
| 79 var magMaxX = canvas.width - MAGNIFIER_WIDTH; |
| 80 var magMaxY = canvas.height - MAGNIFIER_HEIGHT; |
| 81 |
| 82 var magRect = { x: Math.max(0, Math.min(magX, magMaxX)), |
| 83 y: Math.max(0, Math.min(magY, magMaxY)), |
| 84 width: MAGNIFIER_WIDTH, |
| 85 height: MAGNIFIER_HEIGHT |
| 86 }; |
| 87 |
| 88 var imgRect = { x: (magCenter.x / scope.imgScaleFactor) - MAGNIFIE
R_HALF_WIDTH, |
| 89 y: (magCenter.y / scope.imgScaleFactor) - MAGNIFI
ER_HALF_HEIGHT, |
| 90 width: MAGNIFIER_WIDTH, |
| 91 height: MAGNIFIER_HEIGHT |
| 92 }; |
| 93 |
| 94 // draw the magnified image |
| 95 ctx.clearRect(magRect.x, magRect.y, magRect.width, magRect.height)
; |
| 96 ctx.drawImage(image, imgRect.x, imgRect.y, imgRect.width, imgRect.
height, |
| 97 magRect.x, magRect.y, magRect.width, magRect.height)
; |
| 98 |
| 99 // draw the outline rect |
| 100 ctx.beginPath(); |
| 101 ctx.rect(magRect.x, magRect.y, magRect.width, magRect.height); |
| 102 ctx.lineWidth = 2; |
| 103 ctx.strokeStyle = 'red'; |
| 104 ctx.stroke(); |
| 105 |
| 106 }); |
| 107 |
| 108 // render the image to the canvas. This is often done every frame prio
r |
| 109 // to any special effects (i.e. magnification). |
| 110 scope.renderImage = function() { |
| 111 ctx.clearRect(0, 0, canvas.width, canvas.height); |
| 112 ctx.drawImage(image, 0, 0, canvas.width, canvas.height); |
| 113 }; |
| 114 |
| 115 // compute a rect (x,y,width,height) that represents the bounding box
for |
| 116 // the magnification effect |
| 117 scope.computeMagnifierOutline = function(event) { |
| 118 var scaledWidth = MAGNIFIER_WIDTH * scope.imgScaleFactor; |
| 119 var scaledHeight = MAGNIFIER_HEIGHT * scope.imgScaleFactor; |
| 120 return { |
| 121 x: event.offsetX - (scaledWidth * 0.5), |
| 122 y: event.offsetY - (scaledHeight * 0.5), |
| 123 width: scaledWidth, |
| 124 height: scaledHeight |
44 }; | 125 }; |
| 126 }; |
45 | 127 |
46 // When the leftSrc attribute changes, load the image and then reren
der | 128 // event handler for mouse events that triggers the magnification |
47 attrs.$observe('leftSrc', function(value) { | 129 // effect across the 3 images being compared. |
48 leftImage.src = value; | 130 scope.MagnifyDraw = function(event, startMagnify) { |
49 leftImage.onload = function() { | 131 if (startMagnify) { |
50 if (scope.side == "left") { | 132 scope.setMagnifierState(true); |
51 scope.render(); | 133 } else if (!scope.magnifierOn) { |
52 } | 134 return; |
53 }; | 135 } |
54 }); | |
55 | 136 |
56 // When the rightSrc attribute changes, load the image and then rere
nder | 137 scope.renderImage(); |
57 attrs.$observe('rightSrc', function(value) { | |
58 rightImage.src = value; | |
59 rightImage.onload = function() { | |
60 if (scope.side == "right") { | |
61 scope.render(); | |
62 } | |
63 }; | |
64 }); | |
65 | 138 |
66 // Swap which side to draw onto the canvas and then rerender | 139 // render the magnifier outline rect |
67 scope.swap = function() { | 140 var rect = scope.computeMagnifierOutline(event); |
68 if (scope.side == "left") { | 141 ctx.save(); |
69 scope.side = "right"; | 142 ctx.beginPath(); |
70 } else { | 143 ctx.rect(rect.x, rect.y, rect.width, rect.height); |
71 scope.side = "left"; | 144 ctx.lineWidth = 2; |
72 } | 145 ctx.strokeStyle = 'red'; |
73 scope.render(); | 146 ctx.stroke(); |
74 }; | 147 ctx.restore(); |
75 } | 148 |
76 }; | 149 // update scope on baseline / test that will cause them to render |
| 150 scope.setMagnifyCenter({x: event.offsetX, y: event.offsetY}); |
| 151 }; |
| 152 |
| 153 // event handler that triggers the end of the magnification effect and |
| 154 // resets all the canvases to their original state. |
| 155 scope.MagnifyEnd = function(event) { |
| 156 scope.renderImage(); |
| 157 // update scope on baseline / test that will cause them to render |
| 158 scope.setMagnifierState(false); |
| 159 scope.setMagnifyCenter(undefined); |
| 160 }; |
| 161 } |
| 162 }; |
77 }); | 163 }); |
78 | 164 |
| 165 function ImageController($scope, $http, $location, $timeout, $parse) { |
| 166 $scope.imgScaleFactor = 1.0; |
| 167 $scope.magnifierOn = false; |
| 168 $scope.magnifyCenter = undefined; |
| 169 |
| 170 $scope.setImgScaleFactor = function(scaleFactor) { |
| 171 $scope.imgScaleFactor = scaleFactor; |
| 172 } |
| 173 |
| 174 $scope.setMagnifierState = function(magnifierOn) { |
| 175 $scope.magnifierOn = magnifierOn; |
| 176 } |
| 177 |
| 178 $scope.setMagnifyCenter = function(magnifyCenter) { |
| 179 $scope.magnifyCenter = magnifyCenter; |
| 180 } |
| 181 } |
| 182 |
79 function DiffListController($scope, $http, $location, $timeout, $parse) { | 183 function DiffListController($scope, $http, $location, $timeout, $parse) { |
80 // Detect if we are running the web server version of the viewer. If so, we
set a flag and | 184 // Detect if we are running the web server version of the viewer. If so, we
set a flag and |
81 // enable some extra functionality of the website for rebaselining. | 185 // enable some extra functionality of the website for rebaselining. |
82 $scope.isDynamic = ($location.protocol() == "http" || $location.protocol() =
= "https"); | 186 $scope.isDynamic = ($location.protocol() == "http" || $location.protocol() =
= "https"); |
83 | 187 |
84 // Label each kind of differ for the sort buttons. | 188 // Label each kind of differ for the sort buttons. |
85 $scope.differs = [ | 189 $scope.differs = [ |
86 { | 190 { |
87 "title": "Different Pixels" | 191 "title": "Different Pixels" |
88 }, | 192 }, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 } | 267 } |
164 $http.post("/commit_rebaselines", { | 268 $http.post("/commit_rebaselines", { |
165 "rebaselines": rebaselines | 269 "rebaselines": rebaselines |
166 }).success(function(data) { | 270 }).success(function(data) { |
167 $scope.flashStatus(data.success); | 271 $scope.flashStatus(data.success); |
168 }).error(function() { | 272 }).error(function() { |
169 $scope.flashStatus(false); | 273 $scope.flashStatus(false); |
170 }); | 274 }); |
171 }; | 275 }; |
172 } | 276 } |
OLD | NEW |