ue-too
Version:
pan, zoom, and rotate your html canvas
3 lines (2 loc) • 24 kB
JavaScript
import{PointCal}from"point2point";function boundariesFullyDefined(boundaries){return null!=boundaries&&(null!=boundaries.max&&null!=boundaries.min&&(null!=boundaries.max.x&&null!=boundaries.max.y&&null!=boundaries.min.x&&null!=boundaries.min.y))}function translationWidthOf(boundaries){if(null!=boundaries&&null!=boundaries.min&&null!=boundaries.max&&null!=boundaries.min.x&&null!=boundaries.max.x)return boundaries.max.x-boundaries.min.x}function translationHeightOf(boundaries){if(null!=boundaries&&null!=boundaries.min&&null!=boundaries.max&&null!=boundaries.min.y&&null!=boundaries.max.y)return boundaries.max.y-boundaries.min.y}function minZoomLevelBaseOnDimensions(boundaries,canvasWidth,canvasHeight,cameraRotation){const width=translationWidthOf(boundaries),height=translationHeightOf(boundaries);if(null==width||null==height)return;let minZoomLevelWidthWidth=canvasWidth/Math.abs(width*Math.cos(cameraRotation)),minZoomLevelHeightWidth=canvasWidth/Math.abs(height*Math.cos(cameraRotation)),minZoomLevelWidthHeight=canvasHeight/Math.abs(width*Math.sin(cameraRotation)),minZoomLevelHeightHeight=canvasHeight/Math.abs(height*Math.sin(cameraRotation));minZoomLevelWidthWidth==1/0&&(minZoomLevelWidthWidth=0),minZoomLevelHeightWidth==1/0&&(minZoomLevelHeightWidth=0),minZoomLevelWidthHeight==1/0&&(minZoomLevelWidthHeight=0),minZoomLevelHeightHeight==1/0&&(minZoomLevelHeightHeight=0);const minZoomLevelHeight=canvasHeight/height,minZoomLevelWidth=canvasWidth/width;return Math.max(minZoomLevelHeight,minZoomLevelWidth,minZoomLevelWidthWidth,minZoomLevelHeightWidth,minZoomLevelWidthHeight,minZoomLevelHeightHeight)}function zoomLevelBoundariesShouldUpdate(zoomLevelBoundaries,targetMinZoomLevel){return null!=targetMinZoomLevel&&(null==zoomLevelBoundaries||targetMinZoomLevel!=1/0&&(void 0!==zoomLevelBoundaries&&(null==zoomLevelBoundaries.min||targetMinZoomLevel>zoomLevelBoundaries.min)))}function minZoomLevelBaseOnWidth(boundaries,canvasWidth,canvasHeight,cameraRotation){const width=translationWidthOf(boundaries);if(null==width)return;const widthWidthProjection=Math.abs(width*Math.cos(cameraRotation)),widthHeightProjection=Math.abs(width*Math.sin(cameraRotation));if(canvasWidth/widthWidthProjection==1/0)return canvasHeight/widthHeightProjection;return Math.max(canvasWidth/widthWidthProjection,canvasHeight/widthHeightProjection)}function minZoomLevelBaseOnHeight(boundaries,canvasWidth,canvasHeight,cameraRotation){const height=translationHeightOf(boundaries);if(null==height)return;const minZoomLevelHeightWidth=canvasWidth/Math.abs(height*Math.cos(cameraRotation)),minZoomLevelHeightHeight=canvasHeight/Math.abs(height*Math.sin(cameraRotation));if(minZoomLevelHeightHeight==1/0)return minZoomLevelHeightWidth;return Math.max(minZoomLevelHeightWidth,minZoomLevelHeightHeight)}function calculateOrderOfMagnitude(value){if(value<=0)return 0;let count=0;if(value<1){let divisor=1;for(;divisor>value;)divisor/=10,count--}else{let divisor=1;for(;10*divisor<=value;)divisor*=10,count++}return count}class Observable{constructor(){this.observers=[]}subscribe(observer,options){if(this.observers.push(observer),null==options?void 0:options.signal){if(options.signal.aborted)return this.observers=this.observers.filter((o=>o!==observer)),()=>{};const abortHandler=()=>{var _a;this.observers=this.observers.filter((o=>o!==observer)),null===(_a=options.signal)||void 0===_a||_a.removeEventListener("abort",abortHandler)};options.signal.addEventListener("abort",abortHandler)}return()=>{this.observers=this.observers.filter((o=>o!==observer))}}notify(...data){this.observers.forEach((observer=>queueMicrotask((()=>observer(...data)))))}}function drawCrossHair(context,pos,cameraZoomLevel,alignCoordinateSystem,size,color="red"){let halfSize=size/2;halfSize/=cameraZoomLevel,context.beginPath(),context.strokeStyle=color,context.lineWidth=2/cameraZoomLevel,alignCoordinateSystem?(context.moveTo(pos.x-halfSize,pos.y),context.lineTo(pos.x+halfSize,pos.y),context.moveTo(pos.x,pos.y-halfSize),context.lineTo(pos.x,pos.y+halfSize)):(context.moveTo(pos.x-halfSize,-pos.y),context.lineTo(pos.x+halfSize,-pos.y),context.moveTo(pos.x,-pos.y-halfSize),context.lineTo(pos.x,-pos.y+halfSize)),context.stroke(),context.lineWidth=3}function drawBoundingBox(context,boundaries,alignCoordinateSystem){if(!boundariesFullyDefined(boundaries))return;const width=translationWidthOf(boundaries),height=translationHeightOf(boundaries),curMin=null==boundaries?void 0:boundaries.min,curMinX=null==curMin?void 0:curMin.x,curMinY=null==curMin?void 0:curMin.y;null!=curMinX&&null!=curMinY&&null!=width&&null!=height&&(context.beginPath(),context.strokeStyle="blue",context.lineWidth=100,alignCoordinateSystem?context.roundRect(curMinX,curMinY,width,height,5):context.roundRect(curMinX,-curMinY,width,-height,5),context.stroke(),context.lineWidth=3,context.strokeStyle="black")}function drawAxis(context,boundaries,zoomLevel,alignCoordinateSystem){if(!boundariesFullyDefined(boundaries))return;const width=translationWidthOf(boundaries),height=translationHeightOf(boundaries),curMin=null==boundaries?void 0:boundaries.min,curMinX=null==curMin?void 0:curMin.x,curMinY=null==curMin?void 0:curMin.y;null!=curMinX&&null!=curMinY&&null!=width&&null!=height&&(context.lineWidth=1/zoomLevel,context.beginPath(),context.strokeStyle="rgba(87, 173, 72, 0.8)",context.moveTo(0,0),alignCoordinateSystem?context.lineTo(0,curMinY+height):context.lineTo(0,-curMinY-height),context.stroke(),context.beginPath(),context.strokeStyle="rgba(220, 59, 59, 0.8)",context.moveTo(0,0),context.lineTo(curMinX+width,0),context.stroke(),context.strokeStyle="black")}function drawGrid(context,topLeftCorner,topRightCorner,bottomLeftCorner,bottomRightCorner,alignCoordinateSystem,cameraZoomLevel){let leftRightDirection=PointCal.unitVectorFromA2B(topLeftCorner,topRightCorner),topDownDirection=PointCal.unitVectorFromA2B(bottomLeftCorner,topLeftCorner),width=PointCal.distanceBetweenPoints(topLeftCorner,topRightCorner);PointCal.distanceBetweenPoints(topLeftCorner,bottomLeftCorner);let orderOfMagnitude=calculateOrderOfMagnitude(width),subDivisor=Math.pow(10,orderOfMagnitude)/10,minHorizontalSmallTick=Math.ceil(topLeftCorner.x/subDivisor)*subDivisor,maxHorizontalSmallTick=Math.floor(topRightCorner.x/subDivisor)*subDivisor,minVerticalSmallTick=alignCoordinateSystem?Math.floor(topLeftCorner.y/subDivisor)*subDivisor:Math.ceil(bottomLeftCorner.y/subDivisor)*subDivisor,maxVerticalSmallTick=alignCoordinateSystem?Math.ceil(bottomLeftCorner.y/subDivisor)*subDivisor:Math.floor(topLeftCorner.y/subDivisor)*subDivisor;for(let i=minHorizontalSmallTick;i<=maxHorizontalSmallTick;i+=subDivisor){const startPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(leftRightDirection,subDivisor)),endPoint=PointCal.addVector({x:i,y:bottomLeftCorner.y},PointCal.multiplyVectorByScalar(leftRightDirection,subDivisor));context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=.5/cameraZoomLevel,context.moveTo(startPoint.x,startPoint.y),context.lineTo(endPoint.x,endPoint.y),context.stroke()}for(let i=minVerticalSmallTick;i<=maxVerticalSmallTick;i+=subDivisor){const startPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(topDownDirection,subDivisor)),endPoint=PointCal.addVector({x:topRightCorner.x,y:i},PointCal.multiplyVectorByScalar(topDownDirection,subDivisor));context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=.5/cameraZoomLevel,context.moveTo(startPoint.x,startPoint.y),context.lineTo(endPoint.x,endPoint.y),context.stroke()}}function drawRulerLegacy(context,topLeftCorner,topRightCorner,bottomLeftCorner,bottomRightCorner,alignCoordinateSystem,cameraZoomLevel){let leftRightDirection=PointCal.unitVectorFromA2B(topLeftCorner,topRightCorner),topDownDirection=PointCal.unitVectorFromA2B(bottomLeftCorner,topLeftCorner),orderOfMagnitude=calculateOrderOfMagnitude(PointCal.distanceBetweenPoints(topLeftCorner,topRightCorner)),divisor=Math.pow(10,orderOfMagnitude),halfDivisor=divisor/2,subDivisor=divisor/10,scaling=1;orderOfMagnitude<=0&&(scaling=Math.pow(10,1-orderOfMagnitude));let minHorizontalLargeTick=Math.ceil(topLeftCorner.x/divisor)*divisor,maxHorizontalLargeTick=Math.floor(topRightCorner.x/divisor)*divisor,minVerticalLargeTick=alignCoordinateSystem?Math.ceil(topLeftCorner.y/divisor)*divisor:Math.floor(bottomLeftCorner.y/divisor)*divisor;alignCoordinateSystem?Math.floor(bottomLeftCorner.y/divisor):Math.ceil(topLeftCorner.y/divisor);let minHorizontalMediumTick=Math.ceil(topLeftCorner.x/halfDivisor)*halfDivisor,maxHorizontalMediumTick=Math.floor(topRightCorner.x/halfDivisor)*halfDivisor,minVerticalMediumTick=alignCoordinateSystem?Math.ceil(topLeftCorner.y/halfDivisor)*halfDivisor:Math.floor(bottomLeftCorner.y/halfDivisor)*halfDivisor,maxVerticalMediumTick=alignCoordinateSystem?Math.floor(bottomLeftCorner.y/halfDivisor)*halfDivisor:Math.ceil(topLeftCorner.y/halfDivisor)*halfDivisor,minHorizontalSmallTick=Math.ceil(topLeftCorner.x/subDivisor)*subDivisor,maxHorizontalSmallTick=Math.floor(topRightCorner.x/subDivisor)*subDivisor,minVerticalSmallTick=alignCoordinateSystem?Math.ceil(topLeftCorner.y/subDivisor)*subDivisor:Math.floor(bottomLeftCorner.y/subDivisor)*subDivisor,maxVerticalSmallTick=alignCoordinateSystem?Math.floor(bottomLeftCorner.y/subDivisor)*subDivisor:Math.ceil(topLeftCorner.y/subDivisor)*subDivisor,halfDivisorInActualPixel=halfDivisor*cameraZoomLevel,subDivisorInActualPixel=subDivisor*cameraZoomLevel;context.font=`bold ${20/cameraZoomLevel}px Helvetica`;const midBaseLineTextDimensions=context.measureText(""+-(halfDivisor+minHorizontalMediumTick)),midBaseLineHeight=midBaseLineTextDimensions.fontBoundingBoxAscent+midBaseLineTextDimensions.fontBoundingBoxDescent,subBaseLineTextDimensions=context.measureText(""+-(subDivisor+minHorizontalSmallTick)),subBaseLineHeight=subBaseLineTextDimensions.fontBoundingBoxAscent+subBaseLineTextDimensions.fontBoundingBoxDescent,largeHorizontalStep=Math.ceil((maxHorizontalLargeTick-minHorizontalLargeTick)/divisor);for(let index=0;index<=largeHorizontalStep;index++){const i=minHorizontalLargeTick+index*divisor;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=5/cameraZoomLevel;let resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,50/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,-50/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.textAlign="center",context.textBaseline="middle",context.font=`bold ${20/cameraZoomLevel}px Helvetica`;const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`),height=textDimensions.fontBoundingBoxAscent+textDimensions.fontBoundingBoxDescent;alignCoordinateSystem?(resPoint=PointCal.addVector(resPoint,{x:0,y:height/2+.2*height}),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y)):(resPoint=PointCal.addVector(resPoint,{x:0,y:-height/2-.2*height}),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,-resPoint.y)),context.stroke()}const largeVerticalStep=Math.ceil((maxHorizontalLargeTick-minHorizontalLargeTick)/divisor);for(let index=0;index<=largeVerticalStep;index++){const i=minVerticalLargeTick+index*divisor;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=5/cameraZoomLevel;let resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,-50/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,50/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.textAlign="center",context.textBaseline="middle",context.font=`bold ${20/cameraZoomLevel}px Helvetica`;const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`);resPoint=PointCal.addVector(resPoint,{x:textDimensions.width/2+.3*textDimensions.width,y:0}),alignCoordinateSystem?context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y):context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,-resPoint.y),context.stroke()}const mediumHorizontalStep=Math.ceil((maxHorizontalMediumTick-minHorizontalMediumTick)/halfDivisor);for(let index=0;index<=mediumHorizontalStep;index++){const i=minHorizontalMediumTick+index*halfDivisor;if(Math.floor(i*scaling)%Math.floor(divisor*scaling)==0)continue;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=3/cameraZoomLevel;let resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,25/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,-25/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.font=15/cameraZoomLevel+"px Helvetica";const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`);if(halfDivisorInActualPixel>2*midBaseLineTextDimensions.width){context.textAlign="center",context.textBaseline="middle";const height=textDimensions.fontBoundingBoxAscent+textDimensions.fontBoundingBoxDescent;alignCoordinateSystem?resPoint=PointCal.addVector(resPoint,{x:0,y:height/2+.2*height}):(resPoint=PointCal.addVector(resPoint,{x:0,y:-height/2-.2*height}),resPoint=PointCal.flipYAxis(resPoint)),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y)}context.stroke()}const mediumVerticalStep=Math.ceil((maxVerticalMediumTick-minVerticalMediumTick)/halfDivisor);for(let index=0;index<=mediumVerticalStep;index++){const i=minVerticalMediumTick+index*halfDivisor;if(Math.floor(i*scaling)%Math.floor(divisor*scaling)==0)continue;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=3/cameraZoomLevel;let resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,-25/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,25/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.font=18/cameraZoomLevel+"px Helvetica";const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`);textDimensions.fontBoundingBoxAscent,textDimensions.fontBoundingBoxDescent,halfDivisorInActualPixel>2*midBaseLineHeight&&(context.textAlign="center",context.textBaseline="middle",resPoint=PointCal.addVector(resPoint,{x:textDimensions.width/2+.3*textDimensions.width,y:0}),alignCoordinateSystem||(resPoint=PointCal.flipYAxis(resPoint)),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y)),context.stroke()}const smallHorizontalStep=Math.ceil((maxHorizontalSmallTick-minHorizontalSmallTick)/subDivisor);for(let index=0;index<=smallHorizontalStep;index++){const i=minHorizontalSmallTick+index*subDivisor;if(Math.floor(i*scaling)%Math.floor(divisor*scaling)==0||Math.floor(i*scaling)%Math.floor(halfDivisor*scaling)==0)continue;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=1/cameraZoomLevel;let resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,12.5/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:i,y:topLeftCorner.y},PointCal.multiplyVectorByScalar(topDownDirection,-12.5/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.font=10/cameraZoomLevel+"px Helvetica";const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`);if(subDivisorInActualPixel>2*subBaseLineTextDimensions.width){context.textAlign="center",context.textBaseline="middle";const height=textDimensions.fontBoundingBoxAscent+textDimensions.fontBoundingBoxDescent;alignCoordinateSystem?resPoint=PointCal.addVector(resPoint,{x:0,y:height/2+.2*height}):(resPoint=PointCal.addVector(resPoint,{x:0,y:-height/2-.2*height}),resPoint=PointCal.flipYAxis(resPoint)),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y)}context.stroke()}const smallVerticalStep=Math.ceil((maxVerticalSmallTick-minVerticalSmallTick)/subDivisor);for(let index=0;index<=smallVerticalStep;index++){const i=minVerticalSmallTick+index*subDivisor;if(Math.floor(i*scaling)%Math.floor(divisor*scaling)==0||Math.floor(i*scaling)%Math.floor(halfDivisor*scaling)==0)continue;context.beginPath(),context.strokeStyle="black",context.fillStyle="black",context.lineWidth=1/cameraZoomLevel;let resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,-12.5/cameraZoomLevel));alignCoordinateSystem?context.moveTo(resPoint.x,resPoint.y):context.moveTo(resPoint.x,-resPoint.y),resPoint=PointCal.addVector({x:topLeftCorner.x,y:i},PointCal.multiplyVectorByScalar(leftRightDirection,12.5/cameraZoomLevel)),alignCoordinateSystem?context.lineTo(resPoint.x,resPoint.y):context.lineTo(resPoint.x,-resPoint.y),context.font=12/cameraZoomLevel+"px Helvetica";const textDimensions=context.measureText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`);textDimensions.fontBoundingBoxAscent,textDimensions.fontBoundingBoxDescent,subDivisorInActualPixel>2*subBaseLineHeight&&(context.textAlign="center",context.textBaseline="middle",resPoint=PointCal.addVector(resPoint,{x:textDimensions.width/2+.3*textDimensions.width,y:0}),alignCoordinateSystem||(resPoint=PointCal.flipYAxis(resPoint)),context.fillText(`${Math.abs(i)%1==0?i.toFixed(0):i.toFixed(2)}`,resPoint.x,resPoint.y)),context.stroke()}}function drawPositionText(context,pos,cameraZoomLevel,alignCoordinateSystem,offset=20,color="red"){offset/=cameraZoomLevel,context.font=20/cameraZoomLevel+"px Arial",context.fillStyle=color,alignCoordinateSystem?context.fillText(`x: ${pos.x.toFixed(2)}, y: ${pos.y.toFixed(2)}`,pos.x+offset,pos.y+offset):context.fillText(`x: ${pos.x.toFixed(2)}, y: ${pos.y.toFixed(2)}`,pos.x+offset,-pos.y-offset),context.fillStyle="black"}function drawReferenceCircle(context,pos,alignCoordinateSystem){context.beginPath(),context.strokeStyle="rgba(87, 173, 72, 0.8)",alignCoordinateSystem?context.arc(pos.x,pos.y,5,0,2*Math.PI):context.arc(pos.x,-pos.y,5,0,2*Math.PI),context.stroke(),context.strokeStyle="black"}class CanvasPositionDimensionPublisher{constructor(canvas){this._observers=new Observable,this.lastRect=canvas.getBoundingClientRect(),this.resizeObserver=new ResizeObserver((entries=>{for(const entry of entries){const trueRect=getTrueRect(entry.target.getBoundingClientRect(),window.getComputedStyle(entry.target));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}})),this.intersectionObserver=new IntersectionObserver((entries=>{for(const entry of entries)if(entry.isIntersecting){const trueRect=getTrueRect(entry.boundingClientRect,window.getComputedStyle(entry.target));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}})),this.scrollHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeObserver.observe(canvas),this.intersectionObserver.observe(canvas),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),window.addEventListener("resize",this.resizeHandler,{passive:!0})}dispose(){this.resizeObserver.disconnect(),this.intersectionObserver.disconnect(),window.removeEventListener("scroll",this.scrollHandler),window.removeEventListener("resize",this.resizeHandler)}attach(canvas){this.dispose(),this.resizeObserver.observe(canvas),this.intersectionObserver.observe(canvas),this.scrollHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),this.resizeHandler=(()=>{const trueRect=getTrueRect(canvas.getBoundingClientRect(),window.getComputedStyle(canvas));rectChanged(this.lastRect,trueRect)&&(this.publishPositionUpdate(trueRect),this.lastRect=trueRect)}).bind(this),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),window.addEventListener("resize",this.resizeHandler,{passive:!0})}publishPositionUpdate(rect){this._observers.notify(rect)}onPositionUpdate(observer,options){this._observers.subscribe(observer,options)}}function getTrueRect(rect,computedStyle){const paddingLeft=parseFloat(computedStyle.paddingLeft),paddingTop=parseFloat(computedStyle.paddingTop),paddingRight=parseFloat(computedStyle.paddingRight),paddingBottom=parseFloat(computedStyle.paddingBottom),borderLeft=parseFloat(computedStyle.borderLeftWidth),borderTop=parseFloat(computedStyle.borderTopWidth),borderRight=parseFloat(computedStyle.borderRightWidth),borderBottom=parseFloat(computedStyle.borderBottomWidth),trueLeft=rect.left+paddingLeft+borderLeft,trueTop=rect.top+paddingTop+borderTop,trueWidth=rect.width-paddingLeft-paddingRight-borderLeft-borderRight,trueHeight=rect.height-paddingTop-paddingBottom-borderTop-borderBottom;return new DOMRect(trueLeft,trueTop,trueWidth,trueHeight)}function rectChanged(r1,r2){return r1.top!==r2.top||r1.left!==r2.left||r1.width!==r2.width||r1.height!==r2.height}const methodsToFlip={fillRect:[1],strokeRect:[1],fillText:[2],strokeText:[1],lineTo:[1],moveTo:[1],quadraticCurveTo:[1,3],bezierCurveTo:[1,3,5],arc:[1],drawImage:[2],rect:[1],roundRect:[1]};function reverseYAxis(context){return new Proxy(context,{get(target,prop,receiver){const value=Reflect.get(target,prop,target);return"string"==typeof prop&&prop in methodsToFlip&&"function"==typeof value?function(...args){const newArgs=[...args];if("drawImage"===prop&&9===args.length){const convertedArgs=invertYAxisForDrawImageWith9Args(args);return value.apply(target,convertedArgs)}{const yIndices=methodsToFlip[prop];for(const index of yIndices)index<newArgs.length&&(newArgs[index]=-newArgs[index]);"drawImage"===prop&&5===args.length&&(newArgs[2]-=newArgs[4])}return value.apply(target,newArgs)}:"function"==typeof value?function(...args){return value.apply(target,args)}:value},set:(target,prop,value)=>Reflect.set(target,prop,value)})}function invertYAxisForDrawImageWith9Args(args){if(9!==args.length)return args;const newArgs=[...args],imageHeight=args[0].height;return void 0!==imageHeight&&(newArgs[2]=imageHeight-newArgs[2],newArgs[6]=-newArgs[6],newArgs[6]-=newArgs[8],newArgs[4]=-newArgs[4]),newArgs}export{CanvasPositionDimensionPublisher,drawAxis,drawBoundingBox,drawCrossHair,drawGrid,drawPositionText,drawReferenceCircle,drawRulerLegacy,getTrueRect,invertYAxisForDrawImageWith9Args,minZoomLevelBaseOnDimensions,minZoomLevelBaseOnHeight,minZoomLevelBaseOnWidth,reverseYAxis,zoomLevelBoundariesShouldUpdate};
//# sourceMappingURL=index.js.map