maptastic 3.0.0 → 3.2.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
@@ -45,6 +45,8 @@ import { Maptastic } from 'maptastic';
45
45
  const map = new Maptastic("so-simple");
46
46
  ```
47
47
 
48
+ TypeScript definitions are included in the package, so no `@types` package is needed.
49
+
48
50
  ## Controls
49
51
 
50
52
  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.
@@ -164,8 +166,42 @@ Add a new HTML element to be mapped.
164
166
 
165
167
  `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`
166
168
 
169
+ #### removeLayer( _element_ )
170
+
171
+ Stops mapping an element previously added with `addLayer`. The element is left in the page; remove it yourself if you no longer need it.
172
+
167
173
  #### setConfigEnabled( _enabled_ )
168
174
 
169
175
  Sets the current Configuration Mode state.
170
176
 
171
177
  `enabled` boolean, required.
178
+
179
+ ## Development
180
+
181
+ ```bash
182
+ # Node 24+ (see devEngines in package.json)
183
+ npm ci
184
+ npm test # builds dist/ and runs the tests against it
185
+
186
+ # headless browser tests (Chromium, Firefox, WebKit) via Playwright
187
+ npx playwright install
188
+ npm run test:browser
189
+ ```
190
+
191
+ `dist/` is not committed. Run `npm run build` before opening the files in `example/`, which load `../dist/maptastic.js`.
192
+
193
+ ### Releasing
194
+
195
+ Releases are made by [semantic-release](https://github.com/semantic-release/semantic-release) from GitHub Actions
196
+ ([`publish.yml`](.github/workflows/publish.yml)). Commits build up on `master`; when you want a release, run the
197
+ Publish workflow from the Actions tab (or `gh workflow run publish.yml`), optionally with `dry_run` checked to preview
198
+ the next version first. Write commit messages in the
199
+ [Conventional Commits](https://www.conventionalcommits.org/) format: `fix:` makes a patch release, `feat:` a minor
200
+ release, and a `!` after the type (or a `BREAKING CHANGE:` footer) a major release. Other types, such as `docs:`,
201
+ `test:`, and `ci:`, do not release. Do not bump the version in `package.json` by hand.
202
+
203
+ When there are releasable commits since the last tag, the workflow commits the new version and `CHANGELOG.md` back to
204
+ `master`, tags the release, creates the GitHub release (with the built `dist/maptastic.js` and its source map
205
+ attached), and stages the package on npm via [trusted publishing](https://docs.npmjs.com/trusted-publishers), so no npm token is stored anywhere.
206
+ The release goes live only after a maintainer approves it with 2FA ([staged publishing](https://docs.npmjs.com/staged-publishing)):
207
+ run `npm stage list maptastic`, then `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):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).maptastic={})}(this,function(t){"use strict";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})(t)}function i(t,e){for(var s=0;s<e.length;s++){var i=e[s];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function e(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 n(t){var e,s=t.length,i=Array(s);for(e=s-1;-1!==e;--e)i[e]=t[e];return i}function v(t){return"object"!==s(t)?t:function t(e,s,i,n){if(i===s.length-1)return n(e);var o,r=s[i],a=Array(r);for(o=r-1;0<=o;o--)a[o]=t(e[o],s,i+1,n);return a}(t,e(t),0,n)}function l(t,e,s){return function(t,e){var s,i,n,o,r,a=t.LU,h=a.length,l=v(e),c=t.P;for(s=h-1;-1!==s;--s)l[s]=e[s];for(s=0;s<h;++s)for((n=c[s])!==s&&(r=l[s],l[s]=l[n],l[n]=r),o=a[s],i=0;i<s;++i)l[s]-=l[i]*o[i];for(s=h-1;0<=s;--s){for(o=a[s],i=s+1;i<h;++i)l[s]-=l[i]*o[i];l[s]/=o[s]}return l}(function(t,e){var s,i,n,o,r,a,h,l,c,u=1<arguments.length&&void 0!==e&&e,y=Math.abs,f=t.length,g=f-1,d=new Array(f);for(u||(t=v(t)),n=0;n<f;++n){for(c=y((a=t[h=n])[n]),i=n+1;i<f;++i)c<(o=y(t[i][n]))&&(c=o,h=i);for((d[n]=h)!=n&&(t[n]=t[h],t[h]=a,a=t[n]),r=a[n],s=n+1;s<f;++s)t[s][n]/=r;for(s=n+1;s<f;++s){for(l=t[s],i=n+1;i<g;++i)l[i]-=l[n]*a[i],l[++i]-=l[n]*a[i];i===g&&(l[i]-=l[n]*a[i])}}return{LU:t,P:d}}(t,s),e)}var o=Object.prototype.hasOwnProperty;function h(t,e,s){return t&&o.call(t,e)&&null!==t[e]?t[e]:s}function P(t,e,s,i){return Math.sqrt(Math.pow(s-t,2)+Math.pow(i-e,2))}function m(t,e,s,i){var n=e[1]*i[0]-e[0]*i[1]+(i[1]-e[1])*t[0]+(e[0]-i[0])*t[1],o=e[0]*s[1]-e[1]*s[0]+(e[1]-s[1])*t[0]+(s[0]-e[0])*t[1];if(n<0!=o<0)return!1;var r=-s[1]*i[0]+e[1]*(i[0]-s[0])+e[0]*(s[1]-i[1])+s[0]*i[1];return r<0&&(n=-n,o=-o,r=-r),0<n&&0<o&&n+o<r}function c(t,e,s){var i=t[e][0],n=t[e][1];t[e][0]=t[s][0],t[e][1]=t[s][1],t[s][0]=i,t[s][1]=n}function p(t,e){for(var s=Math.sin(e),i=Math.cos(e),n=[0,0],o=0;o<t.targetPoints.length;o++)n[0]+=t.targetPoints[o][0],n[1]+=t.targetPoints[o][1];n[0]/=4,n[1]/=4;for(var r=0;r<t.targetPoints.length;r++){var a=t.targetPoints[r][0]-n[0],h=t.targetPoints[r][1]-n[1];t.targetPoints[r][0]=a*i-h*s+n[0],t.targetPoints[r][1]=a*s+h*i+n[1]}}function w(t,e){for(var s=[0,0],i=0;i<t.targetPoints.length;i++)s[0]+=t.targetPoints[i][0],s[1]+=t.targetPoints[i][1];s[0]/=4,s[1]/=4;for(var n=0;n<t.targetPoints.length;n++){var o=t.targetPoints[n][1]-s[1];t.targetPoints[n][0]=(t.targetPoints[n][0]-s[0])*e+s[0],t.targetPoints[n][1]=o*e+s[1]}}function u(t){for(var e=[],s=0;s<t.length;s++)e.push(t[s].slice(0,2));return e}t.Maptastic=function(){function a(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,a),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=h(t,"labels",!0),this.showCrosshairs=h(t,"crosshairs",!1),this.showScreenBounds=h(t,"screenbounds",!1),this.autoSave=h(t,"autoSave",!0),this.layoutChangeListener=h(t,"onchange",function(){}),this.localStorageKey="maptastic.layers";for(var e=h(t,"layers",[]),s=arguments.length,i=new Array(1<s?s-1:0),n=1;n<s;n++)i[n-1]=arguments[n];for(var o=e.concat(i,[t]),r=0;r<o.length;r++)(o[r]instanceof HTMLElement||"string"==typeof o[r])&&this.addLayer(o[r]);h(t,"autoLoad",!0)&&this.loadSettings(),this.init()}var t,e,s;return t=a,(e=[{key:"init",value:function(){var e=this,t=document.createElement("canvas");t.style.display="none",t.style.position="fixed",t.style.top="0px",t.style.left="0px",t.style.zIndex="1000000",this.canvas=t,this.context=t.getContext("2d"),document.body.appendChild(t),window.addEventListener("resize",function(t){return e.resize()}),window.addEventListener("mousemove",function(t){return e.mouseMove(t)}),window.addEventListener("mouseup",function(t){return e.mouseUp(t)}),window.addEventListener("mousedown",function(t){return e.mouseDown(t)}),window.addEventListener("keydown",function(t){return e.keyDown(t)}),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;t<this.layers.length;t++)if(this.layers[t].visible){this.layers[t].element.style.visibility="visible",this.context.beginPath(),this.context.strokeStyle=this.layers[t]===this.hoveringLayer?"red":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;e<this.layers[t].targetPoints.length;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 s=[0,0],i=0;i<this.layers[t].targetPoints.length;i++)this.context.strokeStyle=this.layers[t].targetPoints[i]===this.hoveringPoint?"red":this.layers[t].targetPoints[i]===this.selectedPoint?"red":"white",s[0]+=this.layers[t].targetPoints[i][0],s[1]+=this.layers[t].targetPoints[i][1],this.context.beginPath(),this.context.arc(this.layers[t].targetPoints[i][0],this.layers[t].targetPoints[i][1],this.selectionRadius/2,0,2*Math.PI,!1),this.context.stroke();if(s[0]/=4,s[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(s[0]-o[0]/2,s[1]-o[1]+8,o[0],o[1]),this.context.fillStyle="black",this.context.fillText(n,s[0],s[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;h<10;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;e<this.layers.length;e++){for(var s=[],i=[],n=0,o=this.layers[e].sourcePoints.length;n<o;++n){var r=this.layers[e].sourcePoints[n],a=this.layers[e].targetPoints[n];s.push([r[0],r[1],1,0,0,0,-r[0]*a[0],-r[1]*a[0]]),i.push(a[0]),s.push([0,0,0,r[0],r[1],1,-r[0]*a[1],-r[1]*a[1]]),i.push(a[1])}var h=l(s,i,!0);this.layers[e].element.style[t]="matrix3d("+[h[0],h[3],0,h[6],h[1],h[4],0,h[7],0,0,1,0,h[2],h[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;var e=t.shiftKey?10:1,s=!1,i=[0,0];switch(t.keyCode){case 32:if(t.shiftKey)return void this.setConfigEnabled(!1);break;case 37:i[0]-=e;break;case 38:i[1]-=e;break;case 39:i[0]+=e;break;case 40:i[1]+=e;break;case 67:this.showCrosshairs=!this.showCrosshairs,s=!0;break;case 83:if(this.isLayerSoloed){for(var n=0;n<this.layers.length;n++)this.layers[n].visible=!0;s=!(this.isLayerSoloed=!1)}else if(null!=this.selectedLayer){for(var o=0;o<this.layers.length;o++)this.layers[o].visible=!1;this.selectedLayer.visible=!0,this.isLayerSoloed=s=!0}break;case 66:this.showScreenBounds=!this.showScreenBounds,this.draw();break;case 72:this.selectedLayer&&(c(this.selectedLayer.sourcePoints,0,1),c(this.selectedLayer.sourcePoints,3,2),this.updateTransform(),this.draw());break;case 86:this.selectedLayer&&(c(this.selectedLayer.sourcePoints,0,3),c(this.selectedLayer.sourcePoints,1,2),this.updateTransform(),this.draw());break;case 82:this.selectedLayer&&(p(this.selectedLayer,Math.PI/2),this.updateTransform(),this.draw())}if(!this.showScreenBounds)if(this.selectedPoint)this.selectedPoint[0]+=i[0],this.selectedPoint[1]+=i[1],s=!0;else if(this.selectedLayer){if(1==t.altKey)p(this.selectedLayer,.01*i[0]),w(this.selectedLayer,-.005*i[1]+1);else for(var r=0;r<this.selectedLayer.targetPoints.length;r++)this.selectedLayer.targetPoints[r][0]+=i[0],this.selectedLayer.targetPoints[r][1]+=i[1];s=!0}s&&(this.updateTransform(),this.draw(),this.autoSave&&this.saveSettings(),this.notifyChangeListener())}},{key:"mouseMove",value:function(t){var e,s,i,n;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 o=t.shiftKey?.1:1;if(this.selectedPoint)this.selectedPoint[0]+=this.mouseDelta[0]*o,this.selectedPoint[1]+=this.mouseDelta[1]*o;else if(this.selectedLayer)if(1==t.altKey)p(this.selectedLayer,this.mouseDelta[0]*(.01*o)),w(this.selectedLayer,this.mouseDelta[1]*(-.005*o)+1);else for(var r=0;r<this.selectedLayer.targetPoints.length;r++)this.selectedLayer.targetPoints[r][0]+=this.mouseDelta[0]*o,this.selectedLayer.targetPoints[r][1]+=this.mouseDelta[1]*o;this.updateTransform(),this.autoSave&&this.saveSettings(),this.draw(),this.notifyChangeListener()}else{this.canvas.style.cursor="default";var a=t.clientX,h=t.clientY,l=null!=this.hoveringPoint,c=null!=this.hoveringLayer;this.hoveringPoint=null;for(var u=0;u<this.layers.length;u++){var y=this.layers[u];if(y.visible)for(var f=0;f<y.targetPoints.length;f++){var g=y.targetPoints[f];if(P(g[0],g[1],a,h)<this.selectionRadius){this.canvas.style.cursor="pointer",this.hoveringPoint=g;break}}}this.hoveringLayer=null;for(var d=0;d<this.layers.length;d++)if(this.layers[d].visible&&(void 0,i=m(e=this.mousePosition,(s=this.layers[d]).targetPoints[0],s.targetPoints[1],s.targetPoints[2]),n=m(e,s.targetPoints[3],s.targetPoints[0],s.targetPoints[2]),i||n)){this.hoveringLayer=this.layers[d];break}!this.showCrosshairs&&l==(null!=this.hoveringPoint)&&c==(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,s=t.clientY;this.mouseDownPoint[0]=e,this.mouseDownPoint[1]=s;for(var i=0;i<this.layers.length;i++)for(var n=this.layers[i],o=0;o<n.targetPoints.length;o++){var r=n.targetPoints[o];if(P(r[0],r[1],e,s)<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 s;if("string"==typeof t){if(!(s=document.getElementById(t)))throw new Error("Maptastic: No element found with id: "+t)}else t instanceof HTMLElement&&(s=t);for(var i=0;i<this.layers.length;i++)this.layers[i].element.id==s.id&&(this.layers[i].targetPoints=u(layout[a].targetPoints));var n=s.offsetLeft,o=s.offsetTop;s.style.position="fixed",s.style.display="block",s.style.top="0px",s.style.left="0px",s.style.padding="0px",s.style.margin="0px";var r={visible:!0,element:s,width:s.clientWidth,height:s.clientHeight,sourcePoints:[],targetPoints:[]};if(r.sourcePoints.push([0,0],[r.width,0],[r.width,r.height],[0,r.height]),e)r.targetPoints=u(e);else{r.targetPoints.push([0,0],[r.width,0],[r.width,r.height],[0,r.height]);for(var a=0;a<r.targetPoints.length;a++)r.targetPoints[a][0]+=n,r.targetPoints[a][1]+=o}this.layers.push(r),this.updateTransform()}},{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;e<t.length;e++)for(var s=0;s<this.layers.length;s++)this.layers[s].element.id==t[e].id&&(this.layers[s].targetPoints=u(t[e].targetPoints),this.layers[s].sourcePoints=u(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;e<this.layers.length;e++)t.push({id:this.layers[e].element.id,targetPoints:u(this.layers[e].targetPoints),sourcePoints:u(this.layers[e].sourcePoints)});return t}},{key:"setLayout",value:function(t){for(var e=0;e<t.length;e++){for(var s=!1,i=0;i<this.layers.length;i++)this.layers[i].element.id==t[e].id&&(console.log("Setting points."),this.layers[i].targetPoints=u(t[e].targetPoints),this.layers[i].sourcePoints=u(t[e].sourcePoints),s=!0);if(s)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()}}])&&i(t.prototype,e),s&&i(t,s),a}(),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/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.\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\n if ((s < 0) != (t < 0)) {\n return false;\n }\n\n let 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/**\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 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 this.hoveringLayer = null;\n for (let i = 0; i < this.layers.length; 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 let exists = false;\n for (var n = 0; n < this.layers.length; n++) {\n if (this.layers[n].element.id == element.id) {\n this.layers[n].targetPoints = clonePoints(layout[i].targetPoints);\n exists = true;\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 * 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":["dim","x","y","_typeof","ret","push","length","_dim","cloneV","i","_n","Array","clone","_foreach2","s","k","f","n","solve","A","b","fast","LUP","j","Pi","LUi","tmp","LU","P","LUsolve","absAjk","Akk","Ak","Pk","Ai","max","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","rotateLayer","layer","angle","sin","cos","centerPoint","p","targetPoints","px","py","scaleLayer","scale","clonePoints","points","slice","configOrTarget","canvas","context","layers","configActive","dragging","dragOffset","selectedLayer","selectedPoint","selectionRadius","hoveringPoint","hoveringLayer","dragOperation","isLayerSoloed","mousePosition","mouseDelta","mouseDownPoint","showLayerNames","showCrosshairs","showScreenBounds","autoSave","layoutChangeListener","localStorageKey","layerList","targets","potentialLayerTargets","concat","HTMLElement","addLayer","loadSettings","init","document","createElement","style","display","position","top","left","zIndex","getContext","body","appendChild","window","addEventListener","event","_this","resize","mouseMove","mouseUp","mouseDown","keyDown","innerHeight","width","innerWidth","height","draw","this","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","increment","dirty","delta","updateTransform","altKey","saveSettings","notifyChangeListener","preventDefault","clientX","clientY","cursor","mouseX","mouseY","previousState","previousLayer","target","getElementById","Error","layout","offsetX","offsetLeft","offsetY","offsetTop","padding","margin","clientWidth","clientHeight","localStorage","setItem","JSON","stringify","getLayout","getItem","data","parse","enabled","exists","console","log"],"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,7 +1,8 @@
1
1
  {
2
2
  "name": "maptastic",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "main": "dist/maptastic.js",
5
+ "types": "types/maptastic.d.ts",
5
6
  "license": "SEE LICENSE IN license.txt",
6
7
  "author": "ben purdy (https://github.com/benpurdy)",
7
8
  "contributors": [
@@ -11,21 +12,43 @@
11
12
  "files": [
12
13
  "license.txt",
13
14
  "src/**/*",
14
- "dist/**/*"
15
+ "dist/**/*",
16
+ "types/maptastic.d.ts"
15
17
  ],
16
18
  "scripts": {
17
- "build": "rollup --config -o dist/maptastic.js",
18
- "clean": "rimraf dist"
19
+ "build": "rollup --config",
20
+ "clean": "rimraf dist",
21
+ "prepublishOnly": "npm run clean && npm run build",
22
+ "pretest": "npm run build",
23
+ "test": "node --test \"test/**/*.test.js\"",
24
+ "test:types": "tsc -p types/test",
25
+ "pretest:browser": "npm run build",
26
+ "test:browser": "playwright test"
19
27
  },
20
28
  "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.4"
29
+ "@babel/core": "^7.29.7",
30
+ "@babel/preset-env": "^7.29.7",
31
+ "@playwright/test": "^1.64.1",
32
+ "@rollup/plugin-babel": "^7.1.0",
33
+ "@rollup/plugin-terser": "^1.0.0",
34
+ "@semantic-release/changelog": "^7.0.0",
35
+ "@semantic-release/exec": "^7.1.0",
36
+ "@semantic-release/git": "^11.0.1",
37
+ "jsdom": "^30.1.3",
38
+ "rimraf": "^6.1.3",
39
+ "rollup": "^4.64.7",
40
+ "semantic-release": "^25.0.9",
41
+ "typescript": "^7.0.2"
29
42
  },
30
- "dependencies": {}
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/austince/maptasticjs.git"
46
+ },
47
+ "devEngines": {
48
+ "runtime": {
49
+ "name": "node",
50
+ "version": ">=24",
51
+ "onFail": "warn"
52
+ }
53
+ }
31
54
  }
package/src/maptastic.js CHANGED
@@ -69,30 +69,32 @@ function distanceTo(x1, y1, x2, y2) {
69
69
  }
70
70
 
71
71
  /**
72
- * Determine whether a {@link Point} falls within a triangle.
73
- *
74
- * @param {Point} point
75
- * @param {Point} a
76
- * @param {Point} b
72
+ * Determine whether a {@link Point} falls within a triangle, edges included.
73
+ *
74
+ * @param {Point} point
75
+ * @param {Point} a
76
+ * @param {Point} b
77
77
  * @param {Point} c
78
- * @returns {boolean}
78
+ * @returns {boolean}
79
79
  */
80
80
  function pointInTriangle(point, a, b, c) {
81
81
  let s = a[1] * c[0] - a[0] * c[1] + (c[1] - a[1]) * point[0] + (a[0] - c[0]) * point[1];
82
82
  let t = a[0] * b[1] - a[1] * b[0] + (a[1] - b[1]) * point[0] + (b[0] - a[0]) * point[1];
83
+ let A = -b[1] * c[0] + a[1] * (c[0] - b[0]) + a[0] * (b[1] - c[1]) + b[0] * c[1];
83
84
 
84
- if ((s < 0) != (t < 0)) {
85
- return false;
85
+ if (A == 0) {
86
+ return false; // degenerate triangle
86
87
  }
87
88
 
88
- let A = -b[1] * c[0] + a[1] * (c[0] - b[0]) + a[0] * (b[1] - c[1]) + b[0] * c[1];
89
- if (A < 0.0) {
89
+ // normalize the winding so the bounds below hold for either orientation
90
+ if (A < 0) {
90
91
  s = -s;
91
92
  t = -t;
92
93
  A = -A;
93
94
  }
94
95
 
95
- return s > 0 && t > 0 && (s + t) < A;
96
+ // inclusive, so the diagonal shared by a layer's two triangles counts as inside
97
+ return s >= 0 && t >= 0 && (s + t) <= A;
96
98
  }
97
99
 
98
100
  /**
@@ -472,6 +474,11 @@ class Maptastic {
472
474
  }
473
475
  }
474
476
 
477
+ // leave Cmd/Ctrl shortcuts (copy, paste, ...) to the page: c and v would otherwise toggle crosshairs / flip
478
+ if (event.metaKey || event.ctrlKey) {
479
+ return;
480
+ }
481
+
475
482
  const key = event.keyCode;
476
483
 
477
484
  const increment = event.shiftKey ? 10 : 1;
@@ -663,8 +670,9 @@ class Maptastic {
663
670
  }
664
671
  }
665
672
 
673
+ // later layers are drawn on top, so search from the end: overlapping layers select the topmost one
666
674
  this.hoveringLayer = null;
667
- for (let i = 0; i < this.layers.length; i++) {
675
+ for (let i = this.layers.length - 1; i >= 0; i--) {
668
676
  if (this.layers[i].visible && pointInLayer(this.mousePosition, this.layers[i])) {
669
677
  this.hoveringLayer = this.layers[i];
670
678
  break;
@@ -758,11 +766,9 @@ class Maptastic {
758
766
  element = target;
759
767
  }
760
768
 
761
- let exists = false;
762
- for (var n = 0; n < this.layers.length; n++) {
769
+ for (let n = 0; n < this.layers.length; n++) {
763
770
  if (this.layers[n].element.id == element.id) {
764
- this.layers[n].targetPoints = clonePoints(layout[i].targetPoints);
765
- exists = true;
771
+ throw new Error('Maptastic: Layer already added: ' + element.id);
766
772
  }
767
773
  }
768
774
 
@@ -802,6 +808,27 @@ class Maptastic {
802
808
  }
803
809
 
804
810
  // Settings
811
+ /**
812
+ * Stop mapping an element that was added with addLayer. The element itself is left in the page.
813
+ *
814
+ * @param {HTMLElement} element
815
+ */
816
+ removeLayer(element) {
817
+ const index = this.layers.findIndex((layer) => layer.element === element);
818
+ if (index === -1) {
819
+ return;
820
+ }
821
+ this.layers.splice(index, 1);
822
+ if (this.selectedLayer && this.selectedLayer.element === element) {
823
+ this.selectedLayer = null;
824
+ this.selectedPoint = null;
825
+ }
826
+ if (this.hoveringLayer && this.hoveringLayer.element === element) {
827
+ this.hoveringLayer = null;
828
+ }
829
+ this.draw();
830
+ }
831
+
805
832
  /**
806
833
  * Save current layout settings to local storage.
807
834
  *
@@ -0,0 +1,54 @@
1
+ /** An `[x, y]` coordinate in pixels. */
2
+ export type Point = [number, number];
3
+
4
+ /** An element, or the ID of an element, to map. */
5
+ export type Target = string | HTMLElement;
6
+
7
+ /** The mapping of a single layer, as returned by `getLayout` and accepted by `setLayout`. */
8
+ export interface Layout {
9
+ /** ID of the layer element. */
10
+ id: string;
11
+ /** Four corner points of the layer on screen. */
12
+ targetPoints: Point[];
13
+ /** Four corner points of the layer's original, unmapped rectangle. */
14
+ sourcePoints: Point[];
15
+ }
16
+
17
+ export interface Config {
18
+ /** Elements or element IDs to use as layers. */
19
+ layers?: Target[];
20
+ /** Called whenever the layout changes. */
21
+ onchange?: () => void;
22
+ /** Show crosshairs in edit mode. Default `false`. */
23
+ crosshairs?: boolean;
24
+ /** Show element IDs in edit mode. Default `true`. */
25
+ labels?: boolean;
26
+ /** Show the display bounds in edit mode. Default `false`. */
27
+ screenbounds?: boolean;
28
+ /** Save layer positions to local storage on change. Default `true`. */
29
+ autoSave?: boolean;
30
+ /** Load layer positions from local storage on creation. Default `true`. */
31
+ autoLoad?: boolean;
32
+ }
33
+
34
+ export class Maptastic {
35
+ constructor(config: Config, ...targets: Target[]);
36
+ constructor(...targets: Target[]);
37
+
38
+ /** Returns the current mapping of every layer. */
39
+ getLayout(): Layout[];
40
+
41
+ /** Applies a layout, adding layers for any IDs that are not mapped yet. */
42
+ setLayout(layout: Layout[]): void;
43
+
44
+ /** Maps a new element, optionally starting from the given corner points. */
45
+ addLayer(target: Target, targetPoints?: Point[]): void;
46
+
47
+ /** Stops mapping an element. The element is left in the page. */
48
+ removeLayer(element: HTMLElement): void;
49
+
50
+ /** Turns edit mode on or off. */
51
+ setConfigEnabled(enabled: boolean): void;
52
+ }
53
+
54
+ export as namespace maptastic;