ue-too
Version:
pan, zoom, and rotate your html canvas
3 lines (2 loc) • 12.8 kB
JavaScript
import{PointCal}from"point2point";function isValidZoomLevelLimits(zoomLevelLimits){return void 0===zoomLevelLimits||!(void 0!==zoomLevelLimits.min&&void 0!==zoomLevelLimits.max&&zoomLevelLimits.min>zoomLevelLimits.max)}function clampZoomLevel(zoomLevel,zoomLevelLimits){return zoomLevelWithinLimits(zoomLevel,zoomLevelLimits)||void 0===zoomLevelLimits||(zoomLevelLimits.max&&(zoomLevel=Math.min(zoomLevelLimits.max,zoomLevel)),zoomLevelLimits.min&&(zoomLevel=Math.max(zoomLevelLimits.min,zoomLevel))),zoomLevel}function zoomLevelWithinLimits(zoomLevel,zoomLevelLimits){return void 0===zoomLevelLimits||!(zoomLevel<=0||void 0!==zoomLevelLimits&&(void 0!==zoomLevelLimits.max&&zoomLevelLimits.max<zoomLevel||void 0!==zoomLevelLimits.min&&zoomLevelLimits.min>zoomLevel))}function decomposeCameraMatrix(transformMatrix,devicePixelRatio,canvasWidth,canvasHeight){const a=transformMatrix.a,b=transformMatrix.b;transformMatrix.c,transformMatrix.d;const tx=transformMatrix.e,ty=transformMatrix.f,rotation=-Math.atan2(b,a),zoom=Math.sqrt(a*a+b*b)/devicePixelRatio;let reverse=[tx,ty];reverse=[reverse[0]/devicePixelRatio,reverse[1]/devicePixelRatio],reverse=[reverse[0]-canvasWidth/2,reverse[1]-canvasHeight/2];const cos_r=Math.cos(rotation),sin_r=Math.sin(rotation);reverse=[cos_r*reverse[0]-sin_r*reverse[1],sin_r*reverse[0]+cos_r*reverse[1]],reverse=[reverse[0]/zoom,reverse[1]/zoom];return{position:{x:-reverse[0],y:-reverse[1]},zoom:zoom,rotation:rotation}}function createCameraMatrix(cameraPos,zoom,rotation,devicePixelRatio,canvasWidth,canvasHeight){const multipliedMatrix=multiplyMatrix({a:devicePixelRatio,b:0,c:0,d:devicePixelRatio,e:0,f:0},{a:1,b:0,c:0,d:1,e:canvasWidth/2,f:canvasHeight/2}),cos_r=Math.cos(-rotation),sin_r=Math.sin(-rotation),rotatedMatrix=multiplyMatrix(multipliedMatrix,{a:cos_r,b:sin_r,c:-sin_r,d:cos_r,e:0,f:0}),zoomedMatrix=multiplyMatrix(rotatedMatrix,{a:zoom,b:0,c:0,d:zoom,e:0,f:0});return multiplyMatrix(zoomedMatrix,{a:1,b:0,c:0,d:1,e:-cameraPos.x,f:-cameraPos.y})}function multiplyMatrix(m1,m2){const a1=m1.a,b1=m1.b,c1=m1.c,d1=m1.d,tx1=m1.e,ty1=m1.f,a2=m2.a,b2=m2.b,c2=m2.c,d2=m2.d,tx2=m2.e,ty2=m2.f;return{a:a1*a2+c1*b2,b:b1*a2+d1*b2,c:a1*c2+c1*d2,d:b1*c2+d1*d2,e:a1*tx2+c1*ty2+tx1,f:b1*tx2+d1*ty2+ty1}}function convert2WorldSpaceWRT(targetPosition,interestPoint,viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation){let cameraFrameCenter={x:viewPortWidth/2,y:viewPortHeight/2},delta2Point=PointCal.subVector(interestPoint,cameraFrameCenter);return delta2Point=PointCal.multiplyVectorByScalar(delta2Point,1/cameraZoomLevel),delta2Point=PointCal.rotatePoint(delta2Point,cameraRotation),PointCal.addVector(targetPosition,delta2Point)}function convert2WorldSpace(point,viewPortWidth,viewPortHeight,cameraPosition,cameraZoomLevel,cameraRotation){let cameraFrameCenter={x:viewPortWidth/2,y:viewPortHeight/2},delta2Point=PointCal.subVector(point,cameraFrameCenter);return delta2Point=PointCal.multiplyVectorByScalar(delta2Point,1/cameraZoomLevel),delta2Point=PointCal.rotatePoint(delta2Point,cameraRotation),PointCal.addVector(cameraPosition,delta2Point)}function convert2WorldSpaceAnchorAtCenter(point,cameraPosition,cameraZoomLevel,cameraRotation){const scaledBack=PointCal.multiplyVectorByScalar(point,1/cameraZoomLevel),rotatedBack=PointCal.rotatePoint(scaledBack,cameraRotation);return PointCal.addVector(rotatedBack,cameraPosition)}function convert2ViewPortSpaceAnchorAtCenter(point,cameraPosition,cameraZoomLevel,cameraRotation){const withOffset=PointCal.subVector(point,cameraPosition),scaled=PointCal.multiplyVectorByScalar(withOffset,cameraZoomLevel);return PointCal.rotatePoint(scaled,-cameraRotation)}function invertFromWorldSpace(point,viewPortWidth,viewPortHeight,cameraPosition,cameraZoomLevel,cameraRotation){let cameraFrameCenter={x:viewPortWidth/2,y:viewPortHeight/2},delta2Point=PointCal.subVector(point,cameraPosition);return delta2Point=PointCal.rotatePoint(delta2Point,-cameraRotation),delta2Point=PointCal.multiplyVectorByScalar(delta2Point,cameraZoomLevel),PointCal.addVector(cameraFrameCenter,delta2Point)}function pointIsInViewPort(point,viewPortWidth,viewPortHeight,cameraPosition,cameraZoomLevel,cameraRotation){const pointInCameraFrame=invertFromWorldSpace(point,viewPortWidth,viewPortHeight,cameraPosition,cameraZoomLevel,cameraRotation);return!(pointInCameraFrame.x<0||pointInCameraFrame.x>viewPortWidth||pointInCameraFrame.y<0||pointInCameraFrame.y>viewPortHeight)}function convertDeltaInViewPortToWorldSpace(delta,cameraZoomLevel,cameraRotation){return PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta,cameraRotation),1/cameraZoomLevel)}function convertDeltaInWorldToViewPortSpace(delta,cameraZoomLevel,cameraRotation){return PointCal.multiplyVectorByScalar(PointCal.rotatePoint(delta,-cameraRotation),cameraZoomLevel)}function cameraPositionToGet(pointInWorld,toPointInViewPort,cameraZoomLevel,cameraRotation){const scaled=PointCal.multiplyVectorByScalar(toPointInViewPort,1/cameraZoomLevel),rotated=PointCal.rotatePoint(scaled,cameraRotation);return PointCal.subVector(pointInWorld,rotated)}function transformationMatrixFromCamera(cameraPosition,cameraZoomLevel,cameraRotation){const cos=Math.cos(cameraRotation),sin=Math.sin(cameraRotation),trMatrix=multiplyMatrix({a:1,b:0,c:0,d:1,e:cameraPosition.x,f:cameraPosition.y},{a:cos,b:sin,c:-sin,d:cos,e:0,f:0});return multiplyMatrix(trMatrix,{a:1/cameraZoomLevel,b:0,c:0,d:1/cameraZoomLevel,e:0,f:0})}function convert2WorldSpaceWithTransformationMatrix(point,transformationMatrix){return{x:point.x*transformationMatrix.a+point.y*transformationMatrix.c+transformationMatrix.e,y:point.x*transformationMatrix.b+point.y*transformationMatrix.d+transformationMatrix.f}}function withinBoundaries(point,boundaries){if(null==boundaries)return!0;let leftSide=!1,rightSide=!1,topSide=!1,bottomSide=!1;return(null==boundaries.max||null==boundaries.max.x||point.x<=boundaries.max.x)&&(rightSide=!0),(null==boundaries.min||null==boundaries.min.x||point.x>=boundaries.min.x)&&(leftSide=!0),(null==boundaries.max||null==boundaries.max.y||point.y<=boundaries.max.y)&&(topSide=!0),(null==boundaries.min||null==boundaries.min.y||point.y>=boundaries.min.y)&&(bottomSide=!0),leftSide&&rightSide&&topSide&&bottomSide}function isValidBoundaries(boundaries){var _a,_b,_c,_d;if(null==boundaries)return!0;const minX=null===(_a=boundaries.min)||void 0===_a?void 0:_a.x,maxX=null===(_b=boundaries.max)||void 0===_b?void 0:_b.x;if(null!=minX&&null!=maxX&&minX>=maxX)return!1;const minY=null===(_c=boundaries.min)||void 0===_c?void 0:_c.y,maxY=null===(_d=boundaries.max)||void 0===_d?void 0:_d.y;return!(null!=minY&&null!=maxY&&minY>=maxY)}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 clampPoint(point,boundaries){if(withinBoundaries(point,boundaries)||null==boundaries)return point;let manipulatePoint={x:point.x,y:point.y},limit=boundaries.min;return null!=limit&&(null!=limit.x&&(manipulatePoint.x=Math.max(manipulatePoint.x,limit.x)),null!=limit.y&&(manipulatePoint.y=Math.max(manipulatePoint.y,limit.y))),limit=boundaries.max,null!=limit&&(null!=limit.x&&(manipulatePoint.x=Math.min(manipulatePoint.x,limit.x)),null!=limit.y&&(manipulatePoint.y=Math.min(manipulatePoint.y,limit.y))),manipulatePoint}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 halfTranslationWidthOf(boundaries){const translationWidth=translationWidthOf(boundaries);return null!=translationWidth?translationWidth/2:void 0}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 halfTranslationHeightOf(boundaries){const translationHeight=translationHeightOf(boundaries);return null!=translationHeight?translationHeight/2:void 0}function clampPointEntireViewPort(point,viewPortWidth,viewPortHeight,boundaries,cameraZoomLevel,cameraRotation){if(null==boundaries)return point;let topLeftCorner=convert2WorldSpaceWRT(point,{x:0,y:viewPortHeight},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),bottomLeftCorner=convert2WorldSpaceWRT(point,{x:0,y:0},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),topRightCorner=convert2WorldSpaceWRT(point,{x:viewPortWidth,y:viewPortHeight},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),bottomRightCorner=convert2WorldSpaceWRT(point,{x:viewPortWidth,y:0},viewPortWidth,viewPortHeight,cameraZoomLevel,cameraRotation),topLeftCornerClamped=clampPoint(topLeftCorner,boundaries),topRightCornerClamped=clampPoint(topRightCorner,boundaries),bottomLeftCornerClamped=clampPoint(bottomLeftCorner,boundaries),bottomRightCornerClamped=clampPoint(bottomRightCorner,boundaries),diffs=[PointCal.subVector(topLeftCornerClamped,topLeftCorner),PointCal.subVector(topRightCornerClamped,topRightCorner),PointCal.subVector(bottomLeftCornerClamped,bottomLeftCorner),PointCal.subVector(bottomRightCornerClamped,bottomRightCorner)],maxXDiff=Math.abs(diffs[0].x),maxYDiff=Math.abs(diffs[0].y),delta=diffs[0];return diffs.forEach((diff=>{Math.abs(diff.x)>maxXDiff&&(maxXDiff=Math.abs(diff.x),delta.x=diff.x),Math.abs(diff.y)>maxYDiff&&(maxYDiff=Math.abs(diff.y),delta.y=diff.y)})),PointCal.addVector(point,delta)}function clampRotation(rotation,rotationLimits){if(rotationWithinLimits(rotation,rotationLimits)||void 0===rotationLimits)return rotation;rotation=normalizeAngleZero2TwoPI(rotation);const angleSpanFromStart=angleSpan(rotationLimits.start,rotation),angleSpanFromEnd=angleSpan(rotationLimits.end,rotation);if(rotationLimits.ccw&&(angleSpanFromStart<0||angleSpanFromEnd>0)||!rotationLimits.ccw&&(angleSpanFromStart>0||angleSpanFromEnd<0)){if(Math.abs(angleSpanFromStart)===Math.abs(angleSpanFromEnd))return rotationLimits.startAsTieBreaker?rotationLimits.start:rotationLimits.end;return Math.abs(angleSpanFromStart)<Math.abs(angleSpanFromEnd)?rotationLimits.start:rotationLimits.end}return rotation}function rotationWithinLimits(rotation,rotationLimits){if(void 0===rotationLimits)return!0;if(normalizeAngleZero2TwoPI(rotationLimits.start)===normalizeAngleZero2TwoPI(rotationLimits.end))return!0;if(normalizeAngleZero2TwoPI(rotationLimits.start+.01)===normalizeAngleZero2TwoPI(rotationLimits.end+.01))return!0;const normalizedRotation=normalizeAngleZero2TwoPI(rotation),angleSpanFromStart=angleSpan(rotationLimits.start,normalizedRotation),angleSpanFromEnd=angleSpan(rotationLimits.end,normalizedRotation);return!(rotationLimits.ccw&&(angleSpanFromStart<0||angleSpanFromEnd>0)||!rotationLimits.ccw&&(angleSpanFromStart>0||angleSpanFromEnd<0))}function rotationWithinBoundary(rotation,rotationBoundary){if(normalizeAngleZero2TwoPI(rotationBoundary.start)===normalizeAngleZero2TwoPI(rotationBoundary.end))return!0;if(normalizeAngleZero2TwoPI(rotationBoundary.start+.01)===normalizeAngleZero2TwoPI(rotationBoundary.end+.01))return!0;let angleFromStart=normalizeAngleZero2TwoPI(rotation)-normalizeAngleZero2TwoPI(rotationBoundary.start);angleFromStart<0&&(angleFromStart+=2*Math.PI),!rotationBoundary.positiveDirection&&angleFromStart>0&&(angleFromStart=2*Math.PI-angleFromStart);let angleRange=normalizeAngleZero2TwoPI(rotationBoundary.end)-normalizeAngleZero2TwoPI(rotationBoundary.start);return angleRange<0&&(angleRange+=2*Math.PI),!rotationBoundary.positiveDirection&&angleRange>0&&(angleRange=2*Math.PI-angleRange),angleRange>=angleFromStart}function normalizeAngleZero2TwoPI(angle){return angle=((angle%=2*Math.PI)+2*Math.PI)%(2*Math.PI)}function angleSpan(from,to){from=normalizeAngleZero2TwoPI(from);let angleDiff=(to=normalizeAngleZero2TwoPI(to))-from;return angleDiff>Math.PI&&(angleDiff=-(2*Math.PI-angleDiff)),angleDiff<-Math.PI&&(angleDiff+=2*Math.PI),angleDiff}function deg2rad(deg){return deg*Math.PI/180}function rad2deg(rad){return 180*rad/Math.PI}export{angleSpan,boundariesFullyDefined,cameraPositionToGet,clampPoint,clampPointEntireViewPort,clampRotation,clampZoomLevel,convert2ViewPortSpaceAnchorAtCenter,convert2WorldSpace,convert2WorldSpaceAnchorAtCenter,convert2WorldSpaceWRT,convert2WorldSpaceWithTransformationMatrix,convertDeltaInViewPortToWorldSpace,convertDeltaInWorldToViewPortSpace,createCameraMatrix,decomposeCameraMatrix,deg2rad,halfTranslationHeightOf,halfTranslationWidthOf,invertFromWorldSpace,isValidBoundaries,isValidZoomLevelLimits,multiplyMatrix,normalizeAngleZero2TwoPI,pointIsInViewPort,rad2deg,rotationWithinBoundary,rotationWithinLimits,transformationMatrixFromCamera,translationHeightOf,translationWidthOf,withinBoundaries,zoomLevelWithinLimits};
//# sourceMappingURL=index.js.map