maptastic 2.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
- maptastic
2
- =========
1
+ # maptastic
3
2
 
4
- Javascript/CSS projection mapping utility. Put your internets on things!
3
+ Javascript/CSS projection mapping utility with zero dependencies. Put your internets on things!
5
4
 
6
5
  ![maptastic animation](https://glowbox.github.io/maptasticjs/images/maptastic.gif "Maptastic JS")
7
6
 
@@ -9,49 +8,50 @@ __note__:
9
8
  The original author has been busy and non-responsive so this fork will serve as a way to keep the project updated.
10
9
  If the author reaches out to me, I will be more than happy to go back to the [original repo](https://github.com/glowbox/maptasticjs).
11
10
 
12
- ### Usage:
11
+ ## Usage
13
12
 
14
- When you include `maptastic.js` in your page, a new class `maptastic.Maptastic` is defined. The first step is to instantiate Maptastic, which can be done a couple of different ways depending on your needs. For most simple cases, this only requires a _single line of code_.
13
+ When you include `maptastic.js` in your page, a new class `maptastic.Maptastic` is defined. The first step is to instantiate Maptastic, which can be done a couple of different ways depending on your needs. For most simple cases, this only requires a _single line of code_.
15
14
 
16
15
  [SHOW ME THE DEMO](https://glowbox.github.io/maptasticjs/example/index.html)
16
+
17
17
  ```html
18
- <html>
19
- <head>
20
- <style>
21
- #so-simple {
22
- width: 300px;
23
- height: 300px;
24
- background: green;
25
- }
26
- </style>
27
- </head>
28
- <body>
29
-
30
- <div id="so-simple">This is pretty simple.</div>
31
-
32
- <!-- The only dependency is on `numeric`, which can be loaded from cdnjs -->
33
- <script src="https://cdnjs.cloudflare.com/ajax/libs/numeric/1.2.6/numeric.js"></script>
34
- <script src="./dist/maptastic.js"></script>
35
- <script>
36
- new maptastic.Maptastic("so-simple");
37
- </script>
38
-
39
- </body>
40
- </html>
18
+ <html>
19
+ <head>
20
+ <style>
21
+ #so-simple {
22
+ width: 300px;
23
+ height: 300px;
24
+ background: green;
25
+ }
26
+ </style>
27
+ </head>
28
+ <body>
29
+
30
+ <div id="so-simple">This is pretty simple.</div>
31
+
32
+ <script src="./dist/maptastic.js"></script>
33
+ <script>
34
+ new maptastic.Maptastic("so-simple");
35
+ </script>
36
+
37
+ </body>
38
+ </html>
41
39
  ```
42
40
 
43
41
  For more advanced needs, `Mapstastic` can also be imported as an ES2015 module.
42
+
44
43
  ```javascript
45
44
  import { Maptastic } from 'maptastic';
46
45
  const map = new Maptastic("so-simple");
47
46
  ```
48
47
 
49
48
  ## Controls
49
+
50
50
  Since the idea is to have a projector aimed all crazy-like, the controls are all keyboard and mouse based since any UI would either get in the way, or would be impossible to see in most cases anyway.
51
51
 
52
52
  `SHIFT` + `Space` Toggle edit mode
53
53
 
54
- #### While In Edit Mode
54
+ ### While In Edit Mode
55
55
 
56
56
  `click` or `drag` select and move quads/corner points
57
57
 
@@ -79,10 +79,9 @@ Since the idea is to have a projector aimed all crazy-like, the controls are all
79
79
 
80
80
  `'v'` Flip selected layer vertically
81
81
 
82
+ ## How about that code
82
83
 
83
- ## How about that code?
84
-
85
- ### Constructor:
84
+ ### Constructor
86
85
 
87
86
  The constructor can be used in two different ways depending on how you would like to integrate with Maptastic.
88
87
 
@@ -90,23 +89,26 @@ The constructor can be used in two different ways depending on how you would lik
90
89
 
91
90
  Specify a list of HTML elements, element IDs, or a mix of both. These elements will all be set up as Maptastic layers and will be configurable in edit mode.
92
91
 
93
- var element2 = document.getElementById("element-id2");
94
-
95
- Maptastic("element-id1", element2, ...);
92
+ ```javascript
93
+ const element2 = document.getElementById("element-id2");
96
94
 
95
+ new mapstastic.Maptastic("element-id1", element2, /* ... */);
96
+ ```
97
97
 
98
98
  #### Option 2 - Advanced Configuration
99
99
 
100
100
  For more advanced useage, specify a configuration object. Available configuration properties are defined below.
101
+
101
102
  ```javascript
102
- var configObject = {
103
- autoSave: false,
104
- autoLoad: false,
105
- onchange: myChangeHandler,
106
- layers: ["element-id1", "element-id2"]
107
- };
108
- var maptastic = Maptastic(configObject);
103
+ const configObject = {
104
+ autoSave: false,
105
+ autoLoad: false,
106
+ onchange: myChangeHandler,
107
+ layers: ["element-id1", "element-id2"]
108
+ };
109
+ const map = new mapstastic.Maptastic(configObject);
109
110
  ```
111
+
110
112
  ##### Configuration options
111
113
 
112
114
  `layers` Array, default *empty*. Identical to Option 1 above, an array of IDs or HTML elements to be used as Maptastic layers.
@@ -121,7 +123,6 @@ For more advanced useage, specify a configuration object. Available configuratio
121
123
 
122
124
  `autoLoad` boolean, default *true*. Control the automatic loading of layer positions from local storage.
123
125
 
124
-
125
126
  ### Methods
126
127
 
127
128
  In most cases, simply instantiating Maptastic with an element or two should be fine. However, if you are doing something more complicated, the Maptastic instance exposes several methods for controlling things at run time.
@@ -133,25 +134,26 @@ Returns an array of layer descriptor objects that represent the current mapping
133
134
  #### setLayout( _layoutData_ )
134
135
 
135
136
  Sets the current mapping layout. The schema must match that returned from `getLayout` and is as follows:
137
+
136
138
  ```javascript
137
- [
138
- {
139
- 'id': 'some-element-id',
140
- 'sourcePoints': [
141
- [x1, y1],
142
- [x2, y2],
143
- [x3, y3],
144
- [x4, y4]
145
- ],
146
- 'targetPoints': [
147
- [x1, y1],
148
- [x2, y2],
149
- [x3, y3],
150
- [x4, y4]
151
- ]
152
- },
153
- ...
154
- ]
139
+ [
140
+ {
141
+ 'id': 'some-element-id',
142
+ 'sourcePoints': [
143
+ [x1, y1],
144
+ [x2, y2],
145
+ [x3, y3],
146
+ [x4, y4]
147
+ ],
148
+ 'targetPoints': [
149
+ [x1, y1],
150
+ [x2, y2],
151
+ [x3, y3],
152
+ [x4, y4]
153
+ ]
154
+ },
155
+ // ...
156
+ ]
155
157
  ```
156
158
 
157
159
  #### addLayer( _target_, _coordinates_ )
@@ -162,9 +164,37 @@ Add a new HTML element to be mapped.
162
164
 
163
165
  `coordinates` optional. An array of four two-dimensional arrays specifying the corner points. This is the same structure as the `targetPoints` array used in `getLayout` and `setLayout`
164
166
 
167
+ #### removeLayer( _element_ )
168
+
169
+ Stops mapping an element previously added with `addLayer`. The element is left in the page; remove it yourself if you no longer need it.
165
170
 
166
171
  #### setConfigEnabled( _enabled_ )
167
172
 
168
173
  Sets the current Configuration Mode state.
169
174
 
170
175
  `enabled` boolean, required.
176
+
177
+ ## Development
178
+
179
+ ```bash
180
+ # Node 24+ (see devEngines in package.json)
181
+ npm ci
182
+ npm test # builds dist/ and runs the tests against it
183
+
184
+ # headless browser tests (Chromium, Firefox, WebKit) via Playwright
185
+ npx playwright install
186
+ npm run test:browser
187
+ ```
188
+
189
+ `dist/` is committed; CI fails if it doesn't match a fresh `npm run build`.
190
+
191
+ ### Releasing
192
+
193
+ Releases are staged to npm from GitHub Actions ([`publish.yml`](.github/workflows/publish.yml)) via
194
+ [trusted publishing](https://docs.npmjs.com/trusted-publishers), so no npm token is stored anywhere,
195
+ and go live only after a maintainer approves them ([staged publishing](https://docs.npmjs.com/staged-publishing)).
196
+
197
+ 1. Bump the version: `npm version <patch|minor|major>` (commits and creates the `vX.Y.Z` tag).
198
+ 2. Push the commit and tag: `git push --follow-tags`.
199
+ 3. Once the workflow finishes, approve the release with 2FA: `npm stage list maptastic`, then
200
+ `npm stage approve <stage-id>` (or use the Staged Packages tab on npmjs.com).
package/dist/maptastic.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("numeric")):"function"==typeof define&&define.amd?define(["exports","numeric"],e):e((t=t||self).maptastic={},t.numeric)}(this,function(t,B){"use strict";t.Maptastic=function(t){function e(t,e,i){return t&&t.hasOwnProperty(e)&&null!==t[e]?t[e]:i}function d(t,e,i,n){return Math.sqrt(Math.pow(i-t,2)+Math.pow(n-e,2))}function P(t,e,i,n){var o=e[1]*n[0]-e[0]*n[1]+(n[1]-e[1])*t[0]+(e[0]-n[0])*t[1],r=e[0]*i[1]-e[1]*i[0]+(e[1]-i[1])*t[0]+(i[0]-e[0])*t[1];if(o<0!=r<0)return!1;var s=-i[1]*n[0]+e[1]*(n[0]-i[0])+e[0]*(i[1]-n[1])+i[0]*n[1];return s<0&&(o=-o,r=-r,s=-s),0<o&&0<r&&o+r<s}function v(){o()}function y(){if(T){g.strokeStyle="red",g.lineWidth=2,g.clearRect(0,0,k.width,k.height);for(var t=0;t<x.length;t++)if(x[t].visible){x[t].element.style.visibility="visible",g.beginPath(),g.strokeStyle=x[t]===I?"red":x[t]===M?"red":"white",g.moveTo(x[t].targetPoints[0][0],x[t].targetPoints[0][1]);for(var e=0;e<x[t].targetPoints.length;e++)g.lineTo(x[t].targetPoints[e][0],x[t].targetPoints[e][1]);g.lineTo(x[t].targetPoints[3][0],x[t].targetPoints[3][1]),g.closePath(),g.stroke();var i=[0,0];for(e=0;e<x[t].targetPoints.length;e++)g.strokeStyle=x[t].targetPoints[e]===L?"red":x[t].targetPoints[e]===E?"red":"white",i[0]+=x[t].targetPoints[e][0],i[1]+=x[t].targetPoints[e][1],g.beginPath(),g.arc(x[t].targetPoints[e][0],x[t].targetPoints[e][1],10,0,2*Math.PI,!1),g.stroke();if(i[0]/=4,i[1]/=4,l){var n=x[t].element.id.toUpperCase();g.font="16px sans-serif",g.textAlign="center";var o=[g.measureText(n).width+8,32];g.fillStyle="white",g.fillRect(i[0]-o[0]/2,i[1]-o[1]+8,o[0],o[1]),g.fillStyle="black",g.fillText(n,i[0],i[1])}}else x[t].element.style.visibility="hidden";if(w&&(g.strokeStyle="yellow",g.lineWidth=1,g.beginPath(),g.moveTo(C[0],0),g.lineTo(C[0],k.height),g.moveTo(0,C[1]),g.lineTo(k.width,C[1]),g.stroke()),f){g.fillStyle="black",g.lineWidth=4,g.fillRect(0,0,k.width,k.height),g.strokeStyle="#909090",g.beginPath();var r=k.width/10,s=k.height/10;for(t=0;t<10;t++)g.moveTo(t*r,0),g.lineTo(t*r,k.height),g.moveTo(0,t*s),g.lineTo(k.width,t*s);g.stroke(),g.strokeStyle="white",g.strokeRect(2,2,k.width-4,k.height-4);var a=Math.round(.6*s);g.font=a+"px mono,sans-serif",g.fillRect(2*r+2,3*s+2,k.width-4*r-4,k.height-6*s-4),g.fillStyle="white",g.fontSize=20,g.fillText(k.width+" x "+k.height,k.width/2,k.height/2+.75*a),g.fillText("display size",k.width/2,k.height/2-.75*a)}}}function r(t,e,i){var n=t[e][0],o=t[e][1];t[e][0]=t[i][0],t[e][1]=t[i][1],t[i][0]=n,t[i][1]=o}function p(t,e){for(var i=Math.sin(e),n=Math.cos(e),o=[0,0],r=0;r<t.targetPoints.length;r++)o[0]+=t.targetPoints[r][0],o[1]+=t.targetPoints[r][1];for(o[0]/=4,o[1]/=4,r=0;r<t.targetPoints.length;r++){var s=t.targetPoints[r][0]-o[0],a=t.targetPoints[r][1]-o[1];t.targetPoints[r][0]=s*n-a*i+o[0],t.targetPoints[r][1]=s*i+a*n+o[1]}}function m(t,e){for(var i=[0,0],n=0;n<t.targetPoints.length;n++)i[0]+=t.targetPoints[n][0],i[1]+=t.targetPoints[n][1];for(i[0]/=4,i[1]/=4,n=0;n<t.targetPoints.length;n++){var o=t.targetPoints[n][1]-i[1];t.targetPoints[n][0]=(t.targetPoints[n][0]-i[0])*e+i[0],t.targetPoints[n][1]=o*e+i[1]}}function s(t,e){var i;if("string"==typeof t){if(!(i=document.getElementById(t)))throw"Maptastic: No element found with id: "+t}else t instanceof HTMLElement&&(i=t);for(var n=0;n<x.length;n++)x[n].element.id==i.id&&(x[n].targetPoints=j(layout[a].targetPoints));var o=i.offsetLeft,r=i.offsetTop;i.style.position="fixed",i.style.display="block",i.style.top="0px",i.style.left="0px",i.style.padding="0px",i.style.margin="0px";var s={visible:!0,element:i,width:i.clientWidth,height:i.clientHeight,sourcePoints:[],targetPoints:[]};if(s.sourcePoints.push([0,0],[s.width,0],[s.width,s.height],[0,s.height]),e)s.targetPoints=j(e);else{s.targetPoints.push([0,0],[s.width,0],[s.width,s.height],[0,s.height]);for(var a=0;a<s.targetPoints.length;a++)s.targetPoints[a][0]+=o,s.targetPoints[a][1]+=r}x.push(s),Y()}var l=e(t,"labels",!0),w=e(t,"crosshairs",!1),f=e(t,"screenbounds",!1),b=e(t,"autoSave",!0),i=e(t,"autoLoad",!0),n=e(t,"layers",[]),o=e(t,"onchange",function(){}),a="maptastic.layers",k=null,g=null,x=[],T=!1,S=!1,h=[],M=null,E=null,L=null,I=null,c=!1,C=[],K=[],u=[],z=function(t){if(!T)return 32==t.keyCode&&t.shiftKey?void O(!0):void 0;var e=t.shiftKey?10:1,i=!1,n=[0,0];switch(t.keyCode){case 32:if(t.shiftKey)return void O(!1);break;case 37:n[0]-=e;break;case 38:n[1]-=e;break;case 39:n[0]+=e;break;case 40:n[1]+=e;break;case 67:w=!w,i=!0;break;case 83:if(c){for(o=0;o<x.length;o++)x[o].visible=!0;i=!(c=!1)}else if(null!=M){for(var o=0;o<x.length;o++)x[o].visible=!1;c=i=M.visible=!0}break;case 66:f=!f,y();break;case 72:M&&(r(M.sourcePoints,0,1),r(M.sourcePoints,3,2),Y(),y());break;case 86:M&&(r(M.sourcePoints,0,3),r(M.sourcePoints,1,2),Y(),y());break;case 82:M&&(p(M,Math.PI/2),Y(),y())}if(!f)if(E)E[0]+=n[0],E[1]+=n[1],i=!0;else if(M){if(1==t.altKey)p(M,.01*n[0]),m(M,-.005*n[1]+1);else for(o=0;o<M.targetPoints.length;o++)M.targetPoints[o][0]+=n[0],M.targetPoints[o][1]+=n[1];i=!0}i&&(Y(),y(),b&&X(),v())},H=function(t){var e,i,n,o;if(T)if(t.preventDefault(),K[0]=t.clientX-C[0],K[1]=t.clientY-C[1],C[0]=t.clientX,C[1]=t.clientY,S){var r=t.shiftKey?.1:1;if(E)E[0]+=K[0]*r,E[1]+=K[1]*r;else if(M)if(1==t.altKey)p(M,K[0]*(.01*r)),m(M,K[1]*(-.005*r)+1);else for(var s=0;s<M.targetPoints.length;s++)M.targetPoints[s][0]+=K[0]*r,M.targetPoints[s][1]+=K[1]*r;Y(),b&&X(),y(),v()}else{k.style.cursor="default";var a=t.clientX,l=t.clientY,f=null!=L,g=null!=I;L=null;for(s=0;s<x.length;s++){var h=x[s];if(h.visible)for(var c=0;c<h.targetPoints.length;c++){var u=h.targetPoints[c];if(d(u[0],u[1],a,l)<20){k.style.cursor="pointer",L=u;break}}}I=null;for(s=0;s<x.length;s++)if(x[s].visible&&(void 0,n=P(e=C,(i=x[s]).targetPoints[0],i.targetPoints[1],i.targetPoints[2]),o=P(e,i.targetPoints[3],i.targetPoints[0],i.targetPoints[2]),n||o)){I=x[s];break}!w&&f==(null!=L)&&g==(null!=I)||y()}},R=function(t){T&&(t.preventDefault(),S=!1)},W=function(t){if(T&&!f){t.preventDefault(),L=null,I?(M=I,S=!0):M=null,E=null;var e=t.clientX,i=t.clientY;u[0]=e,u[1]=i;for(var n=0;n<x.length;n++)for(var o=x[n],r=0;r<o.targetPoints.length;r++){var s=o.targetPoints[r];if(d(s[0],s[1],e,i)<20){M=o,S=!0,h[0]=t.clientX-(E=s)[0],h[1]=t.clientY-s[1];break}}return y(),!1}},X=function(){localStorage.setItem(a,JSON.stringify(N()))},Y=function(){for(var t=["","-webkit-","-moz-","-ms-","-o-"].reduce(function(t,e){return e+"transform"in document.body.style?e:t})+"transform",e=0;e<x.length;e++){for(var i=[],n=[],o=0,r=x[e].sourcePoints.length;o<r;++o){var s=x[e].sourcePoints[o],a=x[e].targetPoints[o];i.push([s[0],s[1],1,0,0,0,-s[0]*a[0],-s[1]*a[0]]),n.push(a[0]),i.push([0,0,0,s[0],s[1],1,-s[0]*a[1],-s[1]*a[1]]),n.push(a[1])}var l=B.solve(i,n,!0);x[e].element.style[t]="matrix3d("+[l[0],l[3],0,l[6],l[1],l[4],0,l[7],0,0,1,0,l[2],l[5],0,1].join(",")+")",x[e].element.style[t+"-origin"]="0px 0px 0px"}},O=function(t){k.style.display=(T=t)?"block":"none",t?y():(M=E=null,f=S=!1)},j=function(t){for(var e=[],i=0;i<t.length;i++)e.push(t[i].slice(0,2));return e},D=function(){k.width=window.innerWidth,k.height=window.innerHeight,y()},N=function(){for(var t=[],e=0;e<x.length;e++)t.push({id:x[e].element.id,targetPoints:j(x[e].targetPoints),sourcePoints:j(x[e].sourcePoints)});return t};(k=document.createElement("canvas")).style.display="none",k.style.position="fixed",k.style.top="0px",k.style.left="0px",k.style.zIndex="1000000",g=k.getContext("2d"),document.body.appendChild(k),window.addEventListener("resize",D),window.addEventListener("mousemove",H),window.addEventListener("mouseup",R),window.addEventListener("mousedown",W),window.addEventListener("keydown",z),D();for(var q=0;q<n.length;q++)(n[q]instanceof HTMLElement||"string"==typeof n[q])&&s(n[q]);for(q=0;q<arguments.length;q++)(arguments[q]instanceof HTMLElement||"string"==typeof arguments[q])&&s(arguments[q]);return i&&function(){if(localStorage.getItem(a)){for(var t=JSON.parse(localStorage.getItem(a)),e=0;e<t.length;e++)for(var i=0;i<x.length;i++)x[i].element.id==t[e].id&&(x[i].targetPoints=j(t[e].targetPoints),x[i].sourcePoints=j(t[e].sourcePoints));Y()}}(),{getLayout:function(){return N()},setLayout:function(t){!function(t){for(var e=0;e<t.length;e++){for(var i=!1,n=0;n<x.length;n++)x[n].element.id==t[e].id&&(console.log("Setting points."),x[n].targetPoints=j(t[e].targetPoints),x[n].sourcePoints=j(t[e].sourcePoints),i=!0);if(i)console.log("Maptastic: Element '"+t[e].id+"' is already mapped.");else{var o=document.getElementById(t[e].id);o?s(o,t[e].targetPoints):console.log("Maptastic: Can't find element: "+t[e].id)}}Y(),y()}(t)},setConfigEnabled:function(t){O(t)},addLayer:function(t,e){s(t,e)}}},Object.defineProperty(t,"__esModule",{value:!0})});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).maptastic={})}(this,function(t){"use strict";function e(t,e,s){return e&&function(t,e){for(var s=0;e.length>s;s++){var n=e[s];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,i(n.key),n)}}(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t}function i(t){var e=function(t,e){if("object"!=typeof t||!t)return t;var i;if("undefined"!=typeof Symbol&&void 0!==(i=t[Symbol.toPrimitive])){var s=i.call(t,e);if("object"!=typeof s)return s;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t,"string");return"symbol"==typeof e?e:e+""}function s(t){return s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},s(t)}function n(t,e,i,s){if(i===e.length-1)return s(t);var o,r=e[i],a=Array(r);for(o=r-1;o>=0;o--)a[o]=n(t[o],e,i+1,s);return a}function o(t){var e;return"object"===s(t)?"object"===s(e=t[0])?"object"===s(e[0])?function(t){for(var e=[];"object"===s(t);)e.push(t.length),t=t[0];return e}(t):[t.length,e.length]:[t.length]:[]}function r(t){var e,i=t.length,s=Array(i);for(e=i-1;-1!==e;--e)s[e]=t[e];return s}function a(t){return"object"!==s(t)?t:n(t,o(t),0,r)}function h(t,e,i){return function(t,e){var i,s,n,o,r,h=t.LU,l=h.length,c=a(e),u=t.P;for(i=l-1;-1!==i;--i)c[i]=e[i];for(i=0;l>i;++i)for(n=u[i],u[i]!==i&&(r=c[i],c[i]=c[n],c[n]=r),o=h[i],s=0;i>s;++s)c[i]-=c[s]*o[s];for(i=l-1;i>=0;--i){for(o=h[i],s=i+1;l>s;++s)c[i]-=c[s]*o[s];c[i]/=o[i]}return c}(function(t){var e,i,s,n,o,r,h,l,c,u=arguments.length>1&&void 0!==arguments[1]&&arguments[1],y=Math.abs,f=t.length,d=f-1,g=new Array(f);for(u||(t=a(t)),s=0;f>s;++s){for(h=s,c=y((r=t[s])[s]),i=s+1;f>i;++i)(n=y(t[i][s]))>c&&(c=n,h=i);for(g[s]=h,h!=s&&(t[s]=t[h],t[h]=r,r=t[s]),o=r[s],e=s+1;f>e;++e)t[e][s]/=o;for(e=s+1;f>e;++e){for(l=t[e],i=s+1;d>i;++i)l[i]-=l[s]*r[i],l[++i]-=l[s]*r[i];i===d&&(l[i]-=l[s]*r[i])}}return{LU:t,P:g}}(t,i),e)}var l=Object.prototype.hasOwnProperty;function c(t,e,i){return t&&l.call(t,e)&&null!==t[e]?t[e]:i}function u(t,e,i,s){return Math.sqrt(Math.pow(i-t,2)+Math.pow(s-e,2))}function y(t,e,i,s){var n=e[1]*s[0]-e[0]*s[1]+(s[1]-e[1])*t[0]+(e[0]-s[0])*t[1],o=e[0]*i[1]-e[1]*i[0]+(e[1]-i[1])*t[0]+(i[0]-e[0])*t[1],r=-i[1]*s[0]+e[1]*(s[0]-i[0])+e[0]*(i[1]-s[1])+i[0]*s[1];return 0!=r&&(0>r&&(n=-n,o=-o,r=-r),n>=0&&o>=0&&r>=n+o)}function f(t,e,i){var s=t[e][0],n=t[e][1];t[e][0]=t[i][0],t[e][1]=t[i][1],t[i][0]=s,t[i][1]=n}function d(t,e){var i=y(t,e.targetPoints[0],e.targetPoints[1],e.targetPoints[2]),s=y(t,e.targetPoints[3],e.targetPoints[0],e.targetPoints[2]);return i||s}function g(t,e){for(var i=Math.sin(e),s=Math.cos(e),n=[0,0],o=0;t.targetPoints.length>o;o++)n[0]+=t.targetPoints[o][0],n[1]+=t.targetPoints[o][1];n[0]/=4,n[1]/=4;for(var r=0;t.targetPoints.length>r;r++){var a=t.targetPoints[r][0]-n[0],h=t.targetPoints[r][1]-n[1];t.targetPoints[r][0]=a*s-h*i+n[0],t.targetPoints[r][1]=a*i+h*s+n[1]}}function v(t,e){for(var i=[0,0],s=0;t.targetPoints.length>s;s++)i[0]+=t.targetPoints[s][0],i[1]+=t.targetPoints[s][1];i[0]/=4,i[1]/=4;for(var n=0;t.targetPoints.length>n;n++){var o=t.targetPoints[n][1]-i[1];t.targetPoints[n][0]=(t.targetPoints[n][0]-i[0])*e+i[0],t.targetPoints[n][1]=o*e+i[1]}}function P(t){for(var e=[],i=0;t.length>i;i++)e.push(t[i].slice(0,2));return e}var m=function(){return e(function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.canvas=null,this.context=null,this.layers=[],this.configActive=!1,this.dragging=!1,this.dragOffset=[0,0],this.selectedLayer=null,this.selectedPoint=null,this.selectionRadius=20,this.hoveringPoint=null,this.hoveringLayer=null,this.dragOperation="move",this.isLayerSoloed=!1,this.mousePosition=[0,0],this.mouseDelta=[0,0],this.mouseDownPoint=[],this.showLayerNames=c(e,"labels",!0),this.showCrosshairs=c(e,"crosshairs",!1),this.showScreenBounds=c(e,"screenbounds",!1),this.autoSave=c(e,"autoSave",!0),this.layoutChangeListener=c(e,"onchange",function(){}),this.localStorageKey="maptastic.layers";for(var i=c(e,"layers",[]),s=arguments.length,n=new Array(s>1?s-1:0),o=1;s>o;o++)n[o-1]=arguments[o];for(var r=i.concat(n,[e]),a=0;r.length>a;a++)(r[a]instanceof HTMLElement||"string"==typeof r[a])&&this.addLayer(r[a]);c(e,"autoLoad",!0)&&this.loadSettings(),this.init()},[{key:"init",value:function(){var t=this,e=document.createElement("canvas");e.style.display="none",e.style.position="fixed",e.style.top="0px",e.style.left="0px",e.style.zIndex="1000000",this.canvas=e,this.context=e.getContext("2d"),document.body.appendChild(e),window.addEventListener("resize",function(e){return t.resize()}),window.addEventListener("mousemove",function(e){return t.mouseMove(e)}),window.addEventListener("mouseup",function(e){return t.mouseUp(e)}),window.addEventListener("mousedown",function(e){return t.mouseDown(e)}),window.addEventListener("keydown",function(e){return t.keyDown(e)}),this.resize()}},{key:"notifyChangeListener",value:function(){this.layoutChangeListener()}},{key:"resize",value:function(){var t=window,e=t.innerHeight;this.canvas.width=t.innerWidth,this.canvas.height=e,this.draw()}},{key:"draw",value:function(){if(this.configActive){this.context.strokeStyle="red",this.context.lineWidth=2,this.context.clearRect(0,0,this.canvas.width,this.canvas.height);for(var t=0;this.layers.length>t;t++)if(this.layers[t].visible){this.layers[t].element.style.visibility="visible",this.context.beginPath(),this.context.strokeStyle=this.layers[t]===this.hoveringLayer||this.layers[t]===this.selectedLayer?"red":"white",this.context.moveTo(this.layers[t].targetPoints[0][0],this.layers[t].targetPoints[0][1]);for(var e=0;this.layers[t].targetPoints.length>e;e++)this.context.lineTo(this.layers[t].targetPoints[e][0],this.layers[t].targetPoints[e][1]);this.context.lineTo(this.layers[t].targetPoints[3][0],this.layers[t].targetPoints[3][1]),this.context.closePath(),this.context.stroke();for(var i=[0,0],s=0;this.layers[t].targetPoints.length>s;s++)this.context.strokeStyle=this.layers[t].targetPoints[s]===this.hoveringPoint||this.layers[t].targetPoints[s]===this.selectedPoint?"red":"white",i[0]+=this.layers[t].targetPoints[s][0],i[1]+=this.layers[t].targetPoints[s][1],this.context.beginPath(),this.context.arc(this.layers[t].targetPoints[s][0],this.layers[t].targetPoints[s][1],this.selectionRadius/2,0,2*Math.PI,!1),this.context.stroke();if(i[0]/=4,i[1]/=4,this.showLayerNames){var n=this.layers[t].element.id.toUpperCase();this.context.font="16px sans-serif",this.context.textAlign="center";var o=[this.context.measureText(n).width+8,32];this.context.fillStyle="white",this.context.fillRect(i[0]-o[0]/2,i[1]-o[1]+8,o[0],o[1]),this.context.fillStyle="black",this.context.fillText(n,i[0],i[1])}}else this.layers[t].element.style.visibility="hidden";if(this.showCrosshairs&&(this.context.strokeStyle="yellow",this.context.lineWidth=1,this.context.beginPath(),this.context.moveTo(this.mousePosition[0],0),this.context.lineTo(this.mousePosition[0],this.canvas.height),this.context.moveTo(0,this.mousePosition[1]),this.context.lineTo(this.canvas.width,this.mousePosition[1]),this.context.stroke()),this.showScreenBounds){this.context.fillStyle="black",this.context.lineWidth=4,this.context.fillRect(0,0,this.canvas.width,this.canvas.height),this.context.strokeStyle="#909090",this.context.beginPath();for(var r=this.canvas.width/10,a=this.canvas.height/10,h=0;10>h;h++)this.context.moveTo(h*r,0),this.context.lineTo(h*r,this.canvas.height),this.context.moveTo(0,h*a),this.context.lineTo(this.canvas.width,h*a);this.context.stroke(),this.context.strokeStyle="white",this.context.strokeRect(2,2,this.canvas.width-4,this.canvas.height-4);var l=Math.round(.6*a);this.context.font=l+"px mono,sans-serif",this.context.fillRect(2*r+2,3*a+2,this.canvas.width-4*r-4,this.canvas.height-6*a-4),this.context.fillStyle="white",this.context.fontSize=20,this.context.fillText(this.canvas.width+" x "+this.canvas.height,this.canvas.width/2,this.canvas.height/2+.75*l),this.context.fillText("display size",this.canvas.width/2,this.canvas.height/2-.75*l)}}}},{key:"updateTransform",value:function(){for(var t=["","-webkit-","-moz-","-ms-","-o-"].reduce(function(t,e){return e+"transform"in document.body.style?e:t})+"transform",e=0;this.layers.length>e;e++){for(var i=[],s=[],n=0,o=this.layers[e].sourcePoints.length;o>n;++n){var r=this.layers[e].sourcePoints[n],a=this.layers[e].targetPoints[n];i.push([r[0],r[1],1,0,0,0,-r[0]*a[0],-r[1]*a[0]]),s.push(a[0]),i.push([0,0,0,r[0],r[1],1,-r[0]*a[1],-r[1]*a[1]]),s.push(a[1])}var l=h(i,s,!0);this.layers[e].element.style[t]="matrix3d("+[l[0],l[3],0,l[6],l[1],l[4],0,l[7],0,0,1,0,l[2],l[5],0,1].join(",")+")",this.layers[e].element.style[t+"-origin"]="0px 0px 0px"}}},{key:"keyDown",value:function(t){if(!this.configActive)return 32==t.keyCode&&t.shiftKey?void this.setConfigEnabled(!0):void 0;if(!t.metaKey&&!t.ctrlKey){var e=t.shiftKey?10:1,i=!1,s=[0,0];switch(t.keyCode){case 32:if(t.shiftKey)return void this.setConfigEnabled(!1);break;case 37:s[0]-=e;break;case 38:s[1]-=e;break;case 39:s[0]+=e;break;case 40:s[1]+=e;break;case 67:this.showCrosshairs=!this.showCrosshairs,i=!0;break;case 83:if(this.isLayerSoloed){for(var n=0;this.layers.length>n;n++)this.layers[n].visible=!0;this.isLayerSoloed=!1,i=!0}else if(null!=this.selectedLayer){for(var o=0;this.layers.length>o;o++)this.layers[o].visible=!1;this.selectedLayer.visible=!0,i=!0,this.isLayerSoloed=!0}break;case 66:this.showScreenBounds=!this.showScreenBounds,this.draw();break;case 72:this.selectedLayer&&(f(this.selectedLayer.sourcePoints,0,1),f(this.selectedLayer.sourcePoints,3,2),this.updateTransform(),this.draw());break;case 86:this.selectedLayer&&(f(this.selectedLayer.sourcePoints,0,3),f(this.selectedLayer.sourcePoints,1,2),this.updateTransform(),this.draw());break;case 82:this.selectedLayer&&(g(this.selectedLayer,Math.PI/2),this.updateTransform(),this.draw())}if(!this.showScreenBounds)if(this.selectedPoint)this.selectedPoint[0]+=s[0],this.selectedPoint[1]+=s[1],i=!0;else if(this.selectedLayer){if(1==t.altKey)g(this.selectedLayer,.01*s[0]),v(this.selectedLayer,-.005*s[1]+1);else for(var r=0;this.selectedLayer.targetPoints.length>r;r++)this.selectedLayer.targetPoints[r][0]+=s[0],this.selectedLayer.targetPoints[r][1]+=s[1];i=!0}i&&(this.updateTransform(),this.draw(),this.autoSave&&this.saveSettings(),this.notifyChangeListener())}}},{key:"mouseMove",value:function(t){if(this.configActive)if(t.preventDefault(),this.mouseDelta[0]=t.clientX-this.mousePosition[0],this.mouseDelta[1]=t.clientY-this.mousePosition[1],this.mousePosition[0]=t.clientX,this.mousePosition[1]=t.clientY,this.dragging){var e=t.shiftKey?.1:1;if(this.selectedPoint)this.selectedPoint[0]+=this.mouseDelta[0]*e,this.selectedPoint[1]+=this.mouseDelta[1]*e;else if(this.selectedLayer)if(1==t.altKey)g(this.selectedLayer,this.mouseDelta[0]*(.01*e)),v(this.selectedLayer,this.mouseDelta[1]*(-.005*e)+1);else for(var i=0;this.selectedLayer.targetPoints.length>i;i++)this.selectedLayer.targetPoints[i][0]+=this.mouseDelta[0]*e,this.selectedLayer.targetPoints[i][1]+=this.mouseDelta[1]*e;this.updateTransform(),this.autoSave&&this.saveSettings(),this.draw(),this.notifyChangeListener()}else{this.canvas.style.cursor="default";var s=t.clientX,n=t.clientY,o=null!=this.hoveringPoint,r=null!=this.hoveringLayer;this.hoveringPoint=null;for(var a=0;this.layers.length>a;a++){var h=this.layers[a];if(h.visible)for(var l=0;h.targetPoints.length>l;l++){var c=h.targetPoints[l];if(u(c[0],c[1],s,n)<this.selectionRadius){this.canvas.style.cursor="pointer",this.hoveringPoint=c;break}}}this.hoveringLayer=null;for(var y=this.layers.length-1;y>=0;y--)if(this.layers[y].visible&&d(this.mousePosition,this.layers[y])){this.hoveringLayer=this.layers[y];break}(this.showCrosshairs||o!=(null!=this.hoveringPoint)||r!=(null!=this.hoveringLayer))&&this.draw()}}},{key:"mouseUp",value:function(t){this.configActive&&(t.preventDefault(),this.dragging=!1)}},{key:"mouseDown",value:function(t){if(this.configActive&&!this.showScreenBounds){t.preventDefault(),this.hoveringPoint=null,this.hoveringLayer?(this.selectedLayer=this.hoveringLayer,this.dragging=!0):this.selectedLayer=null,this.selectedPoint=null;var e=t.clientX,i=t.clientY;this.mouseDownPoint[0]=e,this.mouseDownPoint[1]=i;for(var s=0;this.layers.length>s;s++)for(var n=this.layers[s],o=0;n.targetPoints.length>o;o++){var r=n.targetPoints[o];if(u(r[0],r[1],e,i)<this.selectionRadius){this.selectedLayer=n,this.selectedPoint=r,this.dragging=!0,this.dragOffset[0]=t.clientX-r[0],this.dragOffset[1]=t.clientY-r[1];break}}return this.draw(),!1}}},{key:"addLayer",value:function(t,e){var i;if("string"==typeof t){if(!(i=document.getElementById(t)))throw new Error("Maptastic: No element found with id: "+t)}else t instanceof HTMLElement&&(i=t);for(var s=0;this.layers.length>s;s++)if(this.layers[s].element.id==i.id)throw new Error("Maptastic: Layer already added: "+i.id);var n=i.offsetLeft,o=i.offsetTop;i.style.position="fixed",i.style.display="block",i.style.top="0px",i.style.left="0px",i.style.padding="0px",i.style.margin="0px";var r={visible:!0,element:i,width:i.clientWidth,height:i.clientHeight,sourcePoints:[],targetPoints:[]};if(r.sourcePoints.push([0,0],[r.width,0],[r.width,r.height],[0,r.height]),e)r.targetPoints=P(e);else{r.targetPoints.push([0,0],[r.width,0],[r.width,r.height],[0,r.height]);for(var a=0;r.targetPoints.length>a;a++)r.targetPoints[a][0]+=n,r.targetPoints[a][1]+=o}this.layers.push(r),this.updateTransform()}},{key:"removeLayer",value:function(t){var e=this.layers.findIndex(function(e){return e.element===t});-1!==e&&(this.layers.splice(e,1),this.selectedLayer&&this.selectedLayer.element===t&&(this.selectedLayer=null,this.selectedPoint=null),this.hoveringLayer&&this.hoveringLayer.element===t&&(this.hoveringLayer=null),this.draw())}},{key:"saveSettings",value:function(){localStorage.setItem(this.localStorageKey,JSON.stringify(this.getLayout()))}},{key:"loadSettings",value:function(){if(localStorage.getItem(this.localStorageKey)){for(var t=JSON.parse(localStorage.getItem(this.localStorageKey)),e=0;t.length>e;e++)for(var i=0;this.layers.length>i;i++)this.layers[i].element.id==t[e].id&&(this.layers[i].targetPoints=P(t[e].targetPoints),this.layers[i].sourcePoints=P(t[e].sourcePoints));this.updateTransform()}}},{key:"setConfigEnabled",value:function(t){this.configActive=t,this.canvas.style.display=t?"block":"none",t?this.draw():(this.selectedPoint=null,this.selectedLayer=null,this.dragging=!1,this.showScreenBounds=!1)}},{key:"getLayout",value:function(){for(var t=[],e=0;this.layers.length>e;e++)t.push({id:this.layers[e].element.id,targetPoints:P(this.layers[e].targetPoints),sourcePoints:P(this.layers[e].sourcePoints)});return t}},{key:"setLayout",value:function(t){for(var e=0;t.length>e;e++){for(var i=!1,s=0;this.layers.length>s;s++)this.layers[s].element.id==t[e].id&&(console.log("Setting points."),this.layers[s].targetPoints=P(t[e].targetPoints),this.layers[s].sourcePoints=P(t[e].sourcePoints),i=!0);if(i)console.log("Maptastic: Element '"+t[e].id+"' is already mapped.");else{var n=document.getElementById(t[e].id);n?this.addLayer(n,t[e].targetPoints):console.log("Maptastic: Can't find element: "+t[e].id)}}this.updateTransform(),this.draw()}}])}();t.Maptastic=m});
2
2
  //# sourceMappingURL=maptastic.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"maptastic.js","sources":["../src/maptastic.js"],"sourcesContent":["import { solve } from 'numeric';\n\n\nfunction Maptastic(config) {\n\n var getProp = function (cfg, key, defaultVal) {\n if (cfg && cfg.hasOwnProperty(key) && (cfg[key] !== null)) {\n return cfg[key];\n } else {\n return defaultVal;\n }\n };\n\n var showLayerNames = getProp(config, 'labels', true);\n var showCrosshairs = getProp(config, 'crosshairs', false);\n var showScreenBounds = getProp(config, 'screenbounds', false);\n var autoSave = getProp(config, 'autoSave', true);\n var autoLoad = getProp(config, 'autoLoad', true);\n var layerList = getProp(config, 'layers', []);\n var layoutChangeListener = getProp(config, 'onchange', function () {\n });\n var localStorageKey = 'maptastic.layers';\n\n var canvas = null;\n var context = null;\n\n var layers = [];\n\n var configActive = false;\n\n var dragging = false;\n var dragOffset = [];\n\n var selectedLayer = null;\n var selectedPoint = null;\n var selectionRadius = 20;\n var hoveringPoint = null;\n var hoveringLayer = null;\n var dragOperation = 'move';\n var isLayerSoloed = false;\n\n var mousePosition = [];\n var mouseDelta = [];\n var mouseDownPoint = [];\n\n // Compute linear distance.\n var distanceTo = function (x1, y1, x2, y2) {\n return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));\n };\n\n var pointInTriangle = function (point, a, b, c) {\n var s = a[1] * c[0] - a[0] * c[1] + (c[1] - a[1]) * point[0] + (a[0] - c[0]) * point[1];\n var t = a[0] * b[1] - a[1] * b[0] + (a[1] - b[1]) * point[0] + (b[0] - a[0]) * point[1];\n\n if ((s < 0) != (t < 0)) {\n return false;\n }\n\n var A = -b[1] * c[0] + a[1] * (c[0] - b[0]) + a[0] * (b[1] - c[1]) + b[0] * c[1];\n if (A < 0.0) {\n s = -s;\n t = -t;\n A = -A;\n }\n\n return s > 0 && t > 0 && (s + t) < A;\n };\n\n // determine if a point is inside a layer quad.\n var pointInLayer = function (point, layer) {\n var a = pointInTriangle(point, layer.targetPoints[0], layer.targetPoints[1], layer.targetPoints[2]);\n var b = pointInTriangle(point, layer.targetPoints[3], layer.targetPoints[0], layer.targetPoints[2]);\n return a || b;\n };\n\n var notifyChangeListener = function () {\n layoutChangeListener();\n };\n\n var draw = function () {\n if (!configActive) {\n return;\n }\n\n context.strokeStyle = 'red';\n context.lineWidth = 2;\n context.clearRect(0, 0, canvas.width, canvas.height);\n\n for (var i = 0; i < layers.length; i++) {\n\n if (layers[i].visible) {\n layers[i].element.style.visibility = 'visible';\n\n // Draw layer rectangles.\n context.beginPath();\n if (layers[i] === hoveringLayer) {\n context.strokeStyle = 'red';\n } else if (layers[i] === selectedLayer) {\n context.strokeStyle = 'red';\n } else {\n context.strokeStyle = 'white';\n }\n context.moveTo(layers[i].targetPoints[0][0], layers[i].targetPoints[0][1]);\n for (var p = 0; p < layers[i].targetPoints.length; p++) {\n context.lineTo(layers[i].targetPoints[p][0], layers[i].targetPoints[p][1]);\n }\n context.lineTo(layers[i].targetPoints[3][0], layers[i].targetPoints[3][1]);\n context.closePath();\n context.stroke();\n\n // Draw corner points.\n var centerPoint = [0, 0];\n for (var p = 0; p < layers[i].targetPoints.length; p++) {\n\n if (layers[i].targetPoints[p] === hoveringPoint) {\n context.strokeStyle = 'red';\n } else if (layers[i].targetPoints[p] === selectedPoint) {\n context.strokeStyle = 'red';\n } else {\n context.strokeStyle = 'white';\n }\n\n centerPoint[0] += layers[i].targetPoints[p][0];\n centerPoint[1] += layers[i].targetPoints[p][1];\n\n context.beginPath();\n context.arc(layers[i].targetPoints[p][0], layers[i].targetPoints[p][1],\n selectionRadius / 2, 0, 2 * Math.PI, false);\n context.stroke();\n }\n\n // Find the average of the corner locations for an approximate center.\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n\n if (showLayerNames) {\n // Draw the element ID in the center of the quad for reference.\n var label = layers[i].element.id.toUpperCase();\n context.font = '16px sans-serif';\n context.textAlign = 'center';\n var metrics = context.measureText(label);\n var size = [metrics.width + 8, 16 + 16];\n context.fillStyle = 'white';\n context.fillRect(centerPoint[0] - size[0] / 2, centerPoint[1] - size[1] + 8, size[0], size[1]);\n context.fillStyle = 'black';\n context.fillText(label, centerPoint[0], centerPoint[1]);\n }\n } else {\n layers[i].element.style.visibility = 'hidden';\n }\n }\n\n // Draw mouse crosshairs\n if (showCrosshairs) {\n context.strokeStyle = 'yellow';\n context.lineWidth = 1;\n\n context.beginPath();\n\n context.moveTo(mousePosition[0], 0);\n context.lineTo(mousePosition[0], canvas.height);\n\n context.moveTo(0, mousePosition[1]);\n context.lineTo(canvas.width, mousePosition[1]);\n\n context.stroke();\n }\n\n if (showScreenBounds) {\n\n context.fillStyle = 'black';\n context.lineWidth = 4;\n context.fillRect(0, 0, canvas.width, canvas.height);\n\n context.strokeStyle = '#909090';\n context.beginPath();\n var stepX = canvas.width / 10;\n var stepY = canvas.height / 10;\n\n for (var i = 0; i < 10; i++) {\n context.moveTo(i * stepX, 0);\n context.lineTo(i * stepX, canvas.height);\n\n context.moveTo(0, i * stepY);\n context.lineTo(canvas.width, i * stepY);\n }\n context.stroke();\n\n context.strokeStyle = 'white';\n context.strokeRect(2, 2, canvas.width - 4, canvas.height - 4);\n\n var fontSize = Math.round(stepY * 0.6);\n context.font = fontSize + 'px mono,sans-serif';\n context.fillRect(stepX * 2 + 2, stepY * 3 + 2, canvas.width - stepX * 4 - 4, canvas.height - stepY * 6 - 4);\n context.fillStyle = 'white';\n context.fontSize = 20;\n context.fillText(canvas.width + ' x ' + canvas.height, canvas.width / 2, canvas.height / 2 + (fontSize * 0.75));\n context.fillText('display size', canvas.width / 2, canvas.height / 2 - (fontSize * 0.75));\n }\n };\n\n var swapLayerPoints = function (layerPoints, index1, index2) {\n var tx = layerPoints[index1][0];\n var ty = layerPoints[index1][1];\n layerPoints[index1][0] = layerPoints[index2][0];\n layerPoints[index1][1] = layerPoints[index2][1];\n layerPoints[index2][0] = tx;\n layerPoints[index2][1] = ty;\n };\n\n var init = function () {\n canvas = document.createElement('canvas');\n\n canvas.style.display = 'none';\n canvas.style.position = 'fixed';\n canvas.style.top = '0px';\n canvas.style.left = '0px';\n canvas.style.zIndex = '1000000';\n\n context = canvas.getContext('2d');\n\n document.body.appendChild(canvas);\n\n window.addEventListener('resize', resize);\n\n // UI events\n window.addEventListener('mousemove', mouseMove);\n window.addEventListener('mouseup', mouseUp);\n window.addEventListener('mousedown', mouseDown);\n window.addEventListener('keydown', keyDown);\n\n resize();\n };\n\n var rotateLayer = function (layer, angle) {\n var s = Math.sin(angle);\n var c = Math.cos(angle);\n\n var centerPoint = [0, 0];\n for (var p = 0; p < layer.targetPoints.length; p++) {\n centerPoint[0] += layer.targetPoints[p][0];\n centerPoint[1] += layer.targetPoints[p][1];\n }\n\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n for (var p = 0; p < layer.targetPoints.length; p++) {\n var px = layer.targetPoints[p][0] - centerPoint[0];\n var py = layer.targetPoints[p][1] - centerPoint[1];\n\n layer.targetPoints[p][0] = (px * c) - (py * s) + centerPoint[0];\n layer.targetPoints[p][1] = (px * s) + (py * c) + centerPoint[1];\n }\n };\n\n var scaleLayer = function (layer, scale) {\n\n var centerPoint = [0, 0];\n for (var p = 0; p < layer.targetPoints.length; p++) {\n centerPoint[0] += layer.targetPoints[p][0];\n centerPoint[1] += layer.targetPoints[p][1];\n }\n\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n for (var p = 0; p < layer.targetPoints.length; p++) {\n var px = layer.targetPoints[p][0] - centerPoint[0];\n var py = layer.targetPoints[p][1] - centerPoint[1];\n\n layer.targetPoints[p][0] = (px * scale) + centerPoint[0];\n layer.targetPoints[p][1] = (py * scale) + centerPoint[1];\n }\n };\n\n var keyDown = function (event) {\n if (!configActive) {\n if (event.keyCode == 32 && event.shiftKey) {\n setConfigEnabled(true);\n return;\n } else {\n return;\n }\n }\n\n var key = event.keyCode;\n\n var increment = event.shiftKey ? 10 : 1;\n var dirty = false;\n var delta = [0, 0];\n\n switch (key) {\n\n case 32: // spacebar\n if (event.shiftKey) {\n setConfigEnabled(false);\n return;\n }\n break;\n\n case 37: // left arrow\n delta[0] -= increment;\n break;\n\n case 38: // up arrow\n delta[1] -= increment;\n break;\n\n case 39: // right arrow\n delta[0] += increment;\n break;\n\n case 40: // down arrow\n delta[1] += increment;\n break;\n\n case 67: // c key, toggle crosshairs\n showCrosshairs = !showCrosshairs;\n dirty = true;\n break;\n\n case 83: // s key, solo/unsolo quads\n if (!isLayerSoloed) {\n\n if (selectedLayer != null) {\n for (var i = 0; i < layers.length; i++) {\n layers[i].visible = false;\n }\n selectedLayer.visible = true;\n dirty = true;\n isLayerSoloed = true;\n }\n } else {\n for (var i = 0; i < layers.length; i++) {\n layers[i].visible = true;\n }\n isLayerSoloed = false;\n dirty = true;\n\n }\n break;\n\n case 66: // b key, toggle projector bounds rectangle.\n showScreenBounds = !showScreenBounds;\n draw();\n break;\n\n case 72: // h key, flip horizontal.\n if (selectedLayer) {\n swapLayerPoints(selectedLayer.sourcePoints, 0, 1);\n swapLayerPoints(selectedLayer.sourcePoints, 3, 2);\n updateTransform();\n draw();\n }\n break;\n\n case 86: // v key, flip vertical.\n if (selectedLayer) {\n swapLayerPoints(selectedLayer.sourcePoints, 0, 3);\n swapLayerPoints(selectedLayer.sourcePoints, 1, 2);\n updateTransform();\n draw();\n }\n break;\n\n case 82: // r key, rotate 90 degrees.\n if (selectedLayer) {\n rotateLayer(selectedLayer, Math.PI / 2);\n //rotateLayer(selectedLayer, 0.002);\n updateTransform();\n draw();\n }\n break;\n }\n\n // if a layer or point is selected, add the delta amounts (set above via arrow keys)\n if (!showScreenBounds) {\n if (selectedPoint) {\n selectedPoint[0] += delta[0];\n selectedPoint[1] += delta[1];\n dirty = true;\n } else if (selectedLayer) {\n if (event.altKey == true) {\n rotateLayer(selectedLayer, delta[0] * 0.01);\n scaleLayer(selectedLayer, (delta[1] * -0.005) + 1.0);\n } else {\n for (var i = 0; i < selectedLayer.targetPoints.length; i++) {\n selectedLayer.targetPoints[i][0] += delta[0];\n selectedLayer.targetPoints[i][1] += delta[1];\n }\n }\n dirty = true;\n }\n }\n\n // update the transform and redraw if needed\n if (dirty) {\n updateTransform();\n draw();\n if (autoSave) {\n saveSettings();\n }\n notifyChangeListener();\n }\n };\n\n var mouseMove = function (event) {\n if (!configActive) {\n return;\n }\n\n event.preventDefault();\n\n mouseDelta[0] = event.clientX - mousePosition[0];\n mouseDelta[1] = event.clientY - mousePosition[1];\n\n mousePosition[0] = event.clientX;\n mousePosition[1] = event.clientY;\n\n if (dragging) {\n\n var scale = event.shiftKey ? 0.1 : 1;\n\n if (selectedPoint) {\n selectedPoint[0] += mouseDelta[0] * scale;\n selectedPoint[1] += mouseDelta[1] * scale;\n } else if (selectedLayer) {\n\n // Alt-drag to rotate and scale\n if (event.altKey == true) {\n rotateLayer(selectedLayer, mouseDelta[0] * (0.01 * scale));\n scaleLayer(selectedLayer, (mouseDelta[1] * (-0.005 * scale)) + 1.0);\n } else {\n for (var i = 0; i < selectedLayer.targetPoints.length; i++) {\n selectedLayer.targetPoints[i][0] += mouseDelta[0] * scale;\n selectedLayer.targetPoints[i][1] += mouseDelta[1] * scale;\n }\n }\n }\n\n updateTransform();\n if (autoSave) {\n saveSettings();\n }\n draw();\n notifyChangeListener();\n\n } else {\n var dirty = false;\n\n canvas.style.cursor = 'default';\n var mouseX = event.clientX;\n var mouseY = event.clientY;\n\n var previousState = (hoveringPoint != null);\n var previousLayer = (hoveringLayer != null);\n\n hoveringPoint = null;\n\n for (var i = 0; i < layers.length; i++) {\n var layer = layers[i];\n if (layer.visible) {\n for (var p = 0; p < layer.targetPoints.length; p++) {\n var point = layer.targetPoints[p];\n if (distanceTo(point[0], point[1], mouseX, mouseY) < selectionRadius) {\n canvas.style.cursor = 'pointer';\n hoveringPoint = point;\n break;\n }\n }\n }\n }\n\n hoveringLayer = null;\n for (var i = 0; i < layers.length; i++) {\n if (layers[i].visible && pointInLayer(mousePosition, layers[i])) {\n hoveringLayer = layers[i];\n break;\n }\n }\n\n if (showCrosshairs ||\n (previousState != (hoveringPoint != null)) ||\n (previousLayer != (hoveringLayer != null))\n ) {\n draw();\n }\n }\n };\n\n var mouseUp = function (event) {\n if (!configActive) {\n return;\n }\n event.preventDefault();\n\n dragging = false;\n };\n\n var mouseDown = function (event) {\n if (!configActive || showScreenBounds) {\n return;\n }\n event.preventDefault();\n\n hoveringPoint = null;\n\n if (hoveringLayer) {\n selectedLayer = hoveringLayer;\n dragging = true;\n } else {\n selectedLayer = null;\n }\n\n selectedPoint = null;\n\n var mouseX = event.clientX;\n var mouseY = event.clientY;\n\n mouseDownPoint[0] = mouseX;\n mouseDownPoint[1] = mouseY;\n\n for (var i = 0; i < layers.length; i++) {\n var layer = layers[i];\n for (var p = 0; p < layer.targetPoints.length; p++) {\n var point = layer.targetPoints[p];\n if (distanceTo(point[0], point[1], mouseX, mouseY) < selectionRadius) {\n selectedLayer = layer;\n selectedPoint = point;\n dragging = true;\n dragOffset[0] = event.clientX - point[0];\n dragOffset[1] = event.clientY - point[1];\n //draw();\n break;\n }\n }\n }\n draw();\n return false;\n };\n\n var addLayer = function (target, targetPoints) {\n\n var element;\n\n if (typeof (target) == 'string') {\n element = document.getElementById(target);\n if (!element) {\n throw('Maptastic: No element found with id: ' + target);\n }\n } else if (target instanceof HTMLElement) {\n element = target;\n }\n\n var exists = false;\n for (var n = 0; n < layers.length; n++) {\n if (layers[n].element.id == element.id) {\n layers[n].targetPoints = clonePoints(layout[i].targetPoints);\n exists = true;\n }\n }\n\n var offsetX = element.offsetLeft;\n var offsetY = element.offsetTop;\n\n element.style.position = 'fixed';\n element.style.display = 'block';\n element.style.top = '0px';\n element.style.left = '0px';\n element.style.padding = '0px';\n element.style.margin = '0px';\n\n var layer = {\n 'visible': true,\n 'element': element,\n 'width': element.clientWidth,\n 'height': element.clientHeight,\n 'sourcePoints': [],\n 'targetPoints': []\n };\n layer.sourcePoints.push([0, 0], [layer.width, 0], [layer.width, layer.height], [0, layer.height]);\n\n if (targetPoints) {\n layer.targetPoints = clonePoints(targetPoints);\n } else {\n layer.targetPoints.push([0, 0], [layer.width, 0], [layer.width, layer.height], [0, layer.height]);\n for (var i = 0; i < layer.targetPoints.length; i++) {\n layer.targetPoints[i][0] += offsetX;\n layer.targetPoints[i][1] += offsetY;\n }\n }\n\n layers.push(layer);\n\n updateTransform();\n };\n\n var saveSettings = function () {\n localStorage.setItem(localStorageKey, JSON.stringify(getLayout(layers)));\n };\n\n var loadSettings = function () {\n if (localStorage.getItem(localStorageKey)) {\n var data = JSON.parse(localStorage.getItem(localStorageKey));\n\n for (var i = 0; i < data.length; i++) {\n for (var n = 0; n < layers.length; n++) {\n if (layers[n].element.id == data[i].id) {\n layers[n].targetPoints = clonePoints(data[i].targetPoints);\n layers[n].sourcePoints = clonePoints(data[i].sourcePoints);\n }\n }\n }\n updateTransform();\n }\n };\n\n var updateTransform = function () {\n var transform = ['', '-webkit-', '-moz-', '-ms-', '-o-'].reduce(function (p, v) {\n return v + 'transform' in document.body.style ? v : p;\n }) + 'transform';\n for (var l = 0; l < layers.length; l++) {\n\n for (var a = [], b = [], i = 0, n = layers[l].sourcePoints.length; i < n; ++i) {\n var s = layers[l].sourcePoints[i], t = layers[l].targetPoints[i];\n a.push([s[0], s[1], 1, 0, 0, 0, -s[0] * t[0], -s[1] * t[0]]), b.push(t[0]);\n a.push([0, 0, 0, s[0], s[1], 1, -s[0] * t[1], -s[1] * t[1]]), b.push(t[1]);\n }\n\n var X = solve(a, b, true);\n var matrix = [\n X[0], X[3], 0, X[6],\n X[1], X[4], 0, X[7],\n 0, 0, 1, 0,\n X[2], X[5], 0, 1\n ];\n\n layers[l].element.style[transform] = 'matrix3d(' + matrix.join(',') + ')';\n layers[l].element.style[transform + '-origin'] = '0px 0px 0px';\n }\n };\n\n var setConfigEnabled = function (enabled) {\n configActive = enabled;\n canvas.style.display = enabled ? 'block' : 'none';\n\n if (!enabled) {\n selectedPoint = null;\n selectedLayer = null;\n dragging = false;\n showScreenBounds = false;\n } else {\n draw();\n }\n };\n\n var clonePoints = function (points) {\n var clone = [];\n for (var p = 0; p < points.length; p++) {\n clone.push(points[p].slice(0, 2));\n }\n return clone;\n };\n\n var resize = function () {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n draw();\n };\n\n var getLayout = function () {\n var layout = [];\n for (var i = 0; i < layers.length; i++) {\n layout.push({\n 'id': layers[i].element.id,\n 'targetPoints': clonePoints(layers[i].targetPoints),\n 'sourcePoints': clonePoints(layers[i].sourcePoints)\n });\n }\n return layout;\n };\n\n var setLayout = function (layout) {\n for (var i = 0; i < layout.length; i++) {\n var exists = false;\n for (var n = 0; n < layers.length; n++) {\n if (layers[n].element.id == layout[i].id) {\n console.log('Setting points.');\n layers[n].targetPoints = clonePoints(layout[i].targetPoints);\n layers[n].sourcePoints = clonePoints(layout[i].sourcePoints);\n exists = true;\n }\n }\n\n if (!exists) {\n var element = document.getElementById(layout[i].id);\n if (element) {\n addLayer(element, layout[i].targetPoints);\n } else {\n console.log('Maptastic: Can\\'t find element: ' + layout[i].id);\n }\n } else {\n console.log('Maptastic: Element \\'' + layout[i].id + '\\' is already mapped.');\n }\n }\n updateTransform();\n draw();\n };\n\n init();\n\n // if the config was just an element or string, interpret it as a layer to add.\n\n for (var i = 0; i < layerList.length; i++) {\n if ((layerList[i] instanceof HTMLElement) || (typeof (layerList[i]) === 'string')) {\n addLayer(layerList[i]);\n }\n }\n\n for (var i = 0; i < arguments.length; i++) {\n if ((arguments[i] instanceof HTMLElement) || (typeof (arguments[i]) === 'string')) {\n addLayer(arguments[i]);\n }\n }\n\n if (autoLoad) {\n loadSettings();\n }\n\n return {\n 'getLayout': function () {\n return getLayout();\n },\n 'setLayout': function (layout) {\n setLayout(layout);\n },\n 'setConfigEnabled': function (enabled) {\n setConfigEnabled(enabled);\n },\n 'addLayer': function (target, targetPoints) {\n addLayer(target, targetPoints);\n }\n };\n}\n\nexport { Maptastic };\n"],"names":["config","getProp","cfg","key","defaultVal","hasOwnProperty","distanceTo","x1","y1","x2","y2","Math","sqrt","pow","pointInTriangle","point","a","b","c","s","t","A","notifyChangeListener","layoutChangeListener","draw","configActive","context","strokeStyle","lineWidth","clearRect","canvas","width","height","i","layers","length","visible","element","style","visibility","beginPath","hoveringLayer","selectedLayer","moveTo","targetPoints","p","lineTo","closePath","stroke","centerPoint","hoveringPoint","selectedPoint","arc","selectionRadius","PI","showLayerNames","label","id","toUpperCase","font","textAlign","size","measureText","fillStyle","fillRect","fillText","showCrosshairs","mousePosition","showScreenBounds","stepX","stepY","strokeRect","fontSize","round","swapLayerPoints","layerPoints","index1","index2","tx","ty","rotateLayer","layer","angle","sin","cos","px","py","scaleLayer","scale","addLayer","target","document","getElementById","HTMLElement","n","clonePoints","layout","offsetX","offsetLeft","offsetY","offsetTop","position","display","top","left","padding","margin","clientWidth","clientHeight","sourcePoints","push","updateTransform","autoSave","autoLoad","layerList","localStorageKey","dragging","dragOffset","isLayerSoloed","mouseDelta","mouseDownPoint","keyDown","event","keyCode","shiftKey","setConfigEnabled","increment","dirty","delta","altKey","saveSettings","mouseMove","preventDefault","clientX","clientY","cursor","mouseX","mouseY","previousState","previousLayer","mouseUp","mouseDown","localStorage","setItem","JSON","stringify","getLayout","transform","reduce","v","body","l","X","solve","join","enabled","points","clone","slice","resize","window","innerWidth","innerHeight","createElement","zIndex","getContext","appendChild","addEventListener","arguments","getItem","data","parse","loadSettings","exists","console","log","setLayout"],"mappings":"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"}
1
+ {"version":3,"file":"maptastic.js","sources":["../src/solve.js","../src/maptastic.js"],"sourcesContent":["/**\n * @fileoverview A snippet from the {@link https://github.com/sloisel/numeric | numeric} project, as it is unmaintained and doesn't export correctly.\n * @see {@link https://github.com/sloisel/numeric/blob/656fa1254be540f428710738ca9c1539625777f1/src/numeric.js#L3001-L3089 | Source}\n */\n\n/**\n * @see {@link https://github.com/sloisel/numeric/blob/master/src/numeric.js#L315-L329}\n */\nfunction _foreach2(x, s, k, f) {\n if (k === s.length - 1) {\n return f(x);\n }\n var i, n = s[k], ret = Array(n);\n for (i = n - 1; i >= 0; i--) {\n ret[i] = _foreach2(x[i], s, k + 1, f);\n }\n return ret;\n}\n\n\nfunction _dim(x) {\n var ret = [];\n while (typeof x === \"object\") {\n ret.push(x.length);\n x = x[0];\n }\n return ret;\n}\n\n/**\n * @see {@link https://github.com/sloisel/numeric/blob/656fa1254be540f428710738ca9c1539625777f1/src/numeric.js#L309-L329}\n * @param {*} x \n */\nfunction dim(x) {\n var y, z;\n if (typeof x === \"object\") {\n y = x[0];\n if (typeof y === \"object\") {\n z = y[0];\n if (typeof z === \"object\") {\n return _dim(x);\n }\n return [x.length, y.length];\n }\n return [x.length];\n }\n return [];\n}\n\n\nfunction cloneV(x) {\n var _n = x.length;\n var i, ret = Array(_n);\n\n for (i = _n - 1; i !== -1; --i) {\n ret[i] = (x[i]);\n }\n return ret;\n}\n\nfunction clone(x) {\n if (typeof x !== \"object\") {\n return (x);\n }\n var s = dim(x);\n return _foreach2(x, s, 0, cloneV);\n}\n\n// 11. Ax = b\n/**\n * @param {*} A \n * @param {boolean} [fast=false] \n * @returns {{ LU: *, P: * }}\n */\nfunction LU(A, fast = false) {\n var abs = Math.abs;\n var i, j, k, absAjk, Akk, Ak, Pk, Ai;\n var max;\n var n = A.length, n1 = n - 1;\n var P = new Array(n);\n if (!fast) {\n A = clone(A);\n }\n \n for (k = 0; k < n; ++k) {\n Pk = k;\n Ak = A[k];\n max = abs(Ak[k]);\n for (j = k + 1; j < n; ++j) {\n absAjk = abs(A[j][k]);\n if (max < absAjk) {\n max = absAjk;\n Pk = j;\n }\n }\n P[k] = Pk;\n\n if (Pk != k) {\n A[k] = A[Pk];\n A[Pk] = Ak;\n Ak = A[k];\n }\n\n Akk = Ak[k];\n\n for (i = k + 1; i < n; ++i) {\n A[i][k] /= Akk;\n }\n\n for (i = k + 1; i < n; ++i) {\n Ai = A[i];\n for (j = k + 1; j < n1; ++j) {\n Ai[j] -= Ai[k] * Ak[j];\n ++j;\n Ai[j] -= Ai[k] * Ak[j];\n }\n if (j === n1) Ai[j] -= Ai[k] * Ak[j];\n }\n }\n\n return {\n LU: A,\n P: P\n };\n}\n\nfunction LUsolve(LUP, b) {\n var i, j;\n var LU = LUP.LU;\n var n = LU.length;\n var x = clone(b);\n var P = LUP.P;\n var Pi, LUi, tmp;\n\n for (i = n - 1; i !== -1; --i) x[i] = b[i];\n for (i = 0; i < n; ++i) {\n Pi = P[i];\n if (P[i] !== i) {\n tmp = x[i];\n x[i] = x[Pi];\n x[Pi] = tmp;\n }\n\n LUi = LU[i];\n for (j = 0; j < i; ++j) {\n x[i] -= x[j] * LUi[j];\n }\n }\n\n for (i = n - 1; i >= 0; --i) {\n LUi = LU[i];\n for (j = i + 1; j < n; ++j) {\n x[i] -= x[j] * LUi[j];\n }\n\n x[i] /= LUi[i];\n }\n\n return x;\n}\n\nexport default function solve(A, b, fast) {\n return LUsolve(LU(A, fast), b);\n}","import solve from './solve';\n\n/**\n * @typedef {Object} Config\n * @property {boolean} labels\n * @property {boolean} crosshairs\n * @property {boolean} screenbounds\n * @property {boolean} autoSave\n * @property {Layout[]} layers\n * @property {function(): void} onchange\n */\n\n/**\n * @typedef {(string|HTMLElement)} Target\n */\n\n/**\n * @typedef {[number, number]} Point\n */\n\n/**\n * @typedef {Object} Layout\n * @property {string} id - ID of the layer element\n * @property {Point[]} targetPoints\n * @property {Point[]} sourcePoints\n */\n\n/**\n * @typedef {Object} Layer\n * @property {Point[]} targetPoints\n * @property {Point[]} sourcePoints\n * @property {boolean} visible\n * @property {HTMLElement} element\n * @property {number} width\n * @property {number} height \n */\n\nconst has = Object.prototype.hasOwnProperty;\n\n/**\n * Get an object's property or a default if not defined.\n *\n * @template T\n * @param {*} obj \n * @param {string} key \n * @param {T} defaultVal \n * @returns {T | *} either the default value or the object's property\n */\nfunction getProp(obj, key, defaultVal) {\n if (obj && has.call(obj, key) && (obj[key] !== null)) {\n return obj[key];\n } else {\n return defaultVal;\n }\n}\n\n\n/**\n * Compute linear distance.\n *\n * @param {number} x1 \n * @param {number} y1 \n * @param {number} x2 \n * @param {number} y2 \n * @returns {number}\n */\nfunction distanceTo(x1, y1, x2, y2) {\n return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));\n}\n\n/**\n * Determine whether a {@link Point} falls within a triangle, edges included.\n *\n * @param {Point} point\n * @param {Point} a\n * @param {Point} b\n * @param {Point} c\n * @returns {boolean}\n */\nfunction pointInTriangle(point, a, b, c) {\n let s = a[1] * c[0] - a[0] * c[1] + (c[1] - a[1]) * point[0] + (a[0] - c[0]) * point[1];\n let t = a[0] * b[1] - a[1] * b[0] + (a[1] - b[1]) * point[0] + (b[0] - a[0]) * point[1];\n let A = -b[1] * c[0] + a[1] * (c[0] - b[0]) + a[0] * (b[1] - c[1]) + b[0] * c[1];\n\n if (A == 0) {\n return false; // degenerate triangle\n }\n\n // normalize the winding so the bounds below hold for either orientation\n if (A < 0) {\n s = -s;\n t = -t;\n A = -A;\n }\n\n // inclusive, so the diagonal shared by a layer's two triangles counts as inside\n return s >= 0 && t >= 0 && (s + t) <= A;\n}\n\n/**\n * Swap two points in a given list of points. Mutates `layerPoints`.\n *\n * @param {Point[]} layerPoints \n * @param {number} index1 \n * @param {number} index2 \n */\nfunction swapLayerPoints(layerPoints, index1, index2) {\n const tx = layerPoints[index1][0];\n const ty = layerPoints[index1][1];\n layerPoints[index1][0] = layerPoints[index2][0];\n layerPoints[index1][1] = layerPoints[index2][1];\n layerPoints[index2][0] = tx;\n layerPoints[index2][1] = ty;\n}\n\n/**\n * Determine if a point is inside a layer quad.\n * \n * @param {Point} point \n * @param {Layer} layer \n */\nfunction pointInLayer(point, layer) {\n const a = pointInTriangle(point, layer.targetPoints[0], layer.targetPoints[1], layer.targetPoints[2]);\n const b = pointInTriangle(point, layer.targetPoints[3], layer.targetPoints[0], layer.targetPoints[2]);\n return a || b;\n}\n\n/**\n * Rotate a {@link Layout}. Mutates `layer`.\n *\n * @param {Layer} layer \n * @param {number} angle \n */\nfunction rotateLayer(layer, angle) {\n const s = Math.sin(angle);\n const c = Math.cos(angle);\n\n const centerPoint = [0, 0];\n for (let p = 0; p < layer.targetPoints.length; p++) {\n centerPoint[0] += layer.targetPoints[p][0];\n centerPoint[1] += layer.targetPoints[p][1];\n }\n\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n for (let p = 0; p < layer.targetPoints.length; p++) {\n const px = layer.targetPoints[p][0] - centerPoint[0];\n const py = layer.targetPoints[p][1] - centerPoint[1];\n\n layer.targetPoints[p][0] = (px * c) - (py * s) + centerPoint[0];\n layer.targetPoints[p][1] = (px * s) + (py * c) + centerPoint[1];\n }\n}\n\n/**\n * Scale a {@link Layer}. Mutates `layer`.\n * \n * @param {Layer} layer \n * @param {number} scale \n */\nfunction scaleLayer(layer, scale) {\n const centerPoint = [0, 0];\n for (let p = 0; p < layer.targetPoints.length; p++) {\n centerPoint[0] += layer.targetPoints[p][0];\n centerPoint[1] += layer.targetPoints[p][1];\n }\n\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n for (let p = 0; p < layer.targetPoints.length; p++) {\n let px = layer.targetPoints[p][0] - centerPoint[0];\n let py = layer.targetPoints[p][1] - centerPoint[1];\n\n layer.targetPoints[p][0] = (px * scale) + centerPoint[0];\n layer.targetPoints[p][1] = (py * scale) + centerPoint[1];\n }\n}\n\n/**\n * Clone a list of points.\n * \n * @param {Point[]} points \n * @returns {Point[]} a new list.\n */\nfunction clonePoints(points) {\n const clone = [];\n for (let p = 0; p < points.length; p++) {\n clone.push(points[p].slice(0, 2));\n }\n return clone;\n}\n\nclass Maptastic {\n /**\n * @param {Config|Target} configOrTarget\n * @param {...Target} [targets]\n */\n constructor(configOrTarget, ...targets) {\n /** @type {HTMLCanvasElement} */\n this.canvas = null;\n /** @type {CanvasRenderingContext2D} */\n this.context = null;\n\n /** @type {Layer[]} */\n this.layers = [];\n\n this.configActive = false;\n\n this.dragging = false;\n /** @type {Point} */\n this.dragOffset = [0, 0];\n\n this.selectedLayer = null;\n this.selectedPoint = null;\n this.selectionRadius = 20;\n this.hoveringPoint = null;\n this.hoveringLayer = null;\n this.dragOperation = 'move';\n this.isLayerSoloed = false;\n\n /** @type {Point} */\n this.mousePosition = [0, 0];\n /** @type {Point} */\n this.mouseDelta = [0, 0];\n /** @type {Point} */\n this.mouseDownPoint = [];\n\n this.showLayerNames = getProp(configOrTarget, 'labels', true);\n this.showCrosshairs = getProp(configOrTarget, 'crosshairs', false);\n this.showScreenBounds = getProp(configOrTarget, 'screenbounds', false);\n this.autoSave = getProp(configOrTarget, 'autoSave', true);\n this.layoutChangeListener = getProp(configOrTarget, 'onchange', () => { });\n this.localStorageKey = 'maptastic.layers';\n\n const layerList = getProp(configOrTarget, 'layers', []);\n // if the config was just an element or string, interpret it as a layer to add.\n const potentialLayerTargets = layerList.concat(targets, [configOrTarget]);\n\n for (var i = 0; i < potentialLayerTargets.length; i++) {\n if ((potentialLayerTargets[i] instanceof HTMLElement) || (typeof (potentialLayerTargets[i]) === 'string')) {\n this.addLayer(potentialLayerTargets[i]);\n }\n }\n\n const autoLoad = getProp(configOrTarget, 'autoLoad', true);\n if (autoLoad) {\n this.loadSettings();\n }\n\n this.init();\n }\n\n /**\n * Set up event listeners, canvas, and context.\n * \n * @private\n */\n init() {\n const canvas = document.createElement('canvas');\n\n canvas.style.display = 'none';\n canvas.style.position = 'fixed';\n canvas.style.top = '0px';\n canvas.style.left = '0px';\n canvas.style.zIndex = '1000000';\n this.canvas = canvas;\n\n this.context = canvas.getContext('2d');\n\n document.body.appendChild(canvas);\n\n window.addEventListener('resize', (event) => this.resize());\n\n // UI events\n window.addEventListener('mousemove', (event) => this.mouseMove(event));\n window.addEventListener('mouseup', (event) => this.mouseUp(event));\n window.addEventListener('mousedown', (event) => this.mouseDown(event));\n window.addEventListener('keydown', (event) => this.keyDown(event));\n\n this.resize();\n }\n\n /**\n * @private\n */\n notifyChangeListener() {\n this.layoutChangeListener();\n }\n\n /**\n * @private\n */\n resize() {\n const { innerWidth, innerHeight } = window;\n this.canvas.width = innerWidth;\n this.canvas.height = innerHeight;\n\n this.draw();\n }\n\n /**\n * @private\n */\n draw() {\n if (!this.configActive) {\n return;\n }\n\n this.context.strokeStyle = 'red';\n this.context.lineWidth = 2;\n this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\n for (let i = 0; i < this.layers.length; i++) {\n\n if (this.layers[i].visible) {\n this.layers[i].element.style.visibility = 'visible';\n\n // Draw layer rectangles.\n this.context.beginPath();\n if (this.layers[i] === this.hoveringLayer) {\n this.context.strokeStyle = 'red';\n } else if (this.layers[i] === this.selectedLayer) {\n this.context.strokeStyle = 'red';\n } else {\n this.context.strokeStyle = 'white';\n }\n this.context.moveTo(this.layers[i].targetPoints[0][0], this.layers[i].targetPoints[0][1]);\n for (let p = 0; p < this.layers[i].targetPoints.length; p++) {\n this.context.lineTo(this.layers[i].targetPoints[p][0], this.layers[i].targetPoints[p][1]);\n }\n this.context.lineTo(this.layers[i].targetPoints[3][0], this.layers[i].targetPoints[3][1]);\n this.context.closePath();\n this.context.stroke();\n\n // Draw corner points.\n const centerPoint = [0, 0];\n for (let p = 0; p < this.layers[i].targetPoints.length; p++) {\n\n if (this.layers[i].targetPoints[p] === this.hoveringPoint) {\n this.context.strokeStyle = 'red';\n } else if (this.layers[i].targetPoints[p] === this.selectedPoint) {\n this.context.strokeStyle = 'red';\n } else {\n this.context.strokeStyle = 'white';\n }\n\n centerPoint[0] += this.layers[i].targetPoints[p][0];\n centerPoint[1] += this.layers[i].targetPoints[p][1];\n\n this.context.beginPath();\n this.context.arc(\n this.layers[i].targetPoints[p][0],\n this.layers[i].targetPoints[p][1],\n this.selectionRadius / 2,\n 0,\n 2 * Math.PI,\n false\n );\n this.context.stroke();\n }\n\n // Find the average of the corner locations for an approximate center.\n centerPoint[0] /= 4;\n centerPoint[1] /= 4;\n\n if (this.showLayerNames) {\n // Draw the element ID in the center of the quad for reference.\n const label = this.layers[i].element.id.toUpperCase();\n this.context.font = '16px sans-serif';\n this.context.textAlign = 'center';\n const metrics = this.context.measureText(label);\n const size = [metrics.width + 8, 16 + 16];\n this.context.fillStyle = 'white';\n this.context.fillRect(centerPoint[0] - size[0] / 2, centerPoint[1] - size[1] + 8, size[0], size[1]);\n this.context.fillStyle = 'black';\n this.context.fillText(label, centerPoint[0], centerPoint[1]);\n }\n } else {\n this.layers[i].element.style.visibility = 'hidden';\n }\n }\n\n // Draw mouse crosshairs\n if (this.showCrosshairs) {\n this.context.strokeStyle = 'yellow';\n this.context.lineWidth = 1;\n\n this.context.beginPath();\n\n this.context.moveTo(this.mousePosition[0], 0);\n this.context.lineTo(this.mousePosition[0], this.canvas.height);\n\n this.context.moveTo(0, this.mousePosition[1]);\n this.context.lineTo(this.canvas.width, this.mousePosition[1]);\n\n this.context.stroke();\n }\n\n if (this.showScreenBounds) {\n\n this.context.fillStyle = 'black';\n this.context.lineWidth = 4;\n this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\n this.context.strokeStyle = '#909090';\n this.context.beginPath();\n const stepX = this.canvas.width / 10;\n const stepY = this.canvas.height / 10;\n\n for (let i = 0; i < 10; i++) {\n this.context.moveTo(i * stepX, 0);\n this.context.lineTo(i * stepX, this.canvas.height);\n\n this.context.moveTo(0, i * stepY);\n this.context.lineTo(this.canvas.width, i * stepY);\n }\n this.context.stroke();\n\n this.context.strokeStyle = 'white';\n this.context.strokeRect(2, 2, this.canvas.width - 4, this.canvas.height - 4);\n\n const fontSize = Math.round(stepY * 0.6);\n this.context.font = fontSize + 'px mono,sans-serif';\n this.context.fillRect(stepX * 2 + 2, stepY * 3 + 2, this.canvas.width - stepX * 4 - 4, this.canvas.height - stepY * 6 - 4);\n this.context.fillStyle = 'white';\n this.context.fontSize = 20;\n this.context.fillText(this.canvas.width + ' x ' + this.canvas.height, this.canvas.width / 2, this.canvas.height / 2 + (fontSize * 0.75));\n this.context.fillText('display size', this.canvas.width / 2, this.canvas.height / 2 - (fontSize * 0.75));\n }\n }\n\n updateTransform() {\n // TODO: no reduce\n const transform = ['', '-webkit-', '-moz-', '-ms-', '-o-'].reduce((p, v) => {\n return v + 'transform' in document.body.style ? v : p;\n }) + 'transform';\n for (let l = 0; l < this.layers.length; l++) {\n\n let a = [];\n let b = [];\n for (let i = 0, n = this.layers[l].sourcePoints.length; i < n; ++i) {\n const s = this.layers[l].sourcePoints[i], t = this.layers[l].targetPoints[i];\n a.push([s[0], s[1], 1, 0, 0, 0, -s[0] * t[0], -s[1] * t[0]]), b.push(t[0]);\n a.push([0, 0, 0, s[0], s[1], 1, -s[0] * t[1], -s[1] * t[1]]), b.push(t[1]);\n }\n\n // TODO: remove dependency on numeric\n const X = solve(a, b, true);\n const matrix = [\n X[0], X[3], 0, X[6],\n X[1], X[4], 0, X[7],\n 0, 0, 1, 0,\n X[2], X[5], 0, 1\n ];\n\n this.layers[l].element.style[transform] = 'matrix3d(' + matrix.join(',') + ')';\n this.layers[l].element.style[transform + '-origin'] = '0px 0px 0px';\n }\n }\n\n /**\n * @private\n * @param {KeyboardEvent} event \n */\n keyDown(event) {\n if (!this.configActive) {\n if (event.keyCode == 32 && event.shiftKey) {\n this.setConfigEnabled(true);\n return;\n } else {\n return;\n }\n }\n\n // leave Cmd/Ctrl shortcuts (copy, paste, ...) to the page: c and v would otherwise toggle crosshairs / flip\n if (event.metaKey || event.ctrlKey) {\n return;\n }\n\n const key = event.keyCode;\n\n const increment = event.shiftKey ? 10 : 1;\n let dirty = false;\n const delta = [0, 0];\n\n switch (key) {\n\n case 32: // spacebar\n if (event.shiftKey) {\n this.setConfigEnabled(false);\n return;\n }\n break;\n\n case 37: // left arrow\n delta[0] -= increment;\n break;\n\n case 38: // up arrow\n delta[1] -= increment;\n break;\n\n case 39: // right arrow\n delta[0] += increment;\n break;\n\n case 40: // down arrow\n delta[1] += increment;\n break;\n\n case 67: // c key, toggle crosshairs\n this.showCrosshairs = !this.showCrosshairs;\n dirty = true;\n break;\n\n case 83: // s key, solo/unsolo quads\n if (!this.isLayerSoloed) {\n\n if (this.selectedLayer != null) {\n for (let i = 0; i < this.layers.length; i++) {\n this.layers[i].visible = false;\n }\n this.selectedLayer.visible = true;\n dirty = true;\n this.isLayerSoloed = true;\n }\n } else {\n for (let i = 0; i < this.layers.length; i++) {\n this.layers[i].visible = true;\n }\n this.isLayerSoloed = false;\n dirty = true;\n\n }\n break;\n\n case 66: // b key, toggle projector bounds rectangle.\n this.showScreenBounds = !this.showScreenBounds;\n this.draw();\n break;\n\n case 72: // h key, flip horizontal.\n if (this.selectedLayer) {\n swapLayerPoints(this.selectedLayer.sourcePoints, 0, 1);\n swapLayerPoints(this.selectedLayer.sourcePoints, 3, 2);\n this.updateTransform();\n this.draw();\n }\n break;\n\n case 86: // v key, flip vertical.\n if (this.selectedLayer) {\n swapLayerPoints(this.selectedLayer.sourcePoints, 0, 3);\n swapLayerPoints(this.selectedLayer.sourcePoints, 1, 2);\n this.updateTransform();\n this.draw();\n }\n break;\n\n case 82: // r key, rotate 90 degrees.\n if (this.selectedLayer) {\n rotateLayer(this.selectedLayer, Math.PI / 2);\n //rotateLayer(selectedLayer, 0.002);\n this.updateTransform();\n this.draw();\n }\n break;\n }\n\n // if a layer or point is selected, add the delta amounts (set above via arrow keys)\n if (!this.showScreenBounds) {\n if (this.selectedPoint) {\n this.selectedPoint[0] += delta[0];\n this.selectedPoint[1] += delta[1];\n dirty = true;\n } else if (this.selectedLayer) {\n if (event.altKey == true) {\n rotateLayer(this.selectedLayer, delta[0] * 0.01);\n scaleLayer(this.selectedLayer, (delta[1] * -0.005) + 1.0);\n } else {\n for (let i = 0; i < this.selectedLayer.targetPoints.length; i++) {\n this.selectedLayer.targetPoints[i][0] += delta[0];\n this.selectedLayer.targetPoints[i][1] += delta[1];\n }\n }\n dirty = true;\n }\n }\n\n // update the transform and redraw if needed\n if (dirty) {\n this.updateTransform();\n this.draw();\n if (this.autoSave) {\n this.saveSettings();\n }\n this.notifyChangeListener();\n }\n }\n\n /**\n * @private\n * @param {MouseEvent} event\n */\n mouseMove(event) {\n if (!this.configActive) {\n return;\n }\n\n event.preventDefault();\n\n this.mouseDelta[0] = event.clientX - this.mousePosition[0];\n this.mouseDelta[1] = event.clientY - this.mousePosition[1];\n\n this.mousePosition[0] = event.clientX;\n this.mousePosition[1] = event.clientY;\n\n if (this.dragging) {\n\n const scale = event.shiftKey ? 0.1 : 1;\n\n if (this.selectedPoint) {\n this.selectedPoint[0] += this.mouseDelta[0] * scale;\n this.selectedPoint[1] += this.mouseDelta[1] * scale;\n } else if (this.selectedLayer) {\n\n // Alt-drag to rotate and scale\n if (event.altKey == true) {\n rotateLayer(this.selectedLayer, this.mouseDelta[0] * (0.01 * scale));\n scaleLayer(this.selectedLayer, (this.mouseDelta[1] * (-0.005 * scale)) + 1.0);\n } else {\n for (let i = 0; i < this.selectedLayer.targetPoints.length; i++) {\n this.selectedLayer.targetPoints[i][0] += this.mouseDelta[0] * scale;\n this.selectedLayer.targetPoints[i][1] += this.mouseDelta[1] * scale;\n }\n }\n }\n\n this.updateTransform();\n if (this.autoSave) {\n this.saveSettings();\n }\n this.draw();\n this.notifyChangeListener();\n } else {\n let dirty = false;\n\n this.canvas.style.cursor = 'default';\n const mouseX = event.clientX;\n const mouseY = event.clientY;\n\n const previousState = (this.hoveringPoint != null);\n const previousLayer = (this.hoveringLayer != null);\n\n this.hoveringPoint = null;\n\n for (let i = 0; i < this.layers.length; i++) {\n let layer = this.layers[i];\n if (layer.visible) {\n for (let p = 0; p < layer.targetPoints.length; p++) {\n let point = layer.targetPoints[p];\n if (distanceTo(point[0], point[1], mouseX, mouseY) < this.selectionRadius) {\n this.canvas.style.cursor = 'pointer';\n this.hoveringPoint = point;\n break;\n }\n }\n }\n }\n\n // later layers are drawn on top, so search from the end: overlapping layers select the topmost one\n this.hoveringLayer = null;\n for (let i = this.layers.length - 1; i >= 0; i--) {\n if (this.layers[i].visible && pointInLayer(this.mousePosition, this.layers[i])) {\n this.hoveringLayer = this.layers[i];\n break;\n }\n }\n\n if (this.showCrosshairs ||\n (previousState != (this.hoveringPoint != null)) ||\n (previousLayer != (this.hoveringLayer != null))\n ) {\n this.draw();\n }\n }\n }\n\n /**\n * @private\n * @param {MouseEvent} event \n */\n mouseUp(event) {\n if (!this.configActive) {\n return;\n }\n event.preventDefault();\n\n this.dragging = false;\n }\n\n /**\n * @private\n * @param {MouseEvent} event \n */\n mouseDown(event) {\n if (!this.configActive || this.showScreenBounds) {\n return;\n }\n event.preventDefault();\n\n this.hoveringPoint = null;\n\n if (this.hoveringLayer) {\n this.selectedLayer = this.hoveringLayer;\n this.dragging = true;\n } else {\n this.selectedLayer = null;\n }\n\n this.selectedPoint = null;\n\n const mouseX = event.clientX;\n const mouseY = event.clientY;\n\n this.mouseDownPoint[0] = mouseX;\n this.mouseDownPoint[1] = mouseY;\n\n for (let i = 0; i < this.layers.length; i++) {\n const layer = this.layers[i];\n for (let p = 0; p < layer.targetPoints.length; p++) {\n const point = layer.targetPoints[p];\n if (distanceTo(point[0], point[1], mouseX, mouseY) < this.selectionRadius) {\n this.selectedLayer = layer;\n this.selectedPoint = point;\n this.dragging = true;\n this.dragOffset[0] = event.clientX - point[0];\n this.dragOffset[1] = event.clientY - point[1];\n //this.draw();\n break;\n }\n }\n }\n this.draw();\n return false;\n }\n\n /**\n * Add a {@link Layer} to an HTMLElement, either by id or by reference.\n *\n * @private\n * @param {string|HTMLElement} target \n * @param {Point[]} [targetPoints] initial points for the layer\n */\n addLayer(target, targetPoints) {\n /** @type {HTMLElement} */\n let element;\n if (typeof (target) == 'string') {\n element = document.getElementById(target);\n if (!element) {\n throw new Error('Maptastic: No element found with id: ' + target);\n }\n } else if (target instanceof HTMLElement) {\n element = target;\n }\n\n for (let n = 0; n < this.layers.length; n++) {\n if (this.layers[n].element.id == element.id) {\n throw new Error('Maptastic: Layer already added: ' + element.id);\n }\n }\n\n const offsetX = element.offsetLeft;\n const offsetY = element.offsetTop;\n\n element.style.position = 'fixed';\n element.style.display = 'block';\n element.style.top = '0px';\n element.style.left = '0px';\n element.style.padding = '0px';\n element.style.margin = '0px';\n\n const layer = {\n 'visible': true,\n 'element': element,\n 'width': element.clientWidth,\n 'height': element.clientHeight,\n 'sourcePoints': [],\n 'targetPoints': []\n };\n layer.sourcePoints.push([0, 0], [layer.width, 0], [layer.width, layer.height], [0, layer.height]);\n\n if (targetPoints) {\n layer.targetPoints = clonePoints(targetPoints);\n } else {\n layer.targetPoints.push([0, 0], [layer.width, 0], [layer.width, layer.height], [0, layer.height]);\n for (var i = 0; i < layer.targetPoints.length; i++) {\n layer.targetPoints[i][0] += offsetX;\n layer.targetPoints[i][1] += offsetY;\n }\n }\n\n this.layers.push(layer);\n\n this.updateTransform();\n }\n\n // Settings\n /**\n * Stop mapping an element that was added with addLayer. The element itself is left in the page.\n *\n * @param {HTMLElement} element\n */\n removeLayer(element) {\n const index = this.layers.findIndex((layer) => layer.element === element);\n if (index === -1) {\n return;\n }\n this.layers.splice(index, 1);\n if (this.selectedLayer && this.selectedLayer.element === element) {\n this.selectedLayer = null;\n this.selectedPoint = null;\n }\n if (this.hoveringLayer && this.hoveringLayer.element === element) {\n this.hoveringLayer = null;\n }\n this.draw();\n }\n\n /**\n * Save current layout settings to local storage.\n * \n * @private\n */\n saveSettings() {\n localStorage.setItem(this.localStorageKey, JSON.stringify(this.getLayout()));\n }\n\n /**\n * Load layout settings from local storage.\n * \n * @private\n */\n loadSettings() {\n if (!localStorage.getItem(this.localStorageKey)) {\n return;\n }\n const data = JSON.parse(localStorage.getItem(this.localStorageKey));\n\n for (let i = 0; i < data.length; i++) {\n for (let n = 0; n < this.layers.length; n++) {\n if (this.layers[n].element.id == data[i].id) {\n this.layers[n].targetPoints = clonePoints(data[i].targetPoints);\n this.layers[n].sourcePoints = clonePoints(data[i].sourcePoints);\n }\n }\n }\n this.updateTransform();\n }\n\n /**\n * @private\n * @param {boolean} enabled\n */\n setConfigEnabled(enabled) {\n this.configActive = enabled;\n this.canvas.style.display = enabled ? 'block' : 'none';\n\n if (!enabled) {\n this.selectedPoint = null;\n this.selectedLayer = null;\n this.dragging = false;\n this.showScreenBounds = false;\n } else {\n this.draw();\n }\n }\n\n /**\n * @public\n * @returns {Layout}\n */\n getLayout() {\n const layout = []; // TODO: change to a map()\n for (let i = 0; i < this.layers.length; i++) {\n layout.push({\n 'id': this.layers[i].element.id,\n 'targetPoints': clonePoints(this.layers[i].targetPoints),\n 'sourcePoints': clonePoints(this.layers[i].sourcePoints)\n });\n }\n return layout;\n }\n\n /**\n * @public\n * @param {*} layout \n */\n setLayout(layout) {\n for (let i = 0; i < layout.length; i++) {\n let exists = false;\n for (let n = 0; n < this.layers.length; n++) {\n if (this.layers[n].element.id == layout[i].id) {\n console.log('Setting points.');\n this.layers[n].targetPoints = clonePoints(layout[i].targetPoints);\n this.layers[n].sourcePoints = clonePoints(layout[i].sourcePoints);\n exists = true;\n }\n }\n\n if (!exists) {\n const element = document.getElementById(layout[i].id);\n if (element) {\n this.addLayer(element, layout[i].targetPoints);\n } else {\n console.log('Maptastic: Can\\'t find element: ' + layout[i].id);\n }\n } else {\n console.log('Maptastic: Element \\'' + layout[i].id + '\\' is already mapped.');\n }\n }\n this.updateTransform();\n this.draw();\n }\n}\n\nexport { Maptastic };\n"],"names":["_foreach2","x","s","k","f","length","i","n","ret","Array","dim","y","_typeof","push","_dim","cloneV","_n","clone","solve","A","b","fast","LUP","j","Pi","LUi","tmp","LU","P","LUsolve","absAjk","Akk","Ak","Pk","Ai","max","arguments","undefined","abs","Math","n1","has","Object","prototype","hasOwnProperty","getProp","obj","key","defaultVal","call","distanceTo","x1","y1","x2","y2","sqrt","pow","pointInTriangle","point","a","c","t","swapLayerPoints","layerPoints","index1","index2","tx","ty","pointInLayer","layer","targetPoints","rotateLayer","angle","sin","cos","centerPoint","p","px","py","scaleLayer","scale","clonePoints","points","slice","Maptastic","_createClass","configOrTarget","_classCallCheck","this","canvas","context","layers","configActive","dragging","dragOffset","selectedLayer","selectedPoint","selectionRadius","hoveringPoint","hoveringLayer","dragOperation","isLayerSoloed","mousePosition","mouseDelta","mouseDownPoint","showLayerNames","showCrosshairs","showScreenBounds","autoSave","layoutChangeListener","localStorageKey","layerList","_len","targets","_key","potentialLayerTargets","concat","HTMLElement","addLayer","loadSettings","init","value","_this","document","createElement","style","display","position","top","left","zIndex","getContext","body","appendChild","window","addEventListener","event","resize","mouseMove","mouseUp","mouseDown","keyDown","_window","innerHeight","width","innerWidth","height","draw","strokeStyle","lineWidth","clearRect","visible","element","visibility","beginPath","moveTo","lineTo","closePath","stroke","arc","PI","label","id","toUpperCase","font","textAlign","size","measureText","fillStyle","fillRect","fillText","stepX","stepY","strokeRect","fontSize","round","transform","reduce","v","l","sourcePoints","X","join","keyCode","shiftKey","setConfigEnabled","metaKey","ctrlKey","increment","dirty","delta","updateTransform","altKey","saveSettings","notifyChangeListener","preventDefault","clientX","clientY","cursor","mouseX","mouseY","previousState","previousLayer","target","getElementById","Error","offsetX","offsetLeft","offsetY","offsetTop","padding","margin","clientWidth","clientHeight","index","findIndex","splice","localStorage","setItem","JSON","stringify","getLayout","getItem","data","parse","enabled","layout","exists","console","log"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maptastic",
3
- "version": "2.0.2",
3
+ "version": "3.1.0",
4
4
  "main": "dist/maptastic.js",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "author": "ben purdy (https://github.com/benpurdy)",
@@ -14,20 +14,33 @@
14
14
  "dist/**/*"
15
15
  ],
16
16
  "scripts": {
17
- "build": "rollup --config -o dist/maptastic.js",
18
- "clean": "rimraf dist"
17
+ "build": "rollup --config",
18
+ "clean": "rimraf dist",
19
+ "prepublishOnly": "npm run clean && npm run build",
20
+ "pretest": "npm run build",
21
+ "test": "node --test",
22
+ "pretest:browser": "npm run build",
23
+ "test:browser": "playwright test"
19
24
  },
20
25
  "devDependencies": {
21
- "@babel/core": "^7.7.5",
22
- "@babel/plugin-transform-modules-commonjs": "^7.7.5",
23
- "@babel/preset-env": "^7.7.6",
24
- "rimraf": "^2.6.2",
25
- "rollup": "^1.27.9",
26
- "rollup-plugin-babel": "^4.3.3",
27
- "rollup-plugin-commonjs": "^10.1.0",
28
- "rollup-plugin-uglify": "^6.0.3"
26
+ "@babel/core": "^7.29.7",
27
+ "@babel/preset-env": "^7.29.7",
28
+ "@playwright/test": "^1.64.1",
29
+ "@rollup/plugin-babel": "^7.1.0",
30
+ "@rollup/plugin-terser": "^1.0.0",
31
+ "jsdom": "^30.1.3",
32
+ "rimraf": "^6.1.3",
33
+ "rollup": "^4.64.7"
29
34
  },
30
- "dependencies": {
31
- "numeric": "^1.2.6"
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/austince/maptasticjs.git"
38
+ },
39
+ "devEngines": {
40
+ "runtime": {
41
+ "name": "node",
42
+ "version": ">=24",
43
+ "onFail": "warn"
44
+ }
32
45
  }
33
46
  }