/*! circlepacker v2.1.0 | MIT (c) 2024 Georg Fischer | https://github.com/snorpey/circlepacker#readme */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).circlepacker=t()}(this,(function(){"use strict";class e{constructor(e,t){"object"==typeof e?(this.x=e.x,this.y=e.y):(this.x=e,this.y=t)}cp(){return new e(this.x,this.y)}mul(e){return this.x*=e,this.y*=e,this}normalize(){var e=this.length();return this.x/=e,this.y/=e,this}length(){var e=Math.sqrt(this.x*this.x+this.y*this.y);return e<.005&&e>-.005?1e-6:e}distance(e){var t=this.x-e.x,i=this.y-e.y;return Math.sqrt(t*t+i*i)}distanceSquared(e){var t=this.x-e.x,i=this.y-e.y;return t*t+i*i}}class t{constructor({id:t,radius:i,x:s,y:r,isPulledToTarget:o,isPinned:n}){s=s||0,r=r||0,this.id=t,this.targetPosition=new e(0,0),this.position=new e(s,r),this.previousPosition=new e(s,r),this.isPulledToTarget=o,this.isPinned=n,this.setRadius(i)}setPosition(e){this.previousPosition=this.position,this.position=e.cp()}setRadius(e){this.radius=e,this.radiusSquared=e*e}get delta(){return new e(this.position.x-this.previousPosition.x,this.position.y-this.previousPosition.y)}}function i(e){return e&&"object"==typeof e&&null!==e&&r(e.id)&&e.radius&&(e.position&&"number"==typeof e.position.x&&"number"==typeof e.position.y||"number"==typeof e.x&&"number"==typeof e.y)}function s(e){return!!(e.point1&&e.point2&&n(e.point1)&&n(e.point2))||("number"==typeof e.width&&"number"==typeof e.height||("number"==typeof e.left&&"number"==typeof e.top&&"number"==typeof e.bottom&&"number"==typeof e.right||"number"==typeof e.x1&&"number"==typeof e.y1&&"number"==typeof e.x2&&"number"==typeof e.y2))}function r(e){return"number"==typeof e&&!isNaN(e)||"string"==typeof e&&e.length>0}function o(e,t){return"number"==typeof e&&e>=t}function n(e){return"object"==typeof e&&"number"==typeof e.x&&"number"==typeof e.y}class a{constructor(){this.allCircles=[],this.pinnedCircleIds=[],this.desiredTarget=void 0,this.boundsRect=void 0,this.damping=.025,this.isTargetPullActive=!0,this.calculateOverlap=!1,this.numberOfCenteringPasses=1,this.numberOfCollisionPasses=3,this.numberOfCorrectionPasses=0}setBounds(e){const t=function(e){if(!s(e))return;let t=0,i=0,r=0,o=0;return"number"==typeof e.left?(t=e.left,r=e.right,i=e.top,o=e.bottom):"number"==typeof e.width?("number"==typeof e.x&&(t=e.x),"number"==typeof e.y&&(i=e.y),r=t+e.width,o=i+e.height):"number"==typeof e.x1?(t=e.x1,r=e.x2,i=e.y1,o=e.y2):e.point1&&(t=e.point1.x,r=e.point2.x,i=e.point1.y,o=e.point2.y),{left:t,top:i,right:r,bottom:o}}(e);t&&(this.boundsRect=t)}addCircle(e){e instanceof t||(e=new t({id:e.id,radius:e.radius,x:e.position.x||e.x||0,y:e.position.y||e.y||0,isPinned:e.isPinned||!1,isPulledToTarget:"boolean"!=typeof e.isPulledToTarget||e.isPulledToTarget})),this.allCircles.push(e),this.desiredTarget&&(e.targetPosition=this.desiredTarget.cp())}removeCircle(e){this.allCircles=this.allCircles.filter((t=>t.id!==e))}updatePositions(){const e=this.allCircles,t=e.length;for(let i=0;i0)){let e=0,t=Object.keys(this.getOverlappingCircles()).length;for(;t>0&&e{this.handleBoundaryForCircle(e)}))}handleBoundaryForCircle(e){const{x:t,y:i}=e.position,s=e.radius;let r=!1;this.boundsRect&&(t+s>=this.boundsRect.right?(e.position.x=this.boundsRect.right-s,r=!0):t-sthis.boundsRect.bottom?(e.position.y=this.boundsRect.bottom-s,r=!0):i-s{const s=this.allCircles.filter((e=>i.id!==e.id)).map((t=>{const s=new e(i.position).distance(t.position),r=se.overlapDistance>0));s.length&&(t[i.id]=s)})),t}getPositions(){return this.allCircles.reduce(((e,t)=>(e[t.id]={id:t.id,position:t.position,previousPosition:t.previousPosition,radius:t.radius,delta:t.delta,isPulledToTarget:t.isPulledToTarget,isPinned:t.isPinned},e)),{})}setDraggedCircle(e){this.draggedCircle=e}dragStart(e){const t=this.allCircles.filter((t=>t.id===e))[0];this.setDraggedCircle(t)}dragEnd(){this.draggedCircle&&(this.draggedCircle=null)}drag(e,t){this.draggedCircle&&t&&(this.draggedCircle.position.x=t.x,this.draggedCircle.position.y=t.y)}isCirclePinned(e){const t=this.circleById(e);return!!t&&t.isPinned}pinCircle(e){const t=this.circleById(e);t&&(t.isPinned=!0)}unpinCircle(e){const t=this.circleById(e);t&&(t.isPinned=!1)}setCircleRadius(e,t){const i=this.circleById(e);i&&i.setRadius(t)}setCircleTargetPull(e,t){const i=this.circleById(e);i&&(i.isPulledToTarget=t)}setTargetPull(e){this.isTargetPullActive=e}circleById(e){return this.allCircles.filter((t=>t.id===e))[0]}setTarget(e){this.desiredTarget=e}setCalculateOverlap(e){this.calculateOverlap=e}}class l{constructor(){this.circleManager=new a}handleWorkerMessage(e,t){if(e){const{action:i}=e;switch(i.type){case"SET_BOUNDS":this.circleManager.setBounds(i.bounds);break;case"SET_CENTERING_PASSES":this.circleManager.numberOfCenteringPasses=i.numberOfCenteringPasses;break;case"SET_COLLISION_PASSES":this.circleManager.numberOfCollisionPasses=i.numberOfCollisionPasses;break;case"SET_CORRECTION_PASSES":this.circleManager.numberOfCorrectionPasses=i.numberOfCorrectionPasses;break;case"SET_DAMPING":this.circleManager.damping=i.damping;break;case"SET_TARGET_PULL":this.circleManager.setTargetPull(i.targetPull);break;case"UPDATE":this.update(),this.sendPositions(t);break;case"ADD_CIRCLES":this.addCircles(i.circles);break;case"REMOVE_CIRCLE":this.circleManager.removeCircle(i.id);break;case"DRAG_START":this.circleManager.dragStart(i.id);break;case"DRAG_END":this.circleManager.dragEnd(i.id);break;case"DRAG_MOVE":this.circleManager.drag(i.id,i.position);break;case"SET_CIRCLE_RADIUS":this.circleManager.setCircleRadius(i.id,i.radius);break;case"SET_CIRCLE_TARGET_PULL":this.circleManager.setCircleTargetPull(i.id,i.targetPull);break;case"SET_CALCULATE_OVERLAP":this.circleManager.setCalculateOverlap(i.calculateOverlap);break;case"PIN_CIRCLE":this.circleManager.pinCircle(i.id);break;case"UNPIN_CIRCLE":this.circleManager.unpinCircle(i.id);break;case"SET_TARGET":this.setTarget(i.target)}}}addCircles(e){if(!Array.isArray(e)||!e.length)throw new Error("Circles array is malformed.");e.forEach((e=>this.circleManager.addCircle(e)))}setTarget(t){t&&"number"==typeof t.x&&"number"==typeof t.y&&this.circleManager.setTarget(new e(t))}update(){this.circleManager.updatePositions()}sendPositions(e){if(e){const t={type:"MOVED",updatedCircles:this.circleManager.getPositions(),target:this.circleManager.desiredTarget};this.circleManager.calculateOverlap&&(t.overlappingCircles=this.circleManager.getOverlappingCircles()),e(t)}}}class c{constructor(e={}){this.isAnimationLoopActive="boolean"==typeof e.animationLoop&&e.animationLoop,this.onMoveStart=e.onMoveStart||null,this.onMoveEnd=e.onMoveEnd||null,this.isLooping=!1,this.areItemsMoving=!1,this.animationFrameId=NaN}handleWorkerResponse(e){if("MOVED"===e.type){const t=e.updatedCircles;this.areItemsMoving=this.hasItemMoved(t),!this.areItemsMoving&&this.isLooping&&this.isAnimationLoopActive&&this.stopLoop()}}forceMovement(){this.isAnimationLoopActive&&(this.areItemsMoving=!0)}updateListeners(e){"MOVE_START"===e.type&&"function"==typeof this.onMoveStart&&this.onMoveStart(),"MOVE_END"===e.type&&"function"==typeof this.onMoveEnd&&this.onMoveEnd(e.updatedCircles)}updateLoop(){this.update(),this.isLooping&&(this.areItemsMoving?this.animationFrameId=requestAnimationFrame((()=>this.updateLoop())):this.stopLoop())}startLoop(){!this.isLooping&&this.isAnimationLoopActive&&(this.isLooping=!0,this.updateListeners({type:"MOVE_START"}),this.animationFrameId=requestAnimationFrame((()=>this.updateLoop())))}stopLoop(){this.isLooping&&(this.isLooping=!1,this.updateListeners({type:"MOVE_END",updatedCircles:this.lastCirclePositions}),cancelAnimationFrame(this.animationFrameId))}hasItemMoved(e){let t=!1;for(let i in e)(Math.abs(e[i].delta.x)>.005||Math.abs(e[i].delta.y)>.005)&&(t=!0);return t}destroy(){this.stopLoop(),this.onMoveStart=null,this.onMoveEnd=null}}class d extends c{constructor(e={}){if(super(e),this.useWorker=!e.noWorker,this.destroyAfterOneMove=!!e.destroyAfterOneMove,this.useWorker){if(!Worker)throw new Error("Web workers are not supported.");this.worker=new Worker(URL.createObjectURL(new Blob(["!function(i){\"function\"==typeof define&&define.amd?define(i):i()}((function(){\"use strict\";class i{constructor(i,e){\"object\"==typeof i?(this.x=i.x,this.y=i.y):(this.x=i,this.y=e)}cp(){return new i(this.x,this.y)}mul(i){return this.x*=i,this.y*=i,this}normalize(){var i=this.length();return this.x/=i,this.y/=i,this}length(){var i=Math.sqrt(this.x*this.x+this.y*this.y);return i<.005&&i>-.005?1e-6:i}distance(i){var e=this.x-i.x,t=this.y-i.y;return Math.sqrt(e*e+t*t)}distanceSquared(i){var e=this.x-i.x,t=this.y-i.y;return e*e+t*t}}class e{constructor({id:e,radius:t,x:s,y:r,isPulledToTarget:n,isPinned:o}){s=s||0,r=r||0,this.id=e,this.targetPosition=new i(0,0),this.position=new i(s,r),this.previousPosition=new i(s,r),this.isPulledToTarget=n,this.isPinned=o,this.setRadius(t)}setPosition(i){this.previousPosition=this.position,this.position=i.cp()}setRadius(i){this.radius=i,this.radiusSquared=i*i}get delta(){return new i(this.position.x-this.previousPosition.x,this.position.y-this.previousPosition.y)}}function t(i){if(!function(i){return!!(i.point1&&i.point2&&s(i.point1)&&s(i.point2))||\"number\"==typeof i.width&&\"number\"==typeof i.height||\"number\"==typeof i.left&&\"number\"==typeof i.top&&\"number\"==typeof i.bottom&&\"number\"==typeof i.right||\"number\"==typeof i.x1&&\"number\"==typeof i.y1&&\"number\"==typeof i.x2&&\"number\"==typeof i.y2}(i))return;let e=0,t=0,r=0,n=0;return\"number\"==typeof i.left?(e=i.left,r=i.right,t=i.top,n=i.bottom):\"number\"==typeof i.width?(\"number\"==typeof i.x&&(e=i.x),\"number\"==typeof i.y&&(t=i.y),r=e+i.width,n=t+i.height):\"number\"==typeof i.x1?(e=i.x1,r=i.x2,t=i.y1,n=i.y2):i.point1&&(e=i.point1.x,r=i.point2.x,t=i.point1.y,n=i.point2.y),{left:e,top:t,right:r,bottom:n}}function s(i){return\"object\"==typeof i&&\"number\"==typeof i.x&&\"number\"==typeof i.y}class r{constructor(){this.allCircles=[],this.pinnedCircleIds=[],this.desiredTarget=void 0,this.boundsRect=void 0,this.damping=.025,this.isTargetPullActive=!0,this.calculateOverlap=!1,this.numberOfCenteringPasses=1,this.numberOfCollisionPasses=3,this.numberOfCorrectionPasses=0}setBounds(i){const e=t(i);e&&(this.boundsRect=e)}addCircle(i){i instanceof e||(i=new e({id:i.id,radius:i.radius,x:i.position.x||i.x||0,y:i.position.y||i.y||0,isPinned:i.isPinned||!1,isPulledToTarget:\"boolean\"!=typeof i.isPulledToTarget||i.isPulledToTarget})),this.allCircles.push(i),this.desiredTarget&&(i.targetPosition=this.desiredTarget.cp())}removeCircle(i){this.allCircles=this.allCircles.filter((e=>e.id!==i))}updatePositions(){const i=this.allCircles,e=i.length;for(let t=0;t0)){let i=0,e=Object.keys(this.getOverlappingCircles()).length;for(;e>0&&i{this.handleBoundaryForCircle(i)}))}handleBoundaryForCircle(i){const{x:e,y:t}=i.position,s=i.radius;let r=!1;this.boundsRect&&(e+s>=this.boundsRect.right?(i.position.x=this.boundsRect.right-s,r=!0):e-sthis.boundsRect.bottom?(i.position.y=this.boundsRect.bottom-s,r=!0):t-s{const s=this.allCircles.filter((i=>t.id!==i.id)).map((e=>{const s=new i(t.position).distance(e.position),r=si.overlapDistance>0));s.length&&(e[t.id]=s)})),e}getPositions(){return this.allCircles.reduce(((i,e)=>(i[e.id]={id:e.id,position:e.position,previousPosition:e.previousPosition,radius:e.radius,delta:e.delta,isPulledToTarget:e.isPulledToTarget,isPinned:e.isPinned},i)),{})}setDraggedCircle(i){this.draggedCircle=i}dragStart(i){const e=this.allCircles.filter((e=>e.id===i))[0];this.setDraggedCircle(e)}dragEnd(){this.draggedCircle&&(this.draggedCircle=null)}drag(i,e){this.draggedCircle&&e&&(this.draggedCircle.position.x=e.x,this.draggedCircle.position.y=e.y)}isCirclePinned(i){const e=this.circleById(i);return!!e&&e.isPinned}pinCircle(i){const e=this.circleById(i);e&&(e.isPinned=!0)}unpinCircle(i){const e=this.circleById(i);e&&(e.isPinned=!1)}setCircleRadius(i,e){const t=this.circleById(i);t&&t.setRadius(e)}setCircleTargetPull(i,e){const t=this.circleById(i);t&&(t.isPulledToTarget=e)}setTargetPull(i){this.isTargetPullActive=i}circleById(i){return this.allCircles.filter((e=>e.id===i))[0]}setTarget(i){this.desiredTarget=i}setCalculateOverlap(i){this.calculateOverlap=i}}const n=new class{constructor(){this.circleManager=new r}handleWorkerMessage(i,e){if(i){const{action:t}=i;switch(t.type){case\"SET_BOUNDS\":this.circleManager.setBounds(t.bounds);break;case\"SET_CENTERING_PASSES\":this.circleManager.numberOfCenteringPasses=t.numberOfCenteringPasses;break;case\"SET_COLLISION_PASSES\":this.circleManager.numberOfCollisionPasses=t.numberOfCollisionPasses;break;case\"SET_CORRECTION_PASSES\":this.circleManager.numberOfCorrectionPasses=t.numberOfCorrectionPasses;break;case\"SET_DAMPING\":this.circleManager.damping=t.damping;break;case\"SET_TARGET_PULL\":this.circleManager.setTargetPull(t.targetPull);break;case\"UPDATE\":this.update(),this.sendPositions(e);break;case\"ADD_CIRCLES\":this.addCircles(t.circles);break;case\"REMOVE_CIRCLE\":this.circleManager.removeCircle(t.id);break;case\"DRAG_START\":this.circleManager.dragStart(t.id);break;case\"DRAG_END\":this.circleManager.dragEnd(t.id);break;case\"DRAG_MOVE\":this.circleManager.drag(t.id,t.position);break;case\"SET_CIRCLE_RADIUS\":this.circleManager.setCircleRadius(t.id,t.radius);break;case\"SET_CIRCLE_TARGET_PULL\":this.circleManager.setCircleTargetPull(t.id,t.targetPull);break;case\"SET_CALCULATE_OVERLAP\":this.circleManager.setCalculateOverlap(t.calculateOverlap);break;case\"PIN_CIRCLE\":this.circleManager.pinCircle(t.id);break;case\"UNPIN_CIRCLE\":this.circleManager.unpinCircle(t.id);break;case\"SET_TARGET\":this.setTarget(t.target)}}}addCircles(i){if(!Array.isArray(i)||!i.length)throw new Error(\"Circles array is malformed.\");i.forEach((i=>this.circleManager.addCircle(i)))}setTarget(e){e&&\"number\"==typeof e.x&&\"number\"==typeof e.y&&this.circleManager.setTarget(new i(e))}update(){this.circleManager.updatePositions()}sendPositions(i){if(i){const e={type:\"MOVED\",updatedCircles:this.circleManager.getPositions(),target:this.circleManager.desiredTarget};this.circleManager.calculateOverlap&&(e.overlappingCircles=this.circleManager.getOverlappingCircles()),i(e)}}};function o(i){var e,t;e=self,t=i,e.postMessage(JSON.stringify(t))}self.addEventListener(\"message\",(i=>{const e=function(i){return i.data?JSON.parse(i.data):void 0}(i);n.handleWorkerMessage(e,o)}))}));\n"],{type:'text/javascript'}))),this.worker.addEventListener("message",this.receivedWorkerMessage.bind(this))}else this.workerLogic=new l;this.onMove=e.onMove||null,this.lastCirclePositions={},e.centeringPasses&&this.setCenteringPasses(e.centeringPasses),e.collisionPasses&&this.setCollisionPasses(e.collisionPasses),e.correctionPasses&&this.setCorrectionPasses(e.correctionPasses),"boolean"==typeof e.calculateOverlap&&this.setCalculateOverlap(e.calculateOverlap),e.bounds&&this.setBounds(e.bounds),e.target&&this.setTarget(e.target),e.circles&&e.circles.length&&this.addCircles(e.circles),this.isAnimationLoopActive||this.update()}receivedWorkerMessage(e){const t=function(e){return e.data?JSON.parse(e.data):void 0}(e);t&&(super.handleWorkerResponse(t),this.updateListeners(t))}updateWorker(e){const t={messageId:Date.now(),action:e};var i,s;this.useWorker?(i=this.worker,s=t,i.postMessage(JSON.stringify(s))):this.workerLogic.handleWorkerMessage(t,(e=>{super.handleWorkerResponse(e),this.updateListeners(e)}))}updateListeners(e){"MOVED"===e.type&&"function"==typeof this.onMove&&(this.lastCirclePositions=e.updatedCircles,this.onMove(e.updatedCircles,e.target,e.overlappingCircles)),super.updateListeners(e),this.destroyAfterOneMove&&this.destroy()}addCircles(e){if(!Array.isArray(e))throw new Error("Can't add circles: the circles parameter is not an array.");if(e.length){if(!e.every(i))throw new Error("Can't add circles: some of the items are not well formatted.");this.updateWorker({type:"ADD_CIRCLES",circles:e}),super.forceMovement(),super.startLoop()}}addCircle(e){this.addCircles([e])}removeCircle(e){const t="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(t))throw new Error("Can't remove circle: the circleRef parameter is malformed.");this.updateWorker({type:"REMOVE_CIRCLE",id:t}),super.startLoop()}pinCircle(e){const t="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(t))throw new Error("Can't pin circle: the circleRef parameter is malformed.");this.updateWorker({type:"PIN_CIRCLE",id:t}),super.startLoop()}unpinCircle(e){const t="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(t))throw new Error("Can't unpin circle: the circleRef parameter is malformed.");this.updateWorker({type:"UNPIN_CIRCLE",id:t}),super.startLoop()}setCircleRadius(e,t){const i="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(i))throw new Error("Can't set circle radius: the circleRef parameter is malformed.");if(!o(t,0))throw new Error("Can't set circle radius: the passed radius is malformed.");this.updateWorker({type:"SET_CIRCLE_RADIUS",id:i,radius:t}),super.startLoop()}setCircleTargetPull(e,t){const i="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(i))throw new Error("Can't set circle center pull: the circleRef parameter is malformed.");this.updateWorker({type:"SET_CIRCLE_TARGET_PULL",id:i,targetPull:!!t}),super.startLoop()}setTargetPull(e){this.updateWorker({type:"SET_TARGET_PULL",targetPull:!!e}),super.startLoop()}setBounds(e){if(!s(e))throw new Error("Can't set bounds: the bounds parameter is malformed.");this.updateWorker({type:"SET_BOUNDS",bounds:e}),super.startLoop()}setTarget(e){if(!n(e))throw new Error("Can't set target: the targetPos parameter is malformed.");this.updateWorker({type:"SET_TARGET",target:e}),super.forceMovement(),super.startLoop()}setCenteringPasses(e){if(!o(e,1))throw new Error("Can't set centering passes: the numberOfCenteringPasses parameter is malformed.");this.updateWorker({type:"SET_CENTERING_PASSES",numberOfCenteringPasses:e})}setCollisionPasses(e){if(!o(e,1))throw new Error("Can't set collisionPasses passes: the numberOfCollisionPasses parameter is malformed.");this.updateWorker({type:"SET_COLLISION_PASSES",numberOfCollisionPasses:e})}setCorrectionPasses(e){if(!o(e,0))throw new Error("Can't set CorrectionPasses passes: the numberOfCorrectionPasses parameter is malformed.");this.updateWorker({type:"SET_CORRECTION_PASSES",numberOfCorrectionPasses:e})}setCalculateOverlap(e){if("boolean"!=typeof e)throw new Error("Can't set calculateOverlap the calculateOverlap parameter is not a boolean.");this.updateWorker({type:"SET_CALCULATE_OVERLAP",calculateOverlap:e})}setDamping(e){if(!("number"==typeof e&&e>0&&e<1))throw new Error("Can't set damping: the damping parameter is malformed.");this.updateWorker({type:"SET_DAMPING",damping:e})}update(){this.updateWorker({type:"UPDATE"})}dragStart(e){const t="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(t))throw new Error("Can't start dragging circle: the circleRef parameter is malformed.");this.updateWorker({type:"DRAG_START",id:t}),super.startLoop()}drag(e,t){const i="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(i))throw new Error("Can't drag circle: the circleRef parameter is malformed.");if(!n(t))throw new Error("Can't drag circle: the position parameter is malformed.");this.updateWorker({type:"DRAG_MOVE",id:i,position:t}),super.startLoop()}dragEnd(e){const t="object"==typeof e&&void 0!==e.id?e.id:e;if(!r(t))throw new Error("Can't end dragging circle: the circleRef parameter is malformed.");this.updateWorker({type:"DRAG_END",id:t}),super.startLoop()}destroy(){super.destroy(),this.worker&&this.worker.terminate(),this.onMove=null}}return d.pack=function(e={}){return new Promise(((t,i)=>{try{let i;const s={...e,animationLoop:!1,destroyAfterOneMove:!0,onMove:(e,i,s)=>{t({updatedCircles:e,target:i,overlappingCircles:s})}};i=new d(s)}catch(e){i(e)}}))},d}));