@ray-js/robot-map-sdk 0.0.3-beta-19 → 0.0.3-beta-20

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.
Files changed (50) hide show
  1. package/dist/application/MapApplication.js +1 -1
  2. package/dist/components/Base/Zone.js +1 -1
  3. package/dist/components/ChargingStation/index.js +1 -1
  4. package/dist/components/Controls/Divider.js +1 -1
  5. package/dist/components/Controls/Spot.js +1 -1
  6. package/dist/components/Controls/VirtualWall.js +1 -1
  7. package/dist/components/Robot/index.js +1 -1
  8. package/dist/components/RoomInfo/RoomProperty.js +1 -1
  9. package/dist/components/RoomInfo/RoomSelectionIndicator.js +1 -1
  10. package/dist/constant/config.js +1 -1
  11. package/dist/constant/methods.js +1 -1
  12. package/dist/index.d.ts +67 -2
  13. package/dist/index.js +1 -1
  14. package/dist/index.rjs.js +1 -1
  15. package/dist/managers/CustomElementsManager.js +1 -1
  16. package/dist/managers/MapManager.js +1 -1
  17. package/dist/utils/algorithm.js +1 -1
  18. package/dist/utils/index.js +1 -1
  19. package/dist-app/assets/{index-DFAEtWgf.js → index-CMaxpPPD.js} +1 -1
  20. package/dist-app/index.html +1 -1
  21. package/dist-docs/404.html +2 -2
  22. package/dist-docs/assets/{app.C1hdwNGd.js → app.DP1O8BNS.js} +1 -1
  23. package/dist-docs/assets/chunks/@localSearchIndexroot.BXv7BdiO.js +1 -0
  24. package/dist-docs/assets/chunks/{VPLocalSearchBox.D7RLqunb.js → VPLocalSearchBox.UpWCcVfL.js} +1 -1
  25. package/dist-docs/assets/chunks/{theme.Bgk1r3C0.js → theme.uu9-XYwr.js} +2 -2
  26. package/dist-docs/assets/{guide_getting-started.md.8wgboX-g.js → guide_getting-started.md.u5zOtdU6.js} +1 -1
  27. package/dist-docs/assets/{reference_config.md.DKXC2aOe.js → reference_config.md.zb-n1yzx.js} +2 -2
  28. package/dist-docs/assets/{reference_config.md.DKXC2aOe.lean.js → reference_config.md.zb-n1yzx.lean.js} +1 -1
  29. package/dist-docs/assets/{reference_methods.md.Cw2UFl8i.js → reference_methods.md.D1VYgciC.js} +10 -4
  30. package/dist-docs/assets/{reference_methods.md.Cw2UFl8i.lean.js → reference_methods.md.D1VYgciC.lean.js} +1 -1
  31. package/dist-docs/assets/{reference_types.md.CteNuaxc.js → reference_types.md.g_JJ8gNY.js} +74 -15
  32. package/dist-docs/assets/{reference_types.md.CteNuaxc.lean.js → reference_types.md.g_JJ8gNY.lean.js} +1 -1
  33. package/dist-docs/assets/{reference_utils.md.DU5CMWXW.js → reference_utils.md.C5spobZN.js} +6 -2
  34. package/dist-docs/assets/reference_utils.md.C5spobZN.lean.js +1 -0
  35. package/dist-docs/guide/advanced-usage.html +3 -3
  36. package/dist-docs/guide/concepts.html +3 -3
  37. package/dist-docs/guide/getting-started.html +5 -5
  38. package/dist-docs/hashmap.json +1 -1
  39. package/dist-docs/index.html +3 -3
  40. package/dist-docs/reference/callbacks.html +3 -3
  41. package/dist-docs/reference/config.html +5 -5
  42. package/dist-docs/reference/data.html +3 -3
  43. package/dist-docs/reference/methods.html +13 -7
  44. package/dist-docs/reference/runtime.html +3 -3
  45. package/dist-docs/reference/types.html +77 -18
  46. package/dist-docs/reference/utils.html +9 -5
  47. package/package.json +1 -1
  48. package/dist-docs/assets/chunks/@localSearchIndexroot.BNXBBbhn.js +0 -1
  49. package/dist-docs/assets/reference_utils.md.DU5CMWXW.lean.js +0 -1
  50. /package/dist-docs/assets/{guide_getting-started.md.8wgboX-g.lean.js → guide_getting-started.md.u5zOtdU6.lean.js} +0 -0
@@ -1 +1 @@
1
- import{Application as e,isMobile as t,Assets as n}from"pixi.js";import{Interaction as a}from"./Interaction.js";import{merge as r}from"lodash-es";import{proxy as i}from"valtio/vanilla";import{MAIN_INSTANCE_KEY as o}from"../constant/index.js";import s from"mitt";import{Logger as c}from"../utils/logger.js";import{AppContext as h}from"./AppService.js";import{nanoid as d}from"nanoid/non-secure";import{calculateLineEndpoints as p,areStructuredRoomsAdjacent as m,areMultipleRoomsConnected as l,areRasterRoomsAdjacent as g}from"../utils/algorithm.js";import{ViewportContainer as u}from"./ViewportContainer.js";import{AppContainer as w}from"./AppContainer.js";import{MapManager as f}from"../managers/MapManager.js";import{PathManager as M}from"../managers/PathManager.js";import{HeatmapManager as y}from"../managers/HeatmapManager.js";import{ControlsManager as x}from"../managers/ControlsManager.js";import{DetectedObjectManager as S}from"../managers/DetectedObjectManager.js";import{CustomElementsManager as v}from"../managers/CustomElementsManager.js";import{RoomManager as b}from"../managers/RoomManager.js";import{getOptimalAntialiasingStrategy as P}from"../utils/browser.js";import{DEFAULT_CONFIG as C,DEFAULT_RUNTIME_CONFIG as R}from"../constant/config.js";class O extends e{mapState=null;components={};managers={};config=C;runtime;scaleMin=.5;scaleMax=5;events={};instanceKey;containerElement;emitter=s();tickerState={renderReasons:new Set,renderTimer:null};pendingAsyncRender=!1;isFirstMapDraw=!0;constructor(e=o){super(),this.instanceKey=e,h.registerInstance(e,this),globalThis.__PIXI_APP__=this}async initialize(e){return h.provideAsync(this,async()=>{const{resizeTo:n,events:a,config:s,runtime:h={},...d}=e;this.config=r(this.config,s??{}),c.log("Applying config",this.config,s),this.runtime=i(Object.assign({},R,h));const p=this.instanceKey===o;this.containerElement=n;const m=p?{textureGCMaxIdle:t.any?180:3600,textureGCCheckCountMax:t.any?100:50,autoStart:!1,eventFeatures:{move:!0,globalMove:!1,click:!0,wheel:!0}}:{textureGCMaxIdle:60,textureGCCheckCountMax:10,autoStart:!1,eventFeatures:{move:!1,globalMove:!1,click:!1,wheel:!1}};await this.init({resizeTo:p?n:void 0,preferWebGLVersion:2,resolution:window.devicePixelRatio||1,antialias:P(),autoDensity:!0,backgroundColor:this.config.global.backgroundColor,...m,...d}),this.preloadAssets(),this.scaleMax=this.config.interaction.zoomRange.max,this.scaleMin=this.config.interaction.zoomRange.min,this.events=a,this.initializeViewportContainer(),this.initializeInteraction(),this.initializeAppContainer(),this.managers.mapManager=new f,this.managers.heatmapManager=new y,this.managers.pathManager=new M,this.managers.controlsManager=new x,this.managers.detectedObjectManager=new S,this.managers.customElementsManager=new v,this.managers.roomsManager=new b,document.addEventListener("visibilitychange",this.onVisibilityChange)})}async drawMap(e){return h.provideAsync(this,async()=>{c.log("[Map] drawMap",e);const{size:t,resolution:n,origin:a}=e;a[0]===this.mapState?.origin.x&&a[1]===this.mapState?.origin.y||(this.managers.pathManager.updatePositionByOrigin(...a),this.managers.controlsManager.updatePositionByOrigin(...a),this.managers.detectedObjectManager.updatePositionByOrigin(...a),this.managers.customElementsManager.updatePositionByOrigin(...a)),this.mapState={id:e.id,status:1===e.status,origin:{x:a[0],y:a[1]},charger:{x:e.charger.coordinate[0],y:e.charger.coordinate[1]},chargerDirection:e.charger.angle??0,resolution:n,width:t[0],height:t[1]},this.isFirstMapDraw&&(this.isFirstMapDraw=!1,this.events?.onMapFirstDrawed?.(this.mapState)),this.events?.onMapDrawed?.(this.mapState),await this.managers.mapManager.drawMap(e),this.renderOnce()})}async drawRasterMap(e){return h.provideAsync(this,async()=>{c.log("[Map] drawRasterMap",e);const{mapHeader:t,mapData:n}=e,{originX:a,originY:r}=t;a===this.mapState?.origin.x&&r===this.mapState?.origin.y||(this.managers.pathManager.updatePositionByOrigin(a,r),this.managers.controlsManager.updatePositionByOrigin(a,r),this.managers.detectedObjectManager.updatePositionByOrigin(a,r),this.managers.customElementsManager.updatePositionByOrigin(a,r)),this.mapState={id:t.id,status:t.mapStable,origin:{x:a,y:r},charger:{x:t.chargeX,y:t.chargeY},chargerDirection:t.chargeDirection??0,resolution:100*t.mapResolution,width:t.mapWidth,height:t.mapHeight,version:t.version},this.isFirstMapDraw&&(this.isFirstMapDraw=!1,this.events?.onMapFirstDrawed?.(this.mapState)),this.events?.onMapDrawed?.(this.mapState),await this.managers.mapManager.drawRasterMap(n.parsed,this.mapState),this.renderOnce()})}drawPath(e){return h.provide(this,()=>{c.log("[Path] drawPath",e),this.events?.onPathDrawed?.({id:e.pathHeader.pathId,type:e.pathHeader.type,direction:e.pathHeader.direction,count:e.pathHeader.count,initFlag:e.pathHeader.initFlag,robotPosition:e.pathPoints[e.pathPoints.length-1]??null}),this.managers.pathManager.draw(e),this.renderOnce()})}async drawRoomProperty(e){return h.provide(this,()=>{c.log("[Room] drawRoomProperty",e),this.events?.onRoomPropertiesDrawed?.(e),this.managers.roomsManager.drawRoomProperty(e),this.renderOnceNextFrame()})}drawHeatmap({mapData:e,heatmapPoints:t,useGradient:n=!0}){return h.provide(this,()=>{c.log("[Heatmap] drawHeatmap",t),this.managers.heatmapManager.draw({mapData:e,heatmapPoints:t,useGradient:n}),this.renderOnce()})}drawForbiddenSweepZones(e){return h.provide(this,()=>{c.log("[Controls] drawForbiddenSweepZones",e),this.managers.controlsManager.drawForbiddenSweepZones(e),this.renderOnceNextFrame()})}drawForbiddenMopZones(e){return h.provide(this,()=>{c.log("[Controls] drawForbiddenMopZones",e),this.managers.controlsManager.drawForbiddenMopZones(e),this.renderOnceNextFrame()})}drawCleanZones(e){return h.provide(this,()=>{c.log("[Controls] drawCleanZones",e),this.managers.controlsManager.drawCleanZones(e),this.renderOnceNextFrame()})}drawVirtualWalls(e){return h.provide(this,()=>{c.log("[Controls] drawVirtualWalls",e),this.managers.controlsManager.drawVirtualWalls(e),this.renderOnceNextFrame()})}drawSpots(e){return h.provide(this,()=>{c.log("[Controls] drawSpots",e),this.managers.controlsManager.drawSpots(e),this.renderOnceNextFrame()})}async drawDetectedObjects(e){return h.provideAsync(this,async()=>{c.log("[DetectedObject] drawDetectedObjects",e),await this.managers.detectedObjectManager.drawDetectedObjects(e),this.renderOnceNextFrame()})}async drawCustomElements(e){return h.provideAsync(this,async()=>{c.log("[CustomElements] drawCustomElements",e),await this.managers.customElementsManager.drawCustomElements(e),this.renderOnceNextFrame()})}getForbiddenSweepZones(){return this.managers.controlsManager.getForbiddenSweepZones()}getForbiddenMopZones(){return this.managers.controlsManager.getForbiddenMopZones()}getCleanZones(){return this.managers.controlsManager.getCleanZones()}getVirtualWalls(){return this.managers.controlsManager.getVirtualWalls()}getSpots(){return this.managers.controlsManager.getSpots()}getEffectiveDividerPoints(){return this.managers.controlsManager.getEffectiveDividerPoints()}getDividerEndPoints(){return this.managers.controlsManager.getDividerEndPoints()}resetPanZoom(){this.components.interaction.setPanZoom()}fitMapToView(e,t=!1){return h.provide(this,()=>{if(!e||e.minX===e.maxX||e.minY===e.maxY)return void c.warn("地图边界无效,无法自动适配视图");const n=this.config.map.autoPaddingPercent||.1,a=this.getViewportBounds(),r=e.maxX-e.minX,i=e.maxY-e.minY,o=a.width,s=a.height,h=o*(1-2*n)/r,d=s*(1-2*n)/i,p=Math.min(h,d),m=Math.max(this.config.interaction.fitMinScale,this.scaleMin),l=Math.min(this.config.interaction.fitMaxScale,this.scaleMax),g=Math.max(m,Math.min(l,p)),u=o/2-(e.minX+r/2)*g,w=s/2-(e.minY+i/2)*g;this.components.interaction.setPanZoom({targetPosition:{x:u,y:w},targetScale:{x:g,y:g},setCenter:!0,setScale:!0},t)})}getViewportBounds(){return this.components.viewportContainer?.getViewportBounds()||{x:0,y:0,width:this.renderer.width,height:this.renderer.height}}updateRuntime(e){Object.assign(this.runtime,e),this.renderOnceNextFrame()}metersToPixels(e){return this.mapState?.resolution?e*(1/(this.mapState.resolution/100)):(c.warn("Map resolution not available, using default resolution (5cm/pixel)"),20*e)}pixelsToMeters(e){return this.mapState?.resolution?e*(this.mapState.resolution/100):(c.warn("Map resolution not available, using default resolution (5cm/pixel)"),.05*e)}toFixedSize(e,t){return e/(t??this.components.appContainer.scale.x)}fromFixedSize(e,t){return e*(t??this.components.appContainer.scale.x)}getViewportCenterPoint(){if(!this.mapState)return c.warn("Map state not available, cannot calculate center point"),null;const e=this.getViewportBounds(),t=e.x+e.width/2,n=e.y+e.height/2,a=this.components.appContainer,r=a.scale.x,i=(t-a.x)/r,o=(n-a.y)/r;return{x:i-this.mapState.origin.x,y:o-this.mapState.origin.y}}getMapCenterPoint(){if(!this.mapState)return c.warn("Map state not available, cannot calculate map center point"),null;const e=this.managers.mapManager.mapBounds;if(e.minX===1/0||e.minY===1/0||e.maxX===-1/0||e.maxY===-1/0)return c.warn("Invalid map bounds, cannot calculate map center point"),null;const t=(e.minX+e.maxX)/2,n=(e.minY+e.maxY)/2;return{x:t-this.mapState.origin.x,y:n-this.mapState.origin.y}}getWallPointsByViewportCenter(e){const{width:t=this.config.controls.virtualWall.minWidth,direction:n="horizontal",offsetX:a=0,offsetY:r=0}=e||{},i=this.getViewportCenterPoint()||{x:0,y:0},o=this.metersToPixels(t);return p(i.x,i.y,o,n).map(e=>({x:e.x+a,y:e.y+r}))}getForbiddenSweepZonePointsByViewportCenter(e){const t=this.config.controls.forbiddenSweepZone,{size:n=t.minSize,offsetX:a=0,offsetY:r=0}=e||{};return this.generateZonePoints(n,a,r)}getForbiddenMopZonePointsByViewportCenter(e){const t=this.config.controls.forbiddenMopZone,{size:n=t.minSize,offsetX:a=0,offsetY:r=0}=e||{};return this.generateZonePoints(n,a,r)}getCleanZonePointsByViewportCenter(e){const t=this.config.controls.cleanZone,{size:n=t.minSize,offsetX:a=0,offsetY:r=0}=e||{};return this.generateZonePoints(n,a,r)}getSpotPointByViewportCenter(e){const{offsetX:t=0,offsetY:n=0}=e||{},a=this.getViewportCenterPoint()||{x:0,y:0};return{x:a.x+t,y:a.y+n}}areRoomsAdjacent(e){const t=this.config.map.adjacencyThreshold;return h.provide(this,()=>{if(!e||0===e.length)return c.warn("[Room] No room IDs provided"),!1;if(1===e.length)return!0;const n=Array.from(new Set(e));return 1===n.length||(void 0!==this.mapState?.version?this.areRasterRoomsAdjacentInternal(n,t):this.areStructuredRoomsAdjacentInternal(n,t))})}areStructuredRoomsAdjacentInternal(e,t){const n=[];for(const t of e){const e=this.managers.mapManager.getRoomById(t);if(!e)return c.warn(`[Room] Room ${t} not found in map`),!1;if(!e.outlinePoints||0===e.outlinePoints.length)return c.warn(`[Room] Room ${t} has no outline points`),!1;n.push({id:t,points:e.outlinePoints})}const a=[];for(let e=0;e<n.length;e++)for(let r=e+1;r<n.length;r++){const i=n[e],o=n[r];m(i.points,o.points,t)&&a.push([e,r])}return l(n.length,a)}areRasterRoomsAdjacentInternal(e,t){if(!this.mapState)return c.warn("[Room] Map state not available"),!1;const n=this.mapState.width,a=[];for(const t of e){const e=this.managers.mapManager.getRasterRoomPixels(t);if(!e)return c.warn(`[Room] Room ${t} pixel data not found in raster map`),!1;a.push({id:t,pixels:e})}const r=[];for(let e=0;e<a.length;e++)for(let i=e+1;i<a.length;i++){const o=a[e],s=a[i];g(o.pixels,s.pixels,n,t)&&r.push([e,i])}return l(a.length,r)}async snapshot(){this.render(),await new Promise(e=>setTimeout(e,0));const{snapshot:e}=this.config;return await this.renderer.extract.base64({target:this.components.appContainer,format:e.format,quality:e.quality,resolution:e.resolution,antialias:e.antialias})}async snapshotByData({map:e,path:t,roomProperties:n,customElements:a,forbiddenSweepZones:r,forbiddenMopZones:i,virtualWalls:o,detectedObjects:s},h={}){const p=`SNAPSHOT_${d()}`;c.log(`[MapApplication] ${p} snapshot start`);const m=new O(p);try{if(await m.initialize({config:this.config,runtime:h}),!e)throw new Error("Map data is required");if(e.startsWith("7b22")){const{decodeMapStructured:t}=await import("@ray-js/robot-protocol"),n=t(e);await m.drawMap(n)}else{const{decodeMap:t}=await import("@ray-js/robot-protocol"),n=t(e);if(!n)throw new Error("Failed to decode raster map data");await m.drawRasterMap(n)}if(t){const{decodePath:e}=await import("@ray-js/robot-protocol"),n=e(t);m.drawPath(n)}n&&n.length>0&&m.drawRoomProperty(n),r&&r.length>0&&m.drawForbiddenSweepZones(r),i&&i.length>0&&m.drawForbiddenMopZones(i),o&&o.length>0&&m.drawVirtualWalls(o),s&&s.length>0&&await m.drawDetectedObjects(s),a&&a.length>0&&await m.drawCustomElements(a);const d=await m.snapshot();return c.log(`[MapApplication] ${p} snapshot completed successfully`),d}catch(e){throw c.error(`[MapApplication] ${p} snapshot other map failed:`,e),e}finally{c.log(`[MapApplication] ${p} destroy`),m.destroy()}}renderOnce(){c.log("[Pixi] renderOnce"),this.render()}renderOnceNextFrame(){this.pendingAsyncRender||(this.pendingAsyncRender=!0,requestAnimationFrame(()=>{c.log("[Pixi] renderOnceNextFrame"),this.render(),this.pendingAsyncRender=!1}))}requestRender(e,t=!1){t?(this.tickerState.renderReasons.add(e),this.ticker.started||(c.debug(`🎬 [Ticker] START: ${e}`),this.ticker.start())):this.renderOnceNextFrame()}stopRender(e){this.tickerState.renderReasons.delete(e),0===this.tickerState.renderReasons.size&&this.scheduleStopRender("final",100)}destroy(){h.unregisterInstance(this.instanceKey),this.tickerState.renderTimer&&clearTimeout(this.tickerState.renderTimer),this.tickerState.renderReasons.clear(),this.emitter.all.clear(),document.removeEventListener("visibilitychange",this.onVisibilityChange),this.managers.pathManager.destroy(),this.managers.mapManager.destroy(),this.managers.controlsManager.destroy(),this.managers.detectedObjectManager.destroy(),this.managers.customElementsManager.destroy(),this.managers.roomsManager.destroy(),this.components.interaction.destroy(),this.components.viewportContainer.destroy(),this.components.appContainer.destroy(),super.destroy()}initializeViewportContainer(){this.components.viewportContainer=new u(this.config,this.containerElement),this.stage.addChild(this.components.viewportContainer)}initializeAppContainer(){this.components.appContainer=new w,this.components.interaction.addChild(this.components.appContainer)}initializeInteraction(){this.components.interaction=new a,this.components.viewportContainer.addChild(this.components.interaction)}scheduleStopRender(e,t){this.tickerState.renderTimer&&clearTimeout(this.tickerState.renderTimer),this.tickerState.renderTimer=setTimeout(()=>{this.tickerState.renderReasons.delete(e),0===this.tickerState.renderReasons.size&&(c.debug("⏸️ [Ticker] STOP"),this.ticker.stop())},t)}generateZonePoints(e,t,n){const a=this.getViewportCenterPoint()||{x:0,y:0},r=this.metersToPixels(e)/2,i=a.x+t,o=a.y+n;return[{x:i-r,y:o-r},{x:i+r,y:o-r},{x:i+r,y:o+r},{x:i-r,y:o+r}]}preloadAssets(){const e=this.config.robot.icon.src,t=this.config.chargingStation.icon.src,a=[];n.add({alias:"robot",src:e}),a.push("robot"),n.add({alias:"chargingStation",src:t}),a.push("chargingStation"),n.add({alias:"deleteIcon",src:this.config.controls.deleteIconSrc}),a.push("deleteIcon"),n.add({alias:"rotateIcon",src:this.config.controls.rotateIconSrc}),a.push("rotateIcon"),n.add({alias:"scaleIcon",src:this.config.controls.scaleIconSrc}),a.push("scaleIcon"),n.add({alias:"moveIcon",src:this.config.controls.moveIconSrc}),a.push("moveIcon"),n.add({alias:"checkmark",src:this.config.room.selectionIndicator.iconSrc}),a.push("checkmark"),n.add({alias:"spotIcon",src:this.config.controls.spot.iconSrc}),a.push("spotIcon"),this.config.room.property.cleanMode.assets.forEach((e,t)=>{const r=`cleanMode_${t}`;n.add({alias:r,src:e}),a.push(r)}),this.config.room.property.suction.assets.forEach((e,t)=>{const r=`fan_${t}`;n.add({alias:r,src:e}),a.push(r)}),this.config.room.property.cistern.assets.forEach((e,t)=>{const r=`water_${t}`;n.add({alias:r,src:e}),a.push(r)}),this.config.room.property.cleanTimes.assets.forEach((e,t)=>{const r=`cleanTimes${t+1}`;n.add({alias:r,src:e}),a.push(r)}),this.config.room.floorType.assets.forEach((e,t)=>{if(!e)return;const r=`floorType${t}`;n.add({alias:r,src:e}),a.push(r)}),n.backgroundLoad(a)}onVisibilityChange=()=>{"visible"===document.visibilityState||this.components.interaction?.clearTouches()}}export{O as MapApplication};
1
+ import{Application as t,isMobile as e,Assets as n}from"pixi.js";import{Interaction as a}from"./Interaction.js";import{merge as r}from"lodash-es";import{proxy as i}from"valtio/vanilla";import{MAIN_INSTANCE_KEY as o}from"../constant/index.js";import s from"mitt";import{Logger as c}from"../utils/logger.js";import{AppContext as h}from"./AppService.js";import{nanoid as m}from"nanoid/non-secure";import{calculateLineEndpoints as d,isPointInPolygon as p,binarySearch as l,areStructuredRoomsAdjacent as g,areMultipleRoomsConnected as u,areRasterRoomsAdjacent as w}from"../utils/algorithm.js";import{ViewportContainer as f}from"./ViewportContainer.js";import{AppContainer as y}from"./AppContainer.js";import{MapManager as M}from"../managers/MapManager.js";import{PathManager as S}from"../managers/PathManager.js";import{HeatmapManager as x}from"../managers/HeatmapManager.js";import{ControlsManager as P}from"../managers/ControlsManager.js";import{DetectedObjectManager as b}from"../managers/DetectedObjectManager.js";import{CustomElementsManager as v}from"../managers/CustomElementsManager.js";import{RoomManager as R}from"../managers/RoomManager.js";import{getOptimalAntialiasingStrategy as C}from"../utils/browser.js";import{DEFAULT_CONFIG as I,DEFAULT_RUNTIME_CONFIG as O}from"../constant/config.js";class F extends t{mapState=null;components={};managers={};config=I;runtime;scaleMin=.5;scaleMax=5;events={};instanceKey;containerElement;emitter=s();tickerState={renderReasons:new Set,renderTimer:null};pendingAsyncRender=!1;isFirstMapDraw=!0;constructor(t=o){super(),this.instanceKey=t,h.registerInstance(t,this),globalThis.__PIXI_APP__=this}async initialize(t){return h.provideAsync(this,async()=>{const{resizeTo:n,events:a,config:s,runtime:h={},...m}=t;this.config=r(this.config,s??{}),c.log("Applying config",this.config,s),this.runtime=i(Object.assign({},O,h));const d=this.instanceKey===o;this.containerElement=n;const p=d?{textureGCMaxIdle:e.any?180:3600,textureGCCheckCountMax:e.any?100:50,autoStart:!1,eventFeatures:{move:!0,globalMove:!1,click:!0,wheel:!0}}:{textureGCMaxIdle:60,textureGCCheckCountMax:10,autoStart:!1,eventFeatures:{move:!1,globalMove:!1,click:!1,wheel:!1}};await this.init({resizeTo:d?n:void 0,preferWebGLVersion:2,resolution:window.devicePixelRatio||1,antialias:C(),autoDensity:!0,backgroundColor:this.config.global.backgroundColor,...p,...m}),this.preloadAssets(),this.scaleMax=this.config.interaction.zoomRange.max,this.scaleMin=this.config.interaction.zoomRange.min,this.events=a,this.initializeViewportContainer(),this.initializeInteraction(),this.initializeAppContainer(),this.managers.mapManager=new M,this.managers.heatmapManager=new x,this.managers.pathManager=new S,this.managers.controlsManager=new P,this.managers.detectedObjectManager=new b,this.managers.customElementsManager=new v,this.managers.roomsManager=new R,document.addEventListener("visibilitychange",this.onVisibilityChange)})}async drawMap(t){return h.provideAsync(this,async()=>{c.log("[Map] drawMap",t);const{size:e,resolution:n,origin:a}=t;a[0]===this.mapState?.origin.x&&a[1]===this.mapState?.origin.y||(this.managers.pathManager.updatePositionByOrigin(...a),this.managers.controlsManager.updatePositionByOrigin(...a),this.managers.detectedObjectManager.updatePositionByOrigin(...a),this.managers.customElementsManager.updatePositionByOrigin(...a)),this.mapState={id:t.id,status:1===t.status,origin:{x:a[0],y:a[1]},charger:{x:t.charger.coordinate[0],y:t.charger.coordinate[1]},chargerDirection:t.charger.angle??0,resolution:n,width:e[0],height:e[1],mapType:"structured"},this.isFirstMapDraw&&(this.isFirstMapDraw=!1,this.events?.onMapFirstDrawed?.(this.mapState)),this.events?.onMapDrawed?.(this.mapState),await this.managers.mapManager.drawMap(t),this.renderOnce()})}async drawRasterMap(t){return h.provideAsync(this,async()=>{c.log("[Map] drawRasterMap",t);const{mapHeader:e,mapData:n}=t,{originX:a,originY:r}=e;a===this.mapState?.origin.x&&r===this.mapState?.origin.y||(this.managers.pathManager.updatePositionByOrigin(a,r),this.managers.controlsManager.updatePositionByOrigin(a,r),this.managers.detectedObjectManager.updatePositionByOrigin(a,r),this.managers.customElementsManager.updatePositionByOrigin(a,r)),this.mapState={id:e.id,status:e.mapStable,origin:{x:a,y:r},charger:{x:e.chargeX,y:e.chargeY},chargerDirection:e.chargeDirection??0,resolution:100*e.mapResolution,width:e.mapWidth,height:e.mapHeight,version:e.version,mapType:"raster"},this.isFirstMapDraw&&(this.isFirstMapDraw=!1,this.events?.onMapFirstDrawed?.(this.mapState)),this.events?.onMapDrawed?.(this.mapState),await this.managers.mapManager.drawRasterMap(n.parsed,this.mapState),this.renderOnce()})}drawPath(t){return h.provide(this,()=>{c.log("[Path] drawPath",t),this.events?.onPathDrawed?.({id:t.pathHeader.pathId,type:t.pathHeader.type,direction:t.pathHeader.direction,count:t.pathHeader.count,initFlag:t.pathHeader.initFlag,robotPosition:t.pathPoints[t.pathPoints.length-1]??null}),this.managers.pathManager.draw(t),this.renderOnce()})}async drawRoomProperty(t){return h.provide(this,()=>{c.log("[Room] drawRoomProperty",t),this.events?.onRoomPropertiesDrawed?.(t),this.managers.roomsManager.drawRoomProperty(t),this.renderOnceNextFrame()})}drawHeatmap({mapData:t,heatmapPoints:e,useGradient:n=!0}){return h.provide(this,()=>{c.log("[Heatmap] drawHeatmap",e),this.managers.heatmapManager.draw({mapData:t,heatmapPoints:e,useGradient:n}),this.renderOnce()})}drawForbiddenSweepZones(t){return h.provide(this,()=>{c.log("[Controls] drawForbiddenSweepZones",t),this.managers.controlsManager.drawForbiddenSweepZones(t),this.renderOnceNextFrame()})}drawForbiddenMopZones(t){return h.provide(this,()=>{c.log("[Controls] drawForbiddenMopZones",t),this.managers.controlsManager.drawForbiddenMopZones(t),this.renderOnceNextFrame()})}drawCleanZones(t){return h.provide(this,()=>{c.log("[Controls] drawCleanZones",t),this.managers.controlsManager.drawCleanZones(t),this.renderOnceNextFrame()})}drawVirtualWalls(t){return h.provide(this,()=>{c.log("[Controls] drawVirtualWalls",t),this.managers.controlsManager.drawVirtualWalls(t),this.renderOnceNextFrame()})}drawSpots(t){return h.provide(this,()=>{c.log("[Controls] drawSpots",t),this.managers.controlsManager.drawSpots(t),this.renderOnceNextFrame()})}async drawDetectedObjects(t){return h.provideAsync(this,async()=>{c.log("[DetectedObject] drawDetectedObjects",t),await this.managers.detectedObjectManager.drawDetectedObjects(t),this.renderOnceNextFrame()})}async drawCustomElements(t){return h.provideAsync(this,async()=>{c.log("[CustomElements] drawCustomElements",t),await this.managers.customElementsManager.drawCustomElements(t),this.renderOnceNextFrame()})}getForbiddenSweepZones(){return this.managers.controlsManager.getForbiddenSweepZones()}getForbiddenMopZones(){return this.managers.controlsManager.getForbiddenMopZones()}getCleanZones(){return this.managers.controlsManager.getCleanZones()}getVirtualWalls(){return this.managers.controlsManager.getVirtualWalls()}getSpots(){return this.managers.controlsManager.getSpots()}getEffectiveDividerPoints(){return this.managers.controlsManager.getEffectiveDividerPoints()}getDividerEndPoints(){return this.managers.controlsManager.getDividerEndPoints()}resetPanZoom(){this.components.interaction.setPanZoom()}fitMapToView(t,e=!1){return h.provide(this,()=>{if(!t||t.minX===t.maxX||t.minY===t.maxY)return void c.warn("地图边界无效,无法自动适配视图");const n=this.config.map.autoPaddingPercent||.1,a=this.getViewportBounds(),r=t.maxX-t.minX,i=t.maxY-t.minY,o=a.width,s=a.height,h=o*(1-2*n)/r,m=s*(1-2*n)/i,d=Math.min(h,m),p=Math.max(this.config.interaction.fitMinScale,this.scaleMin),l=Math.min(this.config.interaction.fitMaxScale,this.scaleMax),g=Math.max(p,Math.min(l,d)),u=o/2-(t.minX+r/2)*g,w=s/2-(t.minY+i/2)*g;this.components.interaction.setPanZoom({targetPosition:{x:u,y:w},targetScale:{x:g,y:g},setCenter:!0,setScale:!0},e)})}getViewportBounds(){return this.components.viewportContainer?.getViewportBounds()||{x:0,y:0,width:this.renderer.width,height:this.renderer.height}}updateRuntime(t){Object.assign(this.runtime,t),this.renderOnceNextFrame()}metersToPixels(t){return this.mapState?.resolution?t*(1/(this.mapState.resolution/100)):(c.warn("Map resolution not available, using default resolution (5cm/pixel)"),20*t)}pixelsToMeters(t){return this.mapState?.resolution?t*(this.mapState.resolution/100):(c.warn("Map resolution not available, using default resolution (5cm/pixel)"),.05*t)}toFixedSize(t,e){return t/(e??this.components.appContainer.scale.x)}fromFixedSize(t,e){return t*(e??this.components.appContainer.scale.x)}getViewportCenterPoint(){if(!this.mapState)return c.warn("Map state not available, cannot calculate center point"),null;const t=this.getViewportBounds(),e=t.x+t.width/2,n=t.y+t.height/2,a=this.components.appContainer,r=a.scale.x,i=(e-a.x)/r,o=(n-a.y)/r;return{x:i-this.mapState.origin.x,y:o-this.mapState.origin.y}}getMapCenterPoint(){if(!this.mapState)return c.warn("Map state not available, cannot calculate map center point"),null;const t=this.managers.mapManager.mapBounds;if(t.minX===1/0||t.minY===1/0||t.maxX===-1/0||t.maxY===-1/0)return c.warn("Invalid map bounds, cannot calculate map center point"),null;const e=(t.minX+t.maxX)/2,n=(t.minY+t.maxY)/2;return{x:e-this.mapState.origin.x,y:n-this.mapState.origin.y}}getWallPointsByViewportCenter(t){const{width:e=this.config.controls.virtualWall.minWidth,direction:n="horizontal",offsetX:a=0,offsetY:r=0}=t||{},i=this.getViewportCenterPoint()||{x:0,y:0},o=this.metersToPixels(e);return d(i.x,i.y,o,n).map(t=>({x:t.x+a,y:t.y+r}))}getForbiddenSweepZonePointsByViewportCenter(t){const e=this.config.controls.forbiddenSweepZone,{size:n=e.minSize,offsetX:a=0,offsetY:r=0}=t||{};return this.generateZonePoints(n,a,r)}getForbiddenMopZonePointsByViewportCenter(t){const e=this.config.controls.forbiddenMopZone,{size:n=e.minSize,offsetX:a=0,offsetY:r=0}=t||{};return this.generateZonePoints(n,a,r)}getCleanZonePointsByViewportCenter(t){const e=this.config.controls.cleanZone,{size:n=e.minSize,offsetX:a=0,offsetY:r=0}=t||{};return this.generateZonePoints(n,a,r)}getSpotPointByViewportCenter(t){const{offsetX:e=0,offsetY:n=0}=t||{},a=this.getViewportCenterPoint()||{x:0,y:0};return{x:a.x+e,y:a.y+n}}areRoomsAdjacent(t){const e=this.config.map.adjacencyThreshold;return h.provide(this,()=>{if(!t||0===t.length)return c.warn("[Room] No room IDs provided"),!1;if(1===t.length)return!0;const n=Array.from(new Set(t));return 1===n.length||("raster"===(this.mapState?.mapType??"structured")?this.areRasterRoomsAdjacentInternal(n,e):this.areStructuredRoomsAdjacentInternal(n,e))})}isPointInAnyRoom(t){return h.provide(this,()=>t&&"number"==typeof t.x&&"number"==typeof t.y?"raster"===(this.mapState?.mapType??"structured")?this.isPointInAnyRoomRasterInternal(t):this.isPointInAnyRoomStructuredInternal(t):(c.warn("[Room] Invalid point provided"),null))}isPointInAnyRoomStructuredInternal(t){if(!this.mapState)return c.warn("[Room] Map state not available"),null;const e={x:t.x+this.mapState.origin.x,y:t.y+this.mapState.origin.y},n=this.managers.mapManager.getAllRooms();for(const t of n)if(t.outlinePoints&&t.outlinePoints.length>=3&&p(e,t.outlinePoints))return this.managers.roomsManager.getRoomPropertyById(t.id)||(c.warn(`[Room] Room ${t.id} found in geometry but not in RoomManager`),null);return null}isPointInAnyRoomRasterInternal(t){if(!this.mapState)return c.warn("[Room] Map state not available"),null;const e=this.mapState.width,n=this.mapState.height,a=t.x+this.mapState.origin.x,r=t.y+this.mapState.origin.y,i=Math.round(a),o=Math.round(r);if(i<0||i>=e||o<0||o>=n)return c.warn(`[Room] Point (${i}, ${o}) is out of map bounds (${e}x${n})`),null;const s=o*e+i,h=this.managers.mapManager.getAllRooms();for(const t of h){const e=this.managers.mapManager.getRasterRoomPixels(t.id);if(e&&e.length>0&&l(e,s))return this.managers.roomsManager.getRoomPropertyById(t.id)||(c.warn(`[Room] Room ${t.id} found in geometry but not in RoomManager`),null)}return null}areStructuredRoomsAdjacentInternal(t,e){const n=[];for(const e of t){const t=this.managers.mapManager.getRoomById(e);if(!t)return c.warn(`[Room] Room ${e} not found in map`),!1;if(!t.outlinePoints||0===t.outlinePoints.length)return c.warn(`[Room] Room ${e} has no outline points`),!1;n.push({id:e,points:t.outlinePoints})}const a=[];for(let t=0;t<n.length;t++)for(let r=t+1;r<n.length;r++){const i=n[t],o=n[r];g(i.points,o.points,e)&&a.push([t,r])}return u(n.length,a)}areRasterRoomsAdjacentInternal(t,e){if(!this.mapState)return c.warn("[Room] Map state not available"),!1;const n=this.mapState.width,a=[];for(const e of t){const t=this.managers.mapManager.getRasterRoomPixels(e);if(!t)return c.warn(`[Room] Room ${e} pixel data not found in raster map`),!1;a.push({id:e,pixels:t})}const r=[];for(let t=0;t<a.length;t++)for(let i=t+1;i<a.length;i++){const o=a[t],s=a[i];w(o.pixels,s.pixels,n,e)&&r.push([t,i])}return u(a.length,r)}async snapshot(){this.render(),await new Promise(t=>setTimeout(t,0));const{snapshot:t}=this.config;return await this.renderer.extract.base64({target:this.components.appContainer,format:t.format,quality:t.quality,resolution:t.resolution,antialias:t.antialias})}async snapshotByData({map:t,path:e,roomProperties:n,customElements:a,forbiddenSweepZones:r,forbiddenMopZones:i,virtualWalls:o,detectedObjects:s},h={}){const d=`SNAPSHOT_${m()}`;c.log(`[MapApplication] ${d} snapshot start`);const p=new F(d);try{if(await p.initialize({config:this.config,runtime:h}),!t)throw new Error("Map data is required");if(t.startsWith("7b22")){const{decodeMapStructured:e}=await import("@ray-js/robot-protocol"),n=e(t);await p.drawMap(n)}else{const{decodeMap:e}=await import("@ray-js/robot-protocol"),n=e(t);if(!n)throw new Error("Failed to decode raster map data");await p.drawRasterMap(n)}if(e){const{decodePath:t}=await import("@ray-js/robot-protocol"),n=t(e);p.drawPath(n)}n&&n.length>0&&p.drawRoomProperty(n),r&&r.length>0&&p.drawForbiddenSweepZones(r),i&&i.length>0&&p.drawForbiddenMopZones(i),o&&o.length>0&&p.drawVirtualWalls(o),s&&s.length>0&&await p.drawDetectedObjects(s),a&&a.length>0&&await p.drawCustomElements(a);const m=await p.snapshot();return c.log(`[MapApplication] ${d} snapshot completed successfully`),m}catch(t){throw c.error(`[MapApplication] ${d} snapshot other map failed:`,t),t}finally{c.log(`[MapApplication] ${d} destroy`),p.destroy()}}renderOnce(){c.log("[Pixi] renderOnce"),this.render()}renderOnceNextFrame(){this.pendingAsyncRender||(this.pendingAsyncRender=!0,requestAnimationFrame(()=>{c.log("[Pixi] renderOnceNextFrame"),this.render(),this.pendingAsyncRender=!1}))}requestRender(t,e=!1){e?(this.tickerState.renderReasons.add(t),this.ticker.started||(c.debug(`🎬 [Ticker] START: ${t}`),this.ticker.start())):this.renderOnceNextFrame()}stopRender(t){this.tickerState.renderReasons.delete(t),0===this.tickerState.renderReasons.size&&this.scheduleStopRender("final",100)}destroy(){h.unregisterInstance(this.instanceKey),this.tickerState.renderTimer&&clearTimeout(this.tickerState.renderTimer),this.tickerState.renderReasons.clear(),this.emitter.all.clear(),document.removeEventListener("visibilitychange",this.onVisibilityChange),this.managers.pathManager.destroy(),this.managers.mapManager.destroy(),this.managers.controlsManager.destroy(),this.managers.detectedObjectManager.destroy(),this.managers.customElementsManager.destroy(),this.managers.roomsManager.destroy(),this.components.interaction.destroy(),this.components.viewportContainer.destroy(),this.components.appContainer.destroy(),super.destroy()}initializeViewportContainer(){this.components.viewportContainer=new f(this.config,this.containerElement),this.stage.addChild(this.components.viewportContainer)}initializeAppContainer(){this.components.appContainer=new y,this.components.interaction.addChild(this.components.appContainer)}initializeInteraction(){this.components.interaction=new a,this.components.viewportContainer.addChild(this.components.interaction)}scheduleStopRender(t,e){this.tickerState.renderTimer&&clearTimeout(this.tickerState.renderTimer),this.tickerState.renderTimer=setTimeout(()=>{this.tickerState.renderReasons.delete(t),0===this.tickerState.renderReasons.size&&(c.debug("⏸️ [Ticker] STOP"),this.ticker.stop())},e)}generateZonePoints(t,e,n){const a=this.getViewportCenterPoint()||{x:0,y:0},r=this.metersToPixels(t)/2,i=a.x+e,o=a.y+n;return[{x:i-r,y:o-r},{x:i+r,y:o-r},{x:i+r,y:o+r},{x:i-r,y:o+r}]}preloadAssets(){const t=this.config.robot.icon.src,e=this.config.chargingStation.icon.src,a=[];n.add({alias:"robot",src:t}),a.push("robot"),n.add({alias:"chargingStation",src:e}),a.push("chargingStation"),n.add({alias:"deleteIcon",src:this.config.controls.deleteIconSrc}),a.push("deleteIcon"),n.add({alias:"rotateIcon",src:this.config.controls.rotateIconSrc}),a.push("rotateIcon"),n.add({alias:"scaleIcon",src:this.config.controls.scaleIconSrc}),a.push("scaleIcon"),n.add({alias:"moveIcon",src:this.config.controls.moveIconSrc}),a.push("moveIcon"),n.add({alias:"checkmark",src:this.config.room.selectionIndicator.iconSrc}),a.push("checkmark"),n.add({alias:"spotIcon",src:this.config.controls.spot.iconSrc}),a.push("spotIcon"),this.config.room.property.cleanMode.assets.forEach((t,e)=>{const r=`cleanMode_${e}`;n.add({alias:r,src:t}),a.push(r)}),this.config.room.property.suction.assets.forEach((t,e)=>{const r=`fan_${e}`;n.add({alias:r,src:t}),a.push(r)}),this.config.room.property.cistern.assets.forEach((t,e)=>{const r=`water_${e}`;n.add({alias:r,src:t}),a.push(r)}),this.config.room.property.cleanTimes.assets.forEach((t,e)=>{const r=`cleanTimes${e+1}`;n.add({alias:r,src:t}),a.push(r)}),this.config.room.floorType.assets.forEach((t,e)=>{if(!t)return;const r=`floorType${e}`;n.add({alias:r,src:t}),a.push(r)}),n.backgroundLoad(a)}onVisibilityChange=()=>{"visible"===document.visibilityState||this.components.interaction?.clearTouches()}}export{F as MapApplication};
@@ -1 +1 @@
1
- import{Container as t}from"pixi.js";import{RotateControlButton as o}from"./RotateControlButton.js";import{RemoveControlButton as e}from"./RemoveControlButton.js";import{ScaleControlButton as i}from"./ScaleControlButton.js";import{MoveControlButton as n}from"./MoveControlButton.js";import{ControlFill as s}from"./ControlFill.js";import{normalizeToRectangle as a,getDistance as l,calculateCenter as r,normalizeVector as h,createVector as d,calculatePolygonOutline as u,calculateUprightLineAngle as c,calculateCornerExtension as p,rotatePointsAroundCenter as g,getVectorLength as C,calculateScaleRatio as y}from"../../utils/algorithm.js";import{ClickHandler as x}from"../../mixins/ClickHandler.js";import{throttle as z}from"lodash-es";import{Border as B}from"./Border.js";import{FixedSizeText as S}from"./FixedSizeText.js";import{useAppService as f}from"../../application/AppService.js";class v extends t{static BUTTON_INDICES={REMOVE:0,ROTATE:1,SCALE:2,MOVE:3,FIXED:0};zoneData;zoneType;zoneConfig;controlsConfig;zoneEvents;controlFill;zoneBorder;outlineBorder;moveLine;sizeText;controlButtons;deleteButton=null;rotateButton=null;scaleButton=null;moveButton=null;totalRotationAngle=0;rotationCenter=null;initialZonePoints=[];clickHandler=null;throttledUpdateOutline;constructor(t){super();const{zoneData:o,zoneType:e,events:i={}}=t;this.zoneType=e,this.zoneEvents=i,this.zoneConfig=this.getZoneConfig(),this.controlsConfig=this.getControlsConfig();const n=this.validateAndCorrectZoneSize(o.points),s=a(n);this.zoneData={...o,points:s},this.throttledUpdateOutline=z(this.updateOutlineForScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.createControlButtons(),this.updateEditState(),this.setupClickHandler(),this.registerScaleListener()}registerScaleListener(){f().emitter.on("antiScale",this.throttledUpdateOutline)}updateOutlineForScale(){this.isEditingEnabled()&&(this.updateOutlineBorder(),this.updateMoveLine(),this.updateControlButtonsPosition(),this.updateSizeTextPosition())}getZoneConfig(){const t=f(),{controls:o}=t.getConfig();return o[this.zoneType]}getControlsConfig(){const t=f(),{controls:o}=t.getConfig();return o}validateAndCorrectZoneSize(t){const o=f();if(t.length<4)return t;const e=o.metersToPixels(this.zoneConfig.minSize),[i,n,,s]=t,a=l(i,n),u=l(i,s);if(a>=e&&u>=e)return t;const c=r(t),p=h(d(i,n)),g=h(d(i,s)),C=Math.max(a,e)/2,y=Math.max(u,e)/2;return[{x:c.x-p.x*C-g.x*y,y:c.y-p.y*C-g.y*y},{x:c.x+p.x*C-g.x*y,y:c.y+p.y*C-g.y*y},{x:c.x+p.x*C+g.x*y,y:c.y+p.y*C+g.y*y},{x:c.x-p.x*C+g.x*y,y:c.y-p.y*C+g.y*y}]}getEditingIdsKey(){switch(this.zoneType){case"forbiddenSweepZone":default:return"editingForbiddenSweepZoneIds";case"forbiddenMopZone":return"editingForbiddenMopZoneIds";case"cleanZone":return"editingCleanZoneIds"}}isEditingEnabled(){const t=this.getEditingIdsKey();return f().runtimeSnapshot[t].includes(this.zoneData.id)}initializeComponents(){this.outlineBorder=this.createOutlineBorder(),this.addChild(this.outlineBorder),this.controlFill=this.createControlFill(),this.addChild(this.controlFill),this.zoneBorder=this.createBorder(),this.addChild(this.zoneBorder),this.moveLine=this.createMoveLine(),this.addChild(this.moveLine),this.sizeText=this.createSizeText(),this.addChild(this.sizeText),this.controlButtons=new t,this.controlButtons.visible=this.isEditingEnabled(),this.addChild(this.controlButtons),this.drawZone()}createControlButtons(){const t=this.calculateOutlinePoints();if(t.length<4)return;this.deleteButton=new e({iconAlias:"deleteIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,onClick:this.handleDelete}),this.deleteButton.position.set(t[v.BUTTON_INDICES.REMOVE].x,t[v.BUTTON_INDICES.REMOVE].y),this.rotateButton=new o({iconAlias:"rotateIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,getTargetPoints:()=>this.zoneData.points,onRotationStart:this.handleRotationStart,onRotationMove:this.handleRotationMove,onRotationEnd:this.handleRotationEnd}),this.rotateButton.position.set(t[v.BUTTON_INDICES.ROTATE].x,t[v.BUTTON_INDICES.ROTATE].y),this.scaleButton=new i({iconAlias:"scaleIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,getTargetPoints:()=>this.zoneData.points,getButtonIndex:()=>v.BUTTON_INDICES.SCALE,onScaleStart:this.handleScaleStart,onScaleMove:this.handleScaleMove,onScaleEnd:this.handleScaleEnd}),this.scaleButton.position.set(t[v.BUTTON_INDICES.SCALE].x,t[v.BUTTON_INDICES.SCALE].y);const s=this.calculateMoveButtonPosition();this.moveButton=new n({iconAlias:"moveIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,onMoveStart:this.handleMoveStart,onMoveMove:this.handleMove,onMoveEnd:this.handleMoveEnd}),this.moveButton.position.set(s.x,s.y),this.controlButtons.addChild(this.deleteButton),this.controlButtons.addChild(this.rotateButton),this.controlButtons.addChild(this.scaleButton),this.controlButtons.addChild(this.moveButton)}createControlFill(){const t=this.isEditingEnabled();return new s({points:this.zoneData.points,fillColor:this.zoneConfig.fillColor,enableInteraction:t,onDragStart:this.handleDragStart,onDragMove:this.handleDragMove,onDragEnd:this.handleDragEnd})}createBorder(){const t=this.isEditingEnabled()?this.zoneConfig.editing:this.zoneConfig.normal;return new B({points:this.zoneData.points,closePath:!0,style:{color:this.zoneConfig.strokeColor,width:this.zoneConfig.strokeWidth,isDashed:t.isDashed,dashArray:t.dashArray}})}createOutlineBorder(){const t=this.calculateOutlinePoints();return new B({points:t,closePath:!0,style:{color:this.zoneConfig.outlineStrokeColor,width:this.zoneConfig.outlineStrokeWidth,isDashed:this.zoneConfig.outlineDashed,dashArray:this.zoneConfig.outlineDashArray,fillColor:this.zoneConfig.outlineFillColor}})}createMoveLine(){const t=this.calculateOutlinePoints(),o=this.calculateMoveLinePoints(t);return new B({points:o,closePath:!1,style:{color:this.zoneConfig.outlineStrokeColor,width:this.zoneConfig.outlineStrokeWidth,isDashed:this.zoneConfig.outlineDashed,dashArray:this.zoneConfig.outlineDashArray}})}calculateOutlinePoints(){const{points:t}=this.zoneData;if(t.length<4)return t;const o=f().getApp().toFixedSize(this.zoneConfig.outlineOffset);return u(t,o)}calculateMoveLinePoints(t){return t.length<4?[]:[t[v.BUTTON_INDICES.MOVE],this.calculateMoveButtonPosition()]}createSizeText(){const t=this.calculateZoneSizeText(),o=new S({text:t,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.zoneConfig.textColor,align:"center"}});o.anchor.set(.5);const e=this.calculateSizeTextPosition();o.position.set(e.x,e.y);const i=this.calculateSizeTextRotation();return o.rotation=i,o.eventMode="none",o}calculateZoneSizeText(){const{points:t}=this.zoneData;if(t.length<4)return"0m*0m";const[o,e,,i]=t,n=l(o,e),s=l(o,i),a=f(),r=a.pixelsToMeters(n),h=a.pixelsToMeters(s);return`${r.toFixed(1)}${this.controlsConfig.unitLabel}*${h.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateSizeTextPosition(){const{points:t}=this.zoneData;if(t.length<4)return{x:0,y:0};const[o,e,i,n]=t,{textPosition:s,textOffset:a}=this.zoneConfig,l=f().getApp().toFixedSize(a);let r,u;switch(s){case"top":{r={x:(o.x+e.x)/2,y:(o.y+e.y)/2};const t=h(d(e,o)),i={x:t.y,y:-t.x};u={x:i.x*l,y:i.y*l};break}case"right":{r={x:(e.x+i.x)/2,y:(e.y+i.y)/2};const t=h(d(e,i)),o={x:t.y,y:-t.x};u={x:o.x*l,y:o.y*l};break}case"bottom":{r={x:(n.x+i.x)/2,y:(n.y+i.y)/2};const t=h(d(n,i)),o={x:-t.y,y:t.x};u={x:o.x*l,y:o.y*l};break}case"left":{r={x:(o.x+n.x)/2,y:(o.y+n.y)/2};const t=h(d(n,o)),e={x:t.y,y:-t.x};u={x:e.x*l,y:e.y*l};break}default:r={x:(o.x+e.x)/2,y:(o.y+e.y)/2},u={x:0,y:l}}return{x:r.x+u.x,y:r.y+u.y}}calculateSizeTextRotation(){const{points:t}=this.zoneData;if(t.length<4)return 0;const[o,e,i,n]=t,{textPosition:s}=this.zoneConfig;let a,l;switch(s){case"top":default:a=o,l=e;break;case"right":a=e,l=i;break;case"bottom":a=i,l=n;break;case"left":a=n,l=o}return c(a,l)}calculateMoveButtonPosition(){const t=this.calculateOutlinePoints();if(t.length<4)return{x:0,y:0};const o=f(),{controls:e}=o.getConfig(),i=t[v.BUTTON_INDICES.MOVE],n=t[2],s=t[0],a=o.getApp().toFixedSize(e.moveButtonOffset);return p(i,n,s,a)}handleDragStart=()=>{if(!this.isEditingEnabled())return;const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-drag",!0)};handleDragMove=t=>{if(!this.isEditingEnabled()||0===this.initialZonePoints.length)return;const o=this.parent.toLocal(t.global),e=this.controlFill.getDragStartPosition();if(!e)return;const i=o.x-e.x,n=o.y-e.y;this.applyTranslation(i,n)};handleDragEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-drag"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyTranslation(t,o){this.zoneData.points=this.initialZonePoints.map(e=>({x:e.x+t,y:e.y+o})),this.drawZone(),this.updateControlButtonsPosition()}handleRotationStart=t=>{const o=f();this.totalRotationAngle=0,this.rotationCenter=t,this.initialZonePoints=this.zoneData.points.map(t=>({...t})),o.getApp().requestRender("zone-rotate",!0)};handleRotationMove=t=>{this.totalRotationAngle+=t,this.applyRotation(t)};handleRotationEnd=()=>{const t=f();this.rotationCenter=null,this.totalRotationAngle=0,this.initialZonePoints=[],t.getApp().stopRender("zone-rotate"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyRotation(t){this.rotationCenter&&(this.zoneData.points=g(this.zoneData.points,this.rotationCenter,t),this.drawZone(),this.updateControlButtonsPosition())}handleScaleStart=()=>{const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-scale",!0)};handleScaleMove=t=>{0!==this.initialZonePoints.length&&this.applyEdgeBasedScale(t)};handleScaleEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-scale"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyEdgeBasedScale(t){if(this.initialZonePoints.length<4)return;const o=f(),{FIXED:e}=v.BUTTON_INDICES,{x:i,y:n}=this.initialZonePoints[e],[,s,,a]=this.initialZonePoints,l={x:i,y:n},r=d(l,s),h=d(l,a),u=d(l,t),c=C(r),p=C(h);if(0===c||0===p)return;const g=o.metersToPixels(this.zoneConfig.minSize),[x,z]=[y(u,r,c,g),y(u,h,p,g)];this.zoneData.points=[l,{x:i+r.x*x,y:n+r.y*x},{x:i+r.x*x+h.x*z,y:n+r.y*x+h.y*z},{x:i+h.x*z,y:n+h.y*z}],this.drawZone(),this.updateControlButtonsPosition()}handleMoveStart=()=>{const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-move",!0)};handleMove=t=>{if(!this.isEditingEnabled()||0===this.initialZonePoints.length)return;const o=this.parent.toLocal(t.global),e=this.moveButton?.getDragStartPosition();if(!e)return;const i=o.x-e.x,n=o.y-e.y;this.applyTranslation(i,n)};handleMoveEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-move"),this.zoneEvents.onUpdate?.(this.getZoneData())};handleDelete=()=>{this.zoneEvents.onRemove?.(this.zoneData.id)};setupClickHandler(){this.clickHandler=new x(this,{onClick:()=>{this.isEditingEnabled()||this.zoneEvents?.onClick?.(this.getZoneData())},stopPropagation:!1})}drawZone(){const{points:t}=this.zoneData;t.length<4||(this.controlFill.updatePoints(t),this.zoneBorder.updatePoints(t),this.updateOutlineBorder(),this.updateMoveLine(),this.updateSizeText())}updateOutlineBorder(){const t=this.calculateOutlinePoints();this.outlineBorder.updatePoints(t)}updateMoveLine(){const t=this.calculateOutlinePoints(),o=this.calculateMoveLinePoints(t);this.moveLine.updatePoints(o)}updateSizeText(){if(!this.sizeText)return;const t=this.calculateZoneSizeText();this.sizeText.updateText(t),this.updateSizeTextPosition()}updateSizeTextPosition(){if(!this.sizeText)return;const t=this.calculateSizeTextPosition();this.sizeText.position.set(t.x,t.y);const o=this.calculateSizeTextRotation();this.sizeText.rotation=o}updateControlButtonsPosition(){if(!(this.deleteButton&&this.rotateButton&&this.scaleButton&&this.moveButton))return;const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:o,ROTATE:e,SCALE:i}=v.BUTTON_INDICES,n=this.calculateMoveButtonPosition();[{button:this.deleteButton,point:t[o]},{button:this.rotateButton,point:t[e]},{button:this.scaleButton,point:t[i]},{button:this.moveButton,point:n}].forEach(({button:t,point:o})=>t.position.set(o.x,o.y))}updateEditState(){const t=this.isEditingEnabled();this.controlButtons.visible=t,!t&&this.getCurrentOperationState().hasAnyOperation&&this.stopAllOperations(),this.outlineBorder.visible=t,this.moveLine.visible=t,this.sizeText&&(this.sizeText.visible=t),t&&(this.updateOutlineBorder(),this.updateMoveLine(),this.updateControlButtonsPosition(),this.updateSizeTextPosition()),this.controlFill.setInteractionEnabled(t),this.updateBorderStyle(t?this.zoneConfig.editing:this.zoneConfig.normal),this.zIndex=t?1e3:0}updateBorderStyle(t){this.zoneBorder.updateStyle({isDashed:t.isDashed,dashArray:t.dashArray})}getCurrentOperationState(){const t=this.controlFill.isCurrentlyDragging(),o=this.scaleButton?.isCurrentlyScaling()||!1,e=this.rotateButton?.isCurrentlyRotating()||!1,i=this.moveButton?.isCurrentlyMoving()||!1;return{isDragging:t,isScaling:o,isRotating:e,isMoving:i,hasAnyOperation:t||o||e||i}}stopAllOperations(){this.controlFill.stopDragging(),this.scaleButton?.stopScaling(),this.rotateButton?.stopRotation(),this.moveButton?.stopMoving()}stopDragging(){this.controlFill.stopDragging()}stopScaling(){this.scaleButton?.stopScaling()}stopRotating(){this.rotateButton?.stopRotation()}stopMoving(){this.moveButton?.stopMoving()}isCurrentlyDragging(){return this.controlFill.isCurrentlyDragging()}isCurrentlyScaling(){return this.scaleButton?.isCurrentlyScaling()||!1}isCurrentlyRotating(){return this.rotateButton?.isCurrentlyRotating()||!1}isCurrentlyMoving(){return this.moveButton?.isCurrentlyMoving()||!1}updateZoneData(t){const o=this.validateAndCorrectZoneSize(t.points),e=a(o);this.zoneData={...t,points:e},this.drawZone(),this.updateControlButtonsPosition(),this.updateEditState()}getZoneData(){return{...this.zoneData}}destroy(){f().emitter.off("antiScale",this.throttledUpdateOutline),this.clickHandler?.destroy(),this.clickHandler=null,this.deleteButton?.destroy(),this.rotateButton?.destroy(),this.scaleButton?.destroy(),this.moveButton?.destroy(),this.deleteButton=null,this.rotateButton=null,this.scaleButton=null,this.moveButton=null,this.zoneBorder?.destroy(),this.outlineBorder?.destroy(),this.moveLine?.destroy(),this.sizeText?.destroy(),this.controlFill?.destroy(),this.controlButtons?.destroy(),super.destroy()}}export{v as Zone};
1
+ import{Container as t}from"pixi.js";import{RotateControlButton as o}from"./RotateControlButton.js";import{RemoveControlButton as e}from"./RemoveControlButton.js";import{ScaleControlButton as i}from"./ScaleControlButton.js";import{MoveControlButton as n}from"./MoveControlButton.js";import{ControlFill as s}from"./ControlFill.js";import{normalizeToRectangle as a,getDistance as r,calculateCenter as l,normalizeVector as h,createVector as d,calculatePolygonOutline as u,calculateUprightLineAngle as c,calculateCornerExtension as p,rotatePointsAroundCenter as g,getVectorLength as C,calculateScaleRatio as y}from"../../utils/algorithm.js";import{ClickHandler as x}from"../../mixins/ClickHandler.js";import{throttle as z}from"lodash-es";import{Border as B}from"./Border.js";import{FixedSizeText as S}from"./FixedSizeText.js";import{useAppService as f}from"../../application/AppService.js";class v extends t{static BUTTON_INDICES={REMOVE:0,ROTATE:1,SCALE:2,MOVE:3,FIXED:0};zoneData;zoneType;zoneConfig;controlsConfig;zoneEvents;controlFill;zoneBorder;outlineBorder;moveLine;sizeText;controlButtons;deleteButton=null;rotateButton=null;scaleButton=null;moveButton=null;totalRotationAngle=0;rotationCenter=null;initialZonePoints=[];clickHandler=null;throttledUpdateOutline;constructor(t){super();const{zoneData:o,zoneType:e,events:i={}}=t;this.zoneType=e,this.zoneEvents=i,this.zoneConfig=this.getZoneConfig(),this.controlsConfig=this.getControlsConfig();const n=this.validateAndCorrectZoneSize(o.points),s=a(n);this.zoneData={...o,points:s},this.throttledUpdateOutline=z(this.updateOutlineForScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.createControlButtons(),this.updateEditState(),this.setupClickHandler(),this.registerScaleListener()}registerScaleListener(){f().emitter.on("antiScale",this.throttledUpdateOutline)}updateOutlineForScale(){this.isEditingEnabled()&&(this.updateOutlineBorder(),this.updateMoveLine(),this.updateControlButtonsPosition(),this.updateSizeTextPosition())}getZoneConfig(){const t=f(),{controls:o}=t.getConfig();return o[this.zoneType]}getControlsConfig(){const t=f(),{controls:o}=t.getConfig();return o}validateAndCorrectZoneSize(t){const o=f();if(t.length<4)return t;const e=o.metersToPixels(this.zoneConfig.minSize),[i,n,,s]=t,a=r(i,n),u=r(i,s);if(a>=e&&u>=e)return t;const c=l(t),p=h(d(i,n)),g=h(d(i,s)),C=Math.max(a,e)/2,y=Math.max(u,e)/2;return[{x:c.x-p.x*C-g.x*y,y:c.y-p.y*C-g.y*y},{x:c.x+p.x*C-g.x*y,y:c.y+p.y*C-g.y*y},{x:c.x+p.x*C+g.x*y,y:c.y+p.y*C+g.y*y},{x:c.x-p.x*C+g.x*y,y:c.y-p.y*C+g.y*y}]}getEditingIdsKey(){switch(this.zoneType){case"forbiddenSweepZone":default:return"editingForbiddenSweepZoneIds";case"forbiddenMopZone":return"editingForbiddenMopZoneIds";case"cleanZone":return"editingCleanZoneIds"}}isEditingEnabled(){const t=this.getEditingIdsKey();return f().runtimeSnapshot[t].includes(this.zoneData.id)}initializeComponents(){this.outlineBorder=this.createOutlineBorder(),this.addChild(this.outlineBorder),this.controlFill=this.createControlFill(),this.addChild(this.controlFill),this.zoneBorder=this.createBorder(),this.addChild(this.zoneBorder),this.moveLine=this.createMoveLine(),this.addChild(this.moveLine),this.sizeText=this.createSizeText(),this.addChild(this.sizeText),this.controlButtons=new t,this.controlButtons.visible=this.isEditingEnabled(),this.addChild(this.controlButtons),this.drawZone()}createControlButtons(){const t=this.calculateOutlinePoints();if(t.length<4)return;this.deleteButton=new e({iconAlias:"deleteIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,onClick:this.handleDelete}),this.deleteButton.position.set(t[v.BUTTON_INDICES.REMOVE].x,t[v.BUTTON_INDICES.REMOVE].y),this.zoneConfig.showRotateButton&&(this.rotateButton=new o({iconAlias:"rotateIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,getTargetPoints:()=>this.zoneData.points,onRotationStart:this.handleRotationStart,onRotationMove:this.handleRotationMove,onRotationEnd:this.handleRotationEnd}),this.rotateButton.position.set(t[v.BUTTON_INDICES.ROTATE].x,t[v.BUTTON_INDICES.ROTATE].y)),this.scaleButton=new i({iconAlias:"scaleIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,getTargetPoints:()=>this.zoneData.points,getButtonIndex:()=>v.BUTTON_INDICES.SCALE,onScaleStart:this.handleScaleStart,onScaleMove:this.handleScaleMove,onScaleEnd:this.handleScaleEnd}),this.scaleButton.position.set(t[v.BUTTON_INDICES.SCALE].x,t[v.BUTTON_INDICES.SCALE].y);const s=this.calculateMoveButtonPosition();this.moveButton=new n({iconAlias:"moveIcon",backgroundColor:this.zoneConfig.iconWrapperFillColor,onMoveStart:this.handleMoveStart,onMoveMove:this.handleMove,onMoveEnd:this.handleMoveEnd}),this.moveButton.position.set(s.x,s.y),this.controlButtons.addChild(this.deleteButton),this.rotateButton&&this.controlButtons.addChild(this.rotateButton),this.controlButtons.addChild(this.scaleButton),this.controlButtons.addChild(this.moveButton)}createControlFill(){const t=this.isEditingEnabled();return new s({points:this.zoneData.points,fillColor:this.zoneConfig.fillColor,enableInteraction:t,onDragStart:this.handleDragStart,onDragMove:this.handleDragMove,onDragEnd:this.handleDragEnd})}createBorder(){const t=this.isEditingEnabled()?this.zoneConfig.editing:this.zoneConfig.normal;return new B({points:this.zoneData.points,closePath:!0,style:{color:this.zoneConfig.strokeColor,width:this.zoneConfig.strokeWidth,isDashed:t.isDashed,dashArray:t.dashArray}})}createOutlineBorder(){const t=this.calculateOutlinePoints();return new B({points:t,closePath:!0,style:{color:this.zoneConfig.outlineStrokeColor,width:this.zoneConfig.outlineStrokeWidth,isDashed:this.zoneConfig.outlineDashed,dashArray:this.zoneConfig.outlineDashArray,fillColor:this.zoneConfig.outlineFillColor}})}createMoveLine(){const t=this.calculateOutlinePoints(),o=this.calculateMoveLinePoints(t);return new B({points:o,closePath:!1,style:{color:this.zoneConfig.outlineStrokeColor,width:this.zoneConfig.outlineStrokeWidth,isDashed:this.zoneConfig.outlineDashed,dashArray:this.zoneConfig.outlineDashArray}})}calculateOutlinePoints(){const{points:t}=this.zoneData;if(t.length<4)return t;const o=f().getApp().toFixedSize(this.zoneConfig.outlineOffset);return u(t,o)}calculateMoveLinePoints(t){return t.length<4?[]:[t[v.BUTTON_INDICES.MOVE],this.calculateMoveButtonPosition()]}createSizeText(){const t=this.calculateZoneSizeText(),o=new S({text:t,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.zoneConfig.textColor,align:"center"}});o.anchor.set(.5);const e=this.calculateSizeTextPosition();o.position.set(e.x,e.y);const i=this.calculateSizeTextRotation();return o.rotation=i,o.eventMode="none",o}calculateZoneSizeText(){const{points:t}=this.zoneData;if(t.length<4)return"0m*0m";const[o,e,,i]=t,n=r(o,e),s=r(o,i),a=f(),l=a.pixelsToMeters(n),h=a.pixelsToMeters(s);return`${l.toFixed(1)}${this.controlsConfig.unitLabel}*${h.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateSizeTextPosition(){const{points:t}=this.zoneData;if(t.length<4)return{x:0,y:0};const[o,e,i,n]=t,{textPosition:s,textOffset:a}=this.zoneConfig,r=f().getApp().toFixedSize(a);let l,u;switch(s){case"top":{l={x:(o.x+e.x)/2,y:(o.y+e.y)/2};const t=h(d(e,o)),i={x:t.y,y:-t.x};u={x:i.x*r,y:i.y*r};break}case"right":{l={x:(e.x+i.x)/2,y:(e.y+i.y)/2};const t=h(d(e,i)),o={x:t.y,y:-t.x};u={x:o.x*r,y:o.y*r};break}case"bottom":{l={x:(n.x+i.x)/2,y:(n.y+i.y)/2};const t=h(d(n,i)),o={x:-t.y,y:t.x};u={x:o.x*r,y:o.y*r};break}case"left":{l={x:(o.x+n.x)/2,y:(o.y+n.y)/2};const t=h(d(n,o)),e={x:t.y,y:-t.x};u={x:e.x*r,y:e.y*r};break}default:l={x:(o.x+e.x)/2,y:(o.y+e.y)/2},u={x:0,y:r}}return{x:l.x+u.x,y:l.y+u.y}}calculateSizeTextRotation(){const{points:t}=this.zoneData;if(t.length<4)return 0;const[o,e,i,n]=t,{textPosition:s}=this.zoneConfig;let a,r;switch(s){case"top":default:a=o,r=e;break;case"right":a=e,r=i;break;case"bottom":a=i,r=n;break;case"left":a=n,r=o}return c(a,r)}calculateMoveButtonPosition(){const t=this.calculateOutlinePoints();if(t.length<4)return{x:0,y:0};const o=f(),{controls:e}=o.getConfig(),i=t[v.BUTTON_INDICES.MOVE],n=t[2],s=t[0],a=o.getApp().toFixedSize(e.moveButtonOffset);return p(i,n,s,a)}handleDragStart=()=>{if(!this.isEditingEnabled())return;const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-drag",!0)};handleDragMove=t=>{if(!this.isEditingEnabled()||0===this.initialZonePoints.length)return;const o=this.parent.toLocal(t.global),e=this.controlFill.getDragStartPosition();if(!e)return;const i=o.x-e.x,n=o.y-e.y;this.applyTranslation(i,n)};handleDragEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-drag"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyTranslation(t,o){this.zoneData.points=this.initialZonePoints.map(e=>({x:e.x+t,y:e.y+o})),this.drawZone(),this.updateControlButtonsPosition()}handleRotationStart=t=>{const o=f();this.totalRotationAngle=0,this.rotationCenter=t,this.initialZonePoints=this.zoneData.points.map(t=>({...t})),o.getApp().requestRender("zone-rotate",!0)};handleRotationMove=t=>{this.totalRotationAngle+=t,this.applyRotation(t)};handleRotationEnd=()=>{const t=f();this.rotationCenter=null,this.totalRotationAngle=0,this.initialZonePoints=[],t.getApp().stopRender("zone-rotate"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyRotation(t){this.rotationCenter&&(this.zoneData.points=g(this.zoneData.points,this.rotationCenter,t),this.drawZone(),this.updateControlButtonsPosition())}handleScaleStart=()=>{const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-scale",!0)};handleScaleMove=t=>{0!==this.initialZonePoints.length&&this.applyEdgeBasedScale(t)};handleScaleEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-scale"),this.zoneEvents.onUpdate?.(this.getZoneData())};applyEdgeBasedScale(t){if(this.initialZonePoints.length<4)return;const o=f(),{FIXED:e}=v.BUTTON_INDICES,{x:i,y:n}=this.initialZonePoints[e],[,s,,a]=this.initialZonePoints,r={x:i,y:n},l=d(r,s),h=d(r,a),u=d(r,t),c=C(l),p=C(h);if(0===c||0===p)return;const g=o.metersToPixels(this.zoneConfig.minSize),[x,z]=[y(u,l,c,g),y(u,h,p,g)];this.zoneData.points=[r,{x:i+l.x*x,y:n+l.y*x},{x:i+l.x*x+h.x*z,y:n+l.y*x+h.y*z},{x:i+h.x*z,y:n+h.y*z}],this.drawZone(),this.updateControlButtonsPosition()}handleMoveStart=()=>{const t=f();this.initialZonePoints=this.zoneData.points.map(t=>({...t})),t.getApp().requestRender("zone-move",!0)};handleMove=t=>{if(!this.isEditingEnabled()||0===this.initialZonePoints.length)return;const o=this.parent.toLocal(t.global),e=this.moveButton?.getDragStartPosition();if(!e)return;const i=o.x-e.x,n=o.y-e.y;this.applyTranslation(i,n)};handleMoveEnd=()=>{const t=f();this.initialZonePoints=[],t.getApp().stopRender("zone-move"),this.zoneEvents.onUpdate?.(this.getZoneData())};handleDelete=()=>{this.zoneEvents.onRemove?.(this.zoneData.id)};setupClickHandler(){this.clickHandler=new x(this,{onClick:()=>{this.isEditingEnabled()||this.zoneEvents?.onClick?.(this.getZoneData())},stopPropagation:!1})}drawZone(){const{points:t}=this.zoneData;t.length<4||(this.controlFill.updatePoints(t),this.zoneBorder.updatePoints(t),this.updateOutlineBorder(),this.updateMoveLine(),this.updateSizeText())}updateOutlineBorder(){const t=this.calculateOutlinePoints();this.outlineBorder.updatePoints(t)}updateMoveLine(){const t=this.calculateOutlinePoints(),o=this.calculateMoveLinePoints(t);this.moveLine.updatePoints(o)}updateSizeText(){if(!this.sizeText)return;const t=this.calculateZoneSizeText();this.sizeText.updateText(t),this.updateSizeTextPosition()}updateSizeTextPosition(){if(!this.sizeText)return;const t=this.calculateSizeTextPosition();this.sizeText.position.set(t.x,t.y);const o=this.calculateSizeTextRotation();this.sizeText.rotation=o}updateControlButtonsPosition(){if(!this.deleteButton||!this.scaleButton||!this.moveButton)return;const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:o,ROTATE:e,SCALE:i}=v.BUTTON_INDICES,n=this.calculateMoveButtonPosition(),s=[{button:this.deleteButton,point:t[o]},{button:this.scaleButton,point:t[i]},{button:this.moveButton,point:n}];this.rotateButton&&s.push({button:this.rotateButton,point:t[e]}),s.forEach(({button:t,point:o})=>t.position.set(o.x,o.y))}updateEditState(){const t=this.isEditingEnabled();this.controlButtons.visible=t,!t&&this.getCurrentOperationState().hasAnyOperation&&this.stopAllOperations(),this.outlineBorder.visible=t,this.moveLine.visible=t,this.sizeText&&(this.sizeText.visible=t),t&&(this.updateOutlineBorder(),this.updateMoveLine(),this.updateControlButtonsPosition(),this.updateSizeTextPosition()),this.controlFill.setInteractionEnabled(t),this.updateBorderStyle(t?this.zoneConfig.editing:this.zoneConfig.normal),this.zIndex=t?1e3:0}updateBorderStyle(t){this.zoneBorder.updateStyle({isDashed:t.isDashed,dashArray:t.dashArray})}getCurrentOperationState(){const t=this.controlFill.isCurrentlyDragging(),o=this.scaleButton?.isCurrentlyScaling()||!1,e=this.rotateButton?.isCurrentlyRotating()||!1,i=this.moveButton?.isCurrentlyMoving()||!1;return{isDragging:t,isScaling:o,isRotating:e,isMoving:i,hasAnyOperation:t||o||e||i}}stopAllOperations(){this.controlFill.stopDragging(),this.scaleButton?.stopScaling(),this.rotateButton?.stopRotation(),this.moveButton?.stopMoving()}stopDragging(){this.controlFill.stopDragging()}stopScaling(){this.scaleButton?.stopScaling()}stopRotating(){this.rotateButton?.stopRotation()}stopMoving(){this.moveButton?.stopMoving()}isCurrentlyDragging(){return this.controlFill.isCurrentlyDragging()}isCurrentlyScaling(){return this.scaleButton?.isCurrentlyScaling()||!1}isCurrentlyRotating(){return this.rotateButton?.isCurrentlyRotating()||!1}isCurrentlyMoving(){return this.moveButton?.isCurrentlyMoving()||!1}updateZoneData(t){const o=this.validateAndCorrectZoneSize(t.points),e=a(o);this.zoneData={...t,points:e},this.drawZone(),this.updateControlButtonsPosition(),this.updateEditState()}getZoneData(){return{...this.zoneData}}destroy(){f().emitter.off("antiScale",this.throttledUpdateOutline),this.clickHandler?.destroy(),this.clickHandler=null,this.deleteButton?.destroy(),this.rotateButton?.destroy(),this.scaleButton?.destroy(),this.moveButton?.destroy(),this.deleteButton=null,this.rotateButton=null,this.scaleButton=null,this.moveButton=null,this.zoneBorder?.destroy(),this.outlineBorder?.destroy(),this.moveLine?.destroy(),this.sizeText?.destroy(),this.controlFill?.destroy(),this.controlButtons?.destroy(),super.destroy()}}export{v as Zone};
@@ -1 +1 @@
1
- import{Container as i}from"pixi.js";import{ChargingStationIcon as t}from"./ChargingStationIcon.js";import{LAYER_CHARGING_STATION as n}from"../../application/AppContainer.js";import{subscribeKey as r}from"valtio/vanilla/utils";import{Logger as s}from"../../utils/logger.js";import{useAppService as o}from"../../application/AppService.js";import{Ring as a}from"../Base/Ring.js";class g extends i{chargingStation;ring;unsubscribeFns=[];constructor(){super();const i=o();i.appContainer.addToLayer(n,this),this.ring=new a({config:i.chargingStationConfig}),this.ring.visible=i.runtimeSnapshot.showChargingStationRing,this.addChild(this.ring),this.chargingStation=new t,this.addChild(this.chargingStation);const g=r(i.runtime,"showChargingStationRing",i=>{s.log(`[runtime] showChargingStationRing: ${i}`),this.ring.visible=i});this.unsubscribeFns.push(g)}async draw({x:i,y:t,rotation:n}){0===i&&0===t||(this.ring.draw({x:i,y:t}),await this.chargingStation.draw({x:i,y:t,rotation:n}))}destroy(){this.unsubscribeFns.forEach(i=>i()),this.unsubscribeFns=[],this.ring.destroy(),super.destroy()}}export{g as ChargingStation};
1
+ import{Container as i}from"pixi.js";import{ChargingStationIcon as t}from"./ChargingStationIcon.js";import{LAYER_CHARGING_STATION as n}from"../../application/AppContainer.js";import{subscribeKey as r}from"valtio/vanilla/utils";import{Ring as s}from"../Base/Ring.js";import{Logger as o}from"../../utils/logger.js";import{useAppService as a}from"../../application/AppService.js";class g extends i{chargingStation;ring;unsubscribeFns=[];constructor(){super();const i=a();i.appContainer.addToLayer(n,this),this.ring=new s({config:i.chargingStationConfig}),this.ring.visible=i.runtimeSnapshot.showChargingStationRing,this.addChild(this.ring),this.chargingStation=new t,this.addChild(this.chargingStation);const g=r(i.runtime,"showChargingStationRing",i=>{o.log(`[runtime] showChargingStationRing: ${i}`),this.ring.visible=i});this.unsubscribeFns.push(g)}async draw({x:i,y:t,rotation:n}){0===i&&0===t||(this.ring.draw({x:i,y:t}),await this.chargingStation.draw({x:i,y:t,rotation:n}))}destroy(){this.unsubscribeFns.forEach(i=>i()),this.unsubscribeFns=[],this.ring.destroy(),super.destroy()}}export{g as ChargingStation};
@@ -1 +1 @@
1
- import{Container as i,Polygon as t,Graphics as e}from"pixi.js";import{calculateLineEndpoints as n,calculateLineSegmentHitArea as s,sampleLinePoints as o,getDistance as r,extendLineSegment as d,isPointInPolygon as a,lineIntersectsBox as h}from"../../utils/algorithm.js";import{throttle as l}from"lodash-es";import{Logger as g}from"../../utils/logger.js";import{useAppService as c}from"../../application/AppService.js";import{DashLine as u}from"../Base/DashLine.js";import{EndPoint as p}from"../Base/EndPoint.js";class P extends i{endPoints;dividerConfig;dividerEvents;roomId;roomGeometry=null;dashLine;solidLine=null;startEndPoint;endEndPoint;solidLinePoints=null;initialDividerPoints=[];isDragging=!1;dragStartPosition=null;throttledHandleScaleChange;constructor(i){super();const{endPoints:t,roomId:e,events:n={}}=i;this.dividerEvents=n,this.roomId=e;const s=c();this.dividerConfig=s.dividerConfig,this.roomGeometry=s.mapManager.getRoomById(this.roomId)||null,this.endPoints=t?this.validateDividerPoints(t):this.createDefaultdividerPoints(),this.throttledHandleScaleChange=l(this.handleScaleChange.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.calculateAndCreateSolidLine(),this.registerScaleListener(),this.setupDragEventListeners()}validateDividerPoints(i){if(i.length>=2)return i.slice(0,2);const t=i[0]||{x:0,y:0};return[t,{x:t.x+50,y:t.y}]}createDefaultdividerPoints(){if(!this.roomGeometry)return g.warn("Room geometry not available, creating fallback divider"),[{x:0,y:0},{x:100,y:0}];const i=c(),t=i.getApp().mapState;if(!t)return g.warn("Map state not available, creating fallback divider"),[{x:0,y:0},{x:100,y:0}];const{boundingBox:e}=this.roomGeometry,s=i.getApp().toFixedSize(this.dividerConfig.defaultExtension),o=this.dividerConfig.defaultDirection,r=e.x+e.width/2,d=e.y+e.height/2,a="horizontal"===o?e.width+2*s:e.height+2*s;return n(r,d,a,o).map(i=>({x:i.x-t.origin.x,y:i.y-t.origin.y}))}initializeComponents(){this.createDashLine(),this.addChild(this.dashLine),this.createEndPoints(),this.addChild(this.startEndPoint),this.addChild(this.endEndPoint),this.setupDashLineInteraction()}createDashLine(){const i=this.endPoints;if(i.length<2)return;const{dashLineWidth:t,dashLineDashArray:e,lineColor:n}=this.dividerConfig;this.dashLine=new u({start:i[0],end:i[1],style:{color:n.toString(),width:t,dashArray:e}})}createEndPoints(){const i=this.endPoints;this.startEndPoint=new p({position:i[0],config:this.dividerConfig,onDragStart:this.handleEndPointDragStart,onDragMove:i=>this.handleEndPointDragMove(0,i),onDragEnd:this.handleEndPointDragEnd}),this.endEndPoint=new p({position:i[1],config:this.dividerConfig,onDragStart:this.handleEndPointDragStart,onDragMove:i=>this.handleEndPointDragMove(1,i),onDragEnd:this.handleEndPointDragEnd})}setupDashLineInteraction(){this.dashLine&&(this.setupDashLineHitArea(),this.dashLine.off("pointerdown",this.handleDashLinePointerDown),this.dashLine.on("pointerdown",this.handleDashLinePointerDown))}setupDashLineHitArea(){const i=c();if(!this.dashLine)return;const e=this.endPoints;if(e.length<2)return;const{hitAreaThickness:n}=this.dividerConfig,o=i.getApp().toFixedSize(n),r=s(e[0],e[1],o);if(0===r.length)return;const d=new t(r);this.dashLine.hitArea=d}handleEndPointDragStart=()=>{const i=c();this.initialDividerPoints=this.endPoints.map(i=>({...i})),this.clearSolidLine(),i.getApp().requestRender("divider-endpoint-drag",!0)};handleEndPointDragMove=(i,t)=>{0!==this.initialDividerPoints.length&&(this.endPoints[i]=t,this.updateDashLine(),this.updateSolidLine(),this.setupDashLineHitArea())};handleEndPointDragEnd=()=>{const i=c();this.initialDividerPoints=[],i.getApp().stopRender("divider-endpoint-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints())};handleDashLinePointerDown=i=>{i.stopPropagation(),this.startDragging(i)};startDragging(i){const t=c();this.isDragging=!0;const e=this.parent.toLocal(i.global);this.dragStartPosition={x:e.x,y:e.y},this.initialDividerPoints=this.endPoints.map(i=>({...i})),this.clearSolidLine(),t.getApp().requestRender("divider-drag",!0),c().emitter.emit("gestureHijackStart",i)}setupDragEventListeners(){const{emitter:i}=c();i.on("gestureHijackPointerMove",this.handleDragPointerMove),i.on("gestureHijackPointerUp",this.handleDragPointerUp),i.on("gestureHijackCancel",this.handleDragCancel)}cleanupDragEventListeners(){const{emitter:i}=c();i.off("gestureHijackPointerMove",this.handleDragPointerMove),i.off("gestureHijackPointerUp",this.handleDragPointerUp),i.off("gestureHijackCancel",this.handleDragCancel)}handleDragPointerMove=i=>{if(!this.isDragging||!this.dragStartPosition||0===this.initialDividerPoints.length)return;const t=this.parent.toLocal(i.global),e=t.x-this.dragStartPosition.x,n=t.y-this.dragStartPosition.y;this.endPoints=this.initialDividerPoints.map(i=>({x:i.x+e,y:i.y+n})),this.updateAllComponents()};handleDragPointerUp=()=>{const i=c();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[],i.getApp().stopRender("divider-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints()))};handleDragCancel=()=>{const i=c();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[],i.getApp().stopRender("divider-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints()))};updateAllComponents(){this.updateDashLine(),this.updateSolidLine(),this.updateEndPoints(),this.setupDashLineHitArea()}updateDashLine(){const i=this.endPoints;i.length<2||!this.dashLine||this.dashLine.updatePoints(i[0],i[1])}updateSolidLine(){if(!this.solidLine||!this.solidLinePoints)return;const{solidLineWidth:i,lineColor:t}=this.dividerConfig,e=c().getApp().toFixedSize(i);this.solidLine.clear(),this.solidLine.setStrokeStyle({color:t.toString(),width:e}).moveTo(this.solidLinePoints[0].x,this.solidLinePoints[0].y).lineTo(this.solidLinePoints[1].x,this.solidLinePoints[1].y).stroke()}updateEndPoints(){const i=this.endPoints;this.startEndPoint&&this.startEndPoint.updatePosition(i[0]),this.endEndPoint&&this.endEndPoint.updatePosition(i[1])}registerScaleListener(){const{emitter:i}=c();i.on("antiScale",this.throttledHandleScaleChange)}handleScaleChange=()=>{this.startEndPoint?.redraw(),this.endEndPoint?.redraw(),this.updateSolidLine(),this.setupDashLineHitArea()};getDividerEndPoints(){return[...this.endPoints]}getEffectiveDividerPoints(){return this.solidLinePoints?[...this.solidLinePoints]:null}calculateAndCreateSolidLine(){if(this.clearSolidLine(),!this.roomId)return;if(!this.getRoomGraphics())return;const i=this.calculateLineRoomIntersection();i&&i.length>=2&&(this.solidLinePoints=[i[0],i[i.length-1]],this.createSolidLine())}getRoomGraphics(){const i=c().mapManager.roomFill;return i&&this.roomId&&i.getRoomGraphicsMap().get(this.roomId)||null}calculateLineRoomIntersection(){const i=this.endPoints;if(i.length<2)return null;if(!this.roomId)return null;const[t,e]=i,n=this.isPointInRoomFill(t),s=this.isPointInRoomFill(e);if(n||s)return null;const a=o(t,e),h=[];for(const i of a)this.isPointInRoomFill(i)&&h.push(i);if(0===h.length)return null;const l=h[0],g=h[h.length-1];return r(l,g)<3?null:d(l,g,.5)}isPointInRoomFill(i){if(!this.roomId)return!1;const t=c().getApp().mapState;if(!t)return!1;const e={x:i.x+t.origin.x,y:i.y+t.origin.y};return this.isRasterData()?this.isPointInRasterRoomFill(e):this.isPointInStructuredRoomFill(e)}isPointInRasterRoomFill(i){i.x-=.5,i.y-=.5;const t=c(),e=t.getApp().mapState,n=t.mapManager.roomFill;if(!e||!n)return!1;const s=n.getRasterRoomData(this.roomId);if(!s)return!1;const o=n.getMapWidth();if(0===o)return!1;const r=Math.round(i.y)*o+Math.round(i.x);for(let i=0;i<s.pixelIndices.length;i++)if(s.pixelIndices[i]===r)return!0;return!1}isPointInStructuredRoomFill(i){const t={x:Math.round(i.x),y:Math.round(i.y)},e=c(),n=e.getApp().mapState,s=e.mapManager.getRoomById(this.roomId);return!!(n&&s&&s.outlinePoints)&&a(t,s.outlinePoints,!0)}isRasterData(){const i=c().mapManager.getRoomById(this.roomId);return!i||!i.outlinePoints||0===i.outlinePoints.length}isDividerCompletelyOutOfRoom(){if(!this.roomGeometry)return!1;const{boundingBox:i}=this.roomGeometry,t=this.endPoints;if(t.length<2)return!1;const e=c().getApp().mapState;if(!e)return!1;const n={x:t[0].x+e.origin.x,y:t[0].y+e.origin.y},s={x:t[1].x+e.origin.x,y:t[1].y+e.origin.y};return!h(n,s,i.x,i.y,i.width,i.height)}checkAndResetIfOutOfRoom(){const i=c(),{resetDividerWhenOutOfRoom:t}=i.dividerConfig;t&&this.isDividerCompletelyOutOfRoom()&&this.resetToDefaultState()}resetToDefaultState(){this.endPoints=this.createDefaultdividerPoints(),this.calculateAndCreateSolidLine(),this.updateComponents(),this.dividerEvents.onUpdate?.(this.endPoints)}updateComponents(){const i=this.endPoints;i.length>=2&&(this.dashLine.updatePoints(i[0],i[1]),this.startEndPoint.position.set(i[0].x,i[0].y),this.endEndPoint.position.set(i[1].x,i[1].y),this.setupDashLineInteraction())}createSolidLine(){if(!this.solidLinePoints)return;const{solidLineWidth:i,lineColor:t}=this.dividerConfig,n=c();this.solidLine=new e,this.solidLine.eventMode="none";const s=n.getApp().toFixedSize(i);this.solidLine.setStrokeStyle({color:t.toString(),width:s}).moveTo(this.solidLinePoints[0].x,this.solidLinePoints[0].y).lineTo(this.solidLinePoints[1].x,this.solidLinePoints[1].y).stroke(),this.addChildAt(this.solidLine,0)}clearSolidLine(){this.solidLine&&(this.removeChild(this.solidLine),this.solidLine.destroy(),this.solidLine=null),this.solidLinePoints=null}updatedividerPoints(i){this.endPoints=this.validateDividerPoints(i),this.updateAllComponents(),this.calculateAndCreateSolidLine()}destroy(){c().emitter.off("antiScale",this.throttledHandleScaleChange),this.cleanupDragEventListeners(),this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[]),this.dashLine&&this.dashLine.off("pointerdown",this.handleDashLinePointerDown),this.clearSolidLine(),this.dashLine?.destroy(),this.startEndPoint?.destroy(),this.endEndPoint?.destroy(),super.destroy()}}export{P as Divider};
1
+ import{Container as i,Polygon as t,Graphics as e}from"pixi.js";import{DashLine as n}from"../Base/DashLine.js";import{EndPoint as s}from"../Base/EndPoint.js";import{calculateLineEndpoints as o,calculateLineSegmentHitArea as r,sampleLinePoints as d,getDistance as a,extendLineSegment as h,isPointInPolygon as l,lineIntersectsBox as g}from"../../utils/algorithm.js";import{throttle as c}from"lodash-es";import{Logger as u}from"../../utils/logger.js";import{useAppService as p}from"../../application/AppService.js";class P extends i{endPoints;dividerConfig;dividerEvents;roomId;roomGeometry=null;dashLine;solidLine=null;startEndPoint;endEndPoint;solidLinePoints=null;initialDividerPoints=[];isDragging=!1;dragStartPosition=null;throttledHandleScaleChange;constructor(i){super();const{endPoints:t,roomId:e,events:n={}}=i;this.dividerEvents=n,this.roomId=e;const s=p();this.dividerConfig=s.dividerConfig,this.roomGeometry=s.mapManager.getRoomById(this.roomId)||null,this.endPoints=t?this.validateDividerPoints(t):this.createDefaultdividerPoints(),this.throttledHandleScaleChange=c(this.handleScaleChange.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.calculateAndCreateSolidLine(),this.registerScaleListener(),this.setupDragEventListeners()}validateDividerPoints(i){if(i.length>=2)return i.slice(0,2);const t=i[0]||{x:0,y:0};return[t,{x:t.x+50,y:t.y}]}createDefaultdividerPoints(){if(!this.roomGeometry)return u.warn("Room geometry not available, creating fallback divider"),[{x:0,y:0},{x:100,y:0}];const i=p(),t=i.getApp().mapState;if(!t)return u.warn("Map state not available, creating fallback divider"),[{x:0,y:0},{x:100,y:0}];const{boundingBox:e}=this.roomGeometry,n=i.getApp().toFixedSize(this.dividerConfig.defaultExtension),s=this.dividerConfig.defaultDirection,r=e.x+e.width/2,d=e.y+e.height/2,a="horizontal"===s?e.width+2*n:e.height+2*n;return o(r,d,a,s).map(i=>({x:i.x-t.origin.x,y:i.y-t.origin.y}))}initializeComponents(){this.createDashLine(),this.addChild(this.dashLine),this.createEndPoints(),this.addChild(this.startEndPoint),this.addChild(this.endEndPoint),this.setupDashLineInteraction()}createDashLine(){const i=this.endPoints;if(i.length<2)return;const{dashLineWidth:t,dashLineDashArray:e,lineColor:s}=this.dividerConfig;this.dashLine=new n({start:i[0],end:i[1],style:{color:s.toString(),width:t,dashArray:e}})}createEndPoints(){const i=this.endPoints;this.startEndPoint=new s({position:i[0],config:this.dividerConfig,onDragStart:this.handleEndPointDragStart,onDragMove:i=>this.handleEndPointDragMove(0,i),onDragEnd:this.handleEndPointDragEnd}),this.endEndPoint=new s({position:i[1],config:this.dividerConfig,onDragStart:this.handleEndPointDragStart,onDragMove:i=>this.handleEndPointDragMove(1,i),onDragEnd:this.handleEndPointDragEnd})}setupDashLineInteraction(){this.dashLine&&(this.setupDashLineHitArea(),this.dashLine.off("pointerdown",this.handleDashLinePointerDown),this.dashLine.on("pointerdown",this.handleDashLinePointerDown))}setupDashLineHitArea(){const i=p();if(!this.dashLine)return;const e=this.endPoints;if(e.length<2)return;const{hitAreaThickness:n}=this.dividerConfig,s=i.getApp().toFixedSize(n),o=r(e[0],e[1],s);if(0===o.length)return;const d=new t(o);this.dashLine.hitArea=d}handleEndPointDragStart=()=>{const i=p();this.initialDividerPoints=this.endPoints.map(i=>({...i})),this.clearSolidLine(),i.getApp().requestRender("divider-endpoint-drag",!0)};handleEndPointDragMove=(i,t)=>{0!==this.initialDividerPoints.length&&(this.endPoints[i]=t,this.updateDashLine(),this.updateSolidLine(),this.setupDashLineHitArea())};handleEndPointDragEnd=()=>{const i=p();this.initialDividerPoints=[],i.getApp().stopRender("divider-endpoint-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints())};handleDashLinePointerDown=i=>{i.stopPropagation(),this.startDragging(i)};startDragging(i){const t=p();this.isDragging=!0;const e=this.parent.toLocal(i.global);this.dragStartPosition={x:e.x,y:e.y},this.initialDividerPoints=this.endPoints.map(i=>({...i})),this.clearSolidLine(),t.getApp().requestRender("divider-drag",!0),p().emitter.emit("gestureHijackStart",i)}setupDragEventListeners(){const{emitter:i}=p();i.on("gestureHijackPointerMove",this.handleDragPointerMove),i.on("gestureHijackPointerUp",this.handleDragPointerUp),i.on("gestureHijackCancel",this.handleDragCancel)}cleanupDragEventListeners(){const{emitter:i}=p();i.off("gestureHijackPointerMove",this.handleDragPointerMove),i.off("gestureHijackPointerUp",this.handleDragPointerUp),i.off("gestureHijackCancel",this.handleDragCancel)}handleDragPointerMove=i=>{if(!this.isDragging||!this.dragStartPosition||0===this.initialDividerPoints.length)return;const t=this.parent.toLocal(i.global),e=t.x-this.dragStartPosition.x,n=t.y-this.dragStartPosition.y;this.endPoints=this.initialDividerPoints.map(i=>({x:i.x+e,y:i.y+n})),this.updateAllComponents()};handleDragPointerUp=()=>{const i=p();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[],i.getApp().stopRender("divider-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints()))};handleDragCancel=()=>{const i=p();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[],i.getApp().stopRender("divider-drag"),this.calculateAndCreateSolidLine(),this.checkAndResetIfOutOfRoom(),this.dividerEvents.onUpdate?.(this.getDividerEndPoints()))};updateAllComponents(){this.updateDashLine(),this.updateSolidLine(),this.updateEndPoints(),this.setupDashLineHitArea()}updateDashLine(){const i=this.endPoints;i.length<2||!this.dashLine||this.dashLine.updatePoints(i[0],i[1])}updateSolidLine(){if(!this.solidLine||!this.solidLinePoints)return;const{solidLineWidth:i,lineColor:t}=this.dividerConfig,e=p().getApp().toFixedSize(i);this.solidLine.clear(),this.solidLine.setStrokeStyle({color:t.toString(),width:e}).moveTo(this.solidLinePoints[0].x,this.solidLinePoints[0].y).lineTo(this.solidLinePoints[1].x,this.solidLinePoints[1].y).stroke()}updateEndPoints(){const i=this.endPoints;this.startEndPoint&&this.startEndPoint.updatePosition(i[0]),this.endEndPoint&&this.endEndPoint.updatePosition(i[1])}registerScaleListener(){const{emitter:i}=p();i.on("antiScale",this.throttledHandleScaleChange)}handleScaleChange=()=>{this.startEndPoint?.redraw(),this.endEndPoint?.redraw(),this.updateSolidLine(),this.setupDashLineHitArea()};getDividerEndPoints(){return[...this.endPoints]}getEffectiveDividerPoints(){return this.solidLinePoints?[...this.solidLinePoints]:null}calculateAndCreateSolidLine(){if(this.clearSolidLine(),!this.roomId)return;if(!this.getRoomGraphics())return;const i=this.calculateLineRoomIntersection();i&&i.length>=2&&(this.solidLinePoints=[i[0],i[i.length-1]],this.createSolidLine())}getRoomGraphics(){const i=p().mapManager.roomFill;return i&&this.roomId&&i.getRoomGraphicsMap().get(this.roomId)||null}calculateLineRoomIntersection(){const i=this.endPoints;if(i.length<2)return null;if(!this.roomId)return null;const[t,e]=i,n=this.isPointInRoomFill(t),s=this.isPointInRoomFill(e);if(n||s)return null;const o=d(t,e),r=[];for(const i of o)this.isPointInRoomFill(i)&&r.push(i);if(0===r.length)return null;const l=r[0],g=r[r.length-1];return a(l,g)<3?null:h(l,g,.5)}isPointInRoomFill(i){if(!this.roomId)return!1;const t=p().getApp().mapState;if(!t)return!1;const e={x:i.x+t.origin.x,y:i.y+t.origin.y};return"raster"===t.mapType?this.isPointInRasterRoomFill(e):this.isPointInStructuredRoomFill(e)}isPointInRasterRoomFill(i){i.x-=.5,i.y-=.5;const t=p(),e=t.getApp().mapState,n=t.mapManager.roomFill;if(!e||!n)return!1;const s=n.getRasterRoomData(this.roomId);if(!s)return!1;const o=n.getMapWidth();if(0===o)return!1;const r=Math.round(i.y)*o+Math.round(i.x);for(let i=0;i<s.pixelIndices.length;i++)if(s.pixelIndices[i]===r)return!0;return!1}isPointInStructuredRoomFill(i){const t={x:Math.round(i.x),y:Math.round(i.y)},e=p(),n=e.getApp().mapState,s=e.mapManager.getRoomById(this.roomId);return!!(n&&s&&s.outlinePoints)&&l(t,s.outlinePoints,!0)}isDividerCompletelyOutOfRoom(){if(!this.roomGeometry)return!1;const{boundingBox:i}=this.roomGeometry,t=this.endPoints;if(t.length<2)return!1;const e=p().getApp().mapState;if(!e)return!1;const n={x:t[0].x+e.origin.x,y:t[0].y+e.origin.y},s={x:t[1].x+e.origin.x,y:t[1].y+e.origin.y};return!g(n,s,i.x,i.y,i.width,i.height)}checkAndResetIfOutOfRoom(){const i=p(),{resetDividerWhenOutOfRoom:t}=i.dividerConfig;t&&this.isDividerCompletelyOutOfRoom()&&this.resetToDefaultState()}resetToDefaultState(){this.endPoints=this.createDefaultdividerPoints(),this.calculateAndCreateSolidLine(),this.updateComponents(),this.dividerEvents.onUpdate?.(this.endPoints)}updateComponents(){const i=this.endPoints;i.length>=2&&(this.dashLine.updatePoints(i[0],i[1]),this.startEndPoint.position.set(i[0].x,i[0].y),this.endEndPoint.position.set(i[1].x,i[1].y),this.setupDashLineInteraction())}createSolidLine(){if(!this.solidLinePoints)return;const{solidLineWidth:i,lineColor:t}=this.dividerConfig,n=p();this.solidLine=new e,this.solidLine.eventMode="none";const s=n.getApp().toFixedSize(i);this.solidLine.setStrokeStyle({color:t.toString(),width:s}).moveTo(this.solidLinePoints[0].x,this.solidLinePoints[0].y).lineTo(this.solidLinePoints[1].x,this.solidLinePoints[1].y).stroke(),this.addChildAt(this.solidLine,0)}clearSolidLine(){this.solidLine&&(this.removeChild(this.solidLine),this.solidLine.destroy(),this.solidLine=null),this.solidLinePoints=null}updatedividerPoints(i){this.endPoints=this.validateDividerPoints(i),this.updateAllComponents(),this.calculateAndCreateSolidLine()}destroy(){p().emitter.off("antiScale",this.throttledHandleScaleChange),this.cleanupDragEventListeners(),this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,this.initialDividerPoints=[]),this.dashLine&&this.dashLine.off("pointerdown",this.handleDashLinePointerDown),this.clearSolidLine(),this.dashLine?.destroy(),this.startEndPoint?.destroy(),this.endEndPoint?.destroy(),super.destroy()}}export{P as Divider};
@@ -1 +1 @@
1
- import{Container as t}from"pixi.js";import{ControlFill as i}from"../Base/ControlFill.js";import{Border as e}from"../Base/Border.js";import{FixedSizeText as s}from"../Base/FixedSizeText.js";import{ClickHandler as o}from"../../mixins/ClickHandler.js";import{throttle as n}from"lodash-es";import{useAppService as a}from"../../application/AppService.js";import{EnhancedSprite as r}from"../Base/EnhancedSprite.js";class l extends t{spotData;spotConfig;controlsConfig;spotEvents;controlFill;spotBorder;centerIcon;sizeText;clickHandler=null;initialSpotPoint=null;throttledUpdateScale;constructor(t){super();const{spotData:i,events:e={}}=t,s=a();this.spotData=i,this.spotEvents=e,this.controlsConfig=s.controlsConfig,this.spotConfig=s.controlsConfig.spot,this.throttledUpdateScale=n(this.updateScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.updateEditState(),this.setupClickHandler(),this.registerScaleListener()}registerScaleListener(){a().emitter.on("antiScale",this.throttledUpdateScale)}updateScale(){this.isEditingEnabled()&&this.updateSizeTextPosition()}isEditingEnabled(){return a().runtimeSnapshot.editingSpotIds.includes(this.spotData.id)}calculateRectanglePoints(){const t=a(),{point:i}=this.spotData,{size:e}=this.spotConfig,s=t.metersToPixels(e)/2;return[{x:i.x-s,y:i.y-s},{x:i.x+s,y:i.y-s},{x:i.x+s,y:i.y+s},{x:i.x-s,y:i.y+s}]}initializeComponents(){const t=this.calculateRectanglePoints();this.controlFill=this.createControlFill(t),this.addChild(this.controlFill),this.spotBorder=this.createBorder(t),this.addChild(this.spotBorder),this.centerIcon=this.createCenterIcon(),this.addChild(this.centerIcon),this.sizeText=this.createSizeText(),this.addChild(this.sizeText),this.drawSpot()}createControlFill(t){const e=this.isEditingEnabled();return new i({points:t,fillColor:this.spotConfig.fillColor,enableInteraction:e,onDragStart:this.handleDragStart,onDragMove:this.handleDragMove,onDragEnd:this.handleDragEnd})}createBorder(t){const i=this.isEditingEnabled()?this.spotConfig.editing:this.spotConfig.normal;return new e({points:t,closePath:!0,style:{color:this.spotConfig.strokeColor,width:this.spotConfig.strokeWidth,isDashed:i.isDashed,dashArray:i.dashArray}})}createCenterIcon(){const t=new r;return this.loadIconTexture(t),t.position.set(this.spotData.point.x,this.spotData.point.y),t.eventMode="none",t.visible=!1,t}async loadIconTexture(t){const{iconSize:i}=this.spotConfig;await t.loadTextureAndSetSize("spotIcon",{width:i,height:i,sizeFixed:!1}),t.visible=this.isEditingEnabled()}createSizeText(){const t=this.calculateSpotSizeText(),i=new s({text:t,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.spotConfig.textColor,align:"center"}});i.anchor.set(.5);const e=this.calculateSizeTextPosition();return i.position.set(e.x,e.y),i.eventMode="none",i}calculateSpotSizeText(){const{size:t}=this.spotConfig;return`${t.toFixed(1)}${this.controlsConfig.unitLabel}*${t.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateSizeTextPosition(){const t=a(),i=this.calculateRectanglePoints();if(i.length<4)return{x:0,y:0};const[e,s,o,n]=i,{textPosition:r,textOffset:l}=this.spotConfig,h=t.getApp().toFixedSize(l);let c,d;switch(r){case"top":default:c={x:(e.x+s.x)/2,y:(e.y+s.y)/2},d={x:c.x,y:c.y+h};break;case"right":c={x:(s.x+o.x)/2,y:(s.y+o.y)/2},d={x:c.x+h,y:c.y};break;case"bottom":c={x:(n.x+o.x)/2,y:(n.y+o.y)/2},d={x:c.x,y:c.y+h};break;case"left":c={x:(e.x+n.x)/2,y:(e.y+n.y)/2},d={x:c.x-h,y:c.y}}return d}handleDragStart=()=>{const t=a();this.isEditingEnabled()&&(this.initialSpotPoint={...this.spotData.point},t.getApp().requestRender("spot-drag",!0))};handleDragMove=t=>{if(!this.isEditingEnabled()||!this.initialSpotPoint)return;const i=this.parent.toLocal(t.global),e=this.controlFill.getDragStartPosition();if(!e)return;const s=i.x-e.x,o=i.y-e.y;this.applyTranslation(s,o)};handleDragEnd=()=>{const t=a();this.initialSpotPoint=null,t.getApp().stopRender("spot-drag"),this.spotEvents.onUpdate?.(this.getSpotData())};applyTranslation(t,i){this.initialSpotPoint&&(this.spotData.point={x:this.initialSpotPoint.x+t,y:this.initialSpotPoint.y+i},this.drawSpot())}setupClickHandler(){this.clickHandler=new o(this,{onClick:()=>{this.isEditingEnabled()||this.spotEvents?.onClick?.(this.getSpotData())},stopPropagation:!1})}drawSpot(){const t=this.calculateRectanglePoints();this.controlFill.updatePoints(t),this.spotBorder.updatePoints(t),this.centerIcon.position.set(this.spotData.point.x,this.spotData.point.y),this.updateSizeText()}updateSizeText(){if(!this.sizeText)return;const t=this.calculateSpotSizeText();this.sizeText.updateText(t),this.updateSizeTextPosition()}updateSizeTextPosition(){if(!this.sizeText)return;const t=this.calculateSizeTextPosition();this.sizeText.position.set(t.x,t.y)}updateEditState(){const t=this.isEditingEnabled();if(this.sizeText&&(this.sizeText.visible=t),this.centerIcon&&(this.centerIcon.visible=t),this.controlFill&&this.controlFill.setInteractionEnabled(t),this.spotBorder){const i=t?this.spotConfig.editing:this.spotConfig.normal;this.spotBorder.updateStyle({isDashed:i.isDashed,dashArray:i.dashArray})}this.zIndex=t?1e3:0}updateSpotData(t){this.spotData={...t},this.drawSpot(),this.updateEditState()}getSpotData(){return{...this.spotData}}destroy(){a().emitter.off("antiScale",this.throttledUpdateScale),this.clickHandler?.destroy(),this.clickHandler=null,this.controlFill?.destroy(),this.spotBorder?.destroy(),this.centerIcon?.destroy(),this.sizeText?.destroy(),super.destroy()}static create(t){const i=a();return new l({spotData:t,events:{onUpdate:t=>{i.events?.onUpdateSpot?.(t)},onClick:t=>{i.events?.onClickSpot?.(t)}}})}}export{l as Spot};
1
+ import{Container as t}from"pixi.js";import{ControlFill as i}from"../Base/ControlFill.js";import{Border as e}from"../Base/Border.js";import{FixedSizeText as s}from"../Base/FixedSizeText.js";import{ClickHandler as o}from"../../mixins/ClickHandler.js";import{throttle as n}from"lodash-es";import{EnhancedSprite as a}from"../Base/EnhancedSprite.js";import{useAppService as r}from"../../application/AppService.js";class l extends t{spotData;spotConfig;controlsConfig;spotEvents;controlFill;spotBorder;centerIcon;sizeText;clickHandler=null;initialSpotPoint=null;throttledUpdateScale;constructor(t){super();const{spotData:i,events:e={}}=t,s=r();this.spotData=i,this.spotEvents=e,this.controlsConfig=s.controlsConfig,this.spotConfig=s.controlsConfig.spot,this.throttledUpdateScale=n(this.updateScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.updateEditState(),this.setupClickHandler(),this.registerScaleListener()}registerScaleListener(){r().emitter.on("antiScale",this.throttledUpdateScale)}updateScale(){this.isEditingEnabled()&&this.updateSizeTextPosition()}isEditingEnabled(){return r().runtimeSnapshot.editingSpotIds.includes(this.spotData.id)}calculateRectanglePoints(){const t=r(),{point:i}=this.spotData,{size:e}=this.spotConfig,s=t.metersToPixels(e)/2;return[{x:i.x-s,y:i.y-s},{x:i.x+s,y:i.y-s},{x:i.x+s,y:i.y+s},{x:i.x-s,y:i.y+s}]}initializeComponents(){const t=this.calculateRectanglePoints();this.controlFill=this.createControlFill(t),this.addChild(this.controlFill),this.spotBorder=this.createBorder(t),this.addChild(this.spotBorder),this.centerIcon=this.createCenterIcon(),this.addChild(this.centerIcon),this.sizeText=this.createSizeText(),this.addChild(this.sizeText),this.drawSpot()}createControlFill(t){const e=this.isEditingEnabled();return new i({points:t,fillColor:this.spotConfig.fillColor,enableInteraction:e,onDragStart:this.handleDragStart,onDragMove:this.handleDragMove,onDragEnd:this.handleDragEnd})}createBorder(t){const i=this.isEditingEnabled()?this.spotConfig.editing:this.spotConfig.normal;return new e({points:t,closePath:!0,style:{color:this.spotConfig.strokeColor,width:this.spotConfig.strokeWidth,isDashed:i.isDashed,dashArray:i.dashArray}})}createCenterIcon(){const t=new a;return this.loadIconTexture(t),t.position.set(this.spotData.point.x,this.spotData.point.y),t.eventMode="none",t.visible=!1,t}async loadIconTexture(t){const{iconSize:i}=this.spotConfig;await t.loadTextureAndSetSize("spotIcon",{width:i,height:i,sizeFixed:!1}),t.visible=this.isEditingEnabled()}createSizeText(){const t=this.calculateSpotSizeText(),i=new s({text:t,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.spotConfig.textColor,align:"center"}});i.anchor.set(.5);const e=this.calculateSizeTextPosition();return i.position.set(e.x,e.y),i.eventMode="none",i}calculateSpotSizeText(){const{size:t}=this.spotConfig;return`${t.toFixed(1)}${this.controlsConfig.unitLabel}*${t.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateSizeTextPosition(){const t=r(),i=this.calculateRectanglePoints();if(i.length<4)return{x:0,y:0};const[e,s,o,n]=i,{textPosition:a,textOffset:l}=this.spotConfig,h=t.getApp().toFixedSize(l);let c,d;switch(a){case"top":default:c={x:(e.x+s.x)/2,y:(e.y+s.y)/2},d={x:c.x,y:c.y+h};break;case"right":c={x:(s.x+o.x)/2,y:(s.y+o.y)/2},d={x:c.x+h,y:c.y};break;case"bottom":c={x:(n.x+o.x)/2,y:(n.y+o.y)/2},d={x:c.x,y:c.y+h};break;case"left":c={x:(e.x+n.x)/2,y:(e.y+n.y)/2},d={x:c.x-h,y:c.y}}return d}handleDragStart=()=>{const t=r();this.isEditingEnabled()&&(this.initialSpotPoint={...this.spotData.point},t.getApp().requestRender("spot-drag",!0))};handleDragMove=t=>{if(!this.isEditingEnabled()||!this.initialSpotPoint)return;const i=this.parent.toLocal(t.global),e=this.controlFill.getDragStartPosition();if(!e)return;const s=i.x-e.x,o=i.y-e.y;this.applyTranslation(s,o)};handleDragEnd=()=>{const t=r();this.initialSpotPoint=null,t.getApp().stopRender("spot-drag"),this.spotEvents.onUpdate?.(this.getSpotData())};applyTranslation(t,i){this.initialSpotPoint&&(this.spotData.point={x:this.initialSpotPoint.x+t,y:this.initialSpotPoint.y+i},this.drawSpot())}setupClickHandler(){this.clickHandler=new o(this,{onClick:()=>{this.isEditingEnabled()||this.spotEvents?.onClick?.(this.getSpotData())},stopPropagation:!1})}drawSpot(){const t=this.calculateRectanglePoints();this.controlFill.updatePoints(t),this.spotBorder.updatePoints(t),this.centerIcon.position.set(this.spotData.point.x,this.spotData.point.y),this.updateSizeText()}updateSizeText(){if(!this.sizeText)return;const t=this.calculateSpotSizeText();this.sizeText.updateText(t),this.updateSizeTextPosition()}updateSizeTextPosition(){if(!this.sizeText)return;const t=this.calculateSizeTextPosition();this.sizeText.position.set(t.x,t.y)}updateEditState(){const t=this.isEditingEnabled();if(this.sizeText&&(this.sizeText.visible=t),this.centerIcon&&(this.centerIcon.visible=t),this.controlFill&&this.controlFill.setInteractionEnabled(t),this.spotBorder){const i=t?this.spotConfig.editing:this.spotConfig.normal;this.spotBorder.updateStyle({isDashed:i.isDashed,dashArray:i.dashArray})}this.zIndex=t?1e3:0}updateSpotData(t){this.spotData={...t},this.drawSpot(),this.updateEditState()}getSpotData(){return{...this.spotData}}destroy(){r().emitter.off("antiScale",this.throttledUpdateScale),this.clickHandler?.destroy(),this.clickHandler=null,this.controlFill?.destroy(),this.spotBorder?.destroy(),this.centerIcon?.destroy(),this.sizeText?.destroy(),super.destroy()}static create(t){const i=r();return new l({spotData:t,events:{onUpdate:t=>{i.events?.onUpdateSpot?.(t)},onClick:t=>{i.events?.onClickSpot?.(t)}}})}}export{l as Spot};
@@ -1 +1 @@
1
- import{Container as t,Graphics as i,Polygon as e}from"pixi.js";import{getDistance as n,normalizeVector as l,createVector as o,calculateLineMidpointOffset as s,calculateUprightLineAngle as a,calculateLineSegmentOutline as r,calculateCornerExtension as h,calculateLineSegmentHitArea as d}from"../../utils/algorithm.js";import{throttle as c}from"lodash-es";import{ClickHandler as u}from"../../mixins/ClickHandler.js";import{useAppService as g}from"../../application/AppService.js";import{DashLine as p}from"../Base/DashLine.js";import{FixedSizeText as w}from"../Base/FixedSizeText.js";import{Border as C}from"../Base/Border.js";import{RemoveControlButton as f}from"../Base/RemoveControlButton.js";import{ScaleControlButton as L}from"../Base/ScaleControlButton.js";import{MoveControlButton as v}from"../Base/MoveControlButton.js";class m extends t{static BUTTON_INDICES={REMOVE:0,SCALE:2,MOVE:3};wallData;wallConfig;controlsConfig;wallEvents;wallLine;outlineBorder;moveLine;lengthText;controlButtons;removeButton=null;scaleButton=null;moveButton=null;initialWallPoints=[];isDragging=!1;dragStartPosition=null;throttledUpdateOutline;throttledHandleScaleChange;wallLineClickHandler=null;constructor(t){super();const{wallData:i,events:e={}}=t;this.wallEvents=e;const n=g();this.wallConfig=n.controlsConfig.virtualWall,this.controlsConfig=n.controlsConfig,this.wallData={...i,points:this.validateAndCorrectWallLength(i.points)},this.throttledHandleScaleChange=c(this.handleScaleChange.bind(this),30,{leading:!0,trailing:!0}),this.throttledUpdateOutline=c(this.updateOutlineForScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.updateEditState(),this.registerScaleListener(),this.setupDragEventListeners()}validateAndCorrectWallLength(t){const i=g();if(t.length<2)return t;const[e,s]=t,a=i.metersToPixels(this.wallConfig.minWidth),r=n(e,s);if(r>=a)return t;if(0===r)return[e,{x:e.x+a,y:e.y}];const h=l(o(e,s));return[e,{x:e.x+h.x*a,y:e.y+h.y*a}]}isEditingEnabled(){return g().runtimeSnapshot.editingVirtualWallIds.includes(this.wallData.id)}updateOutlineForScale(){this.isEditingEnabled()&&(this.updateOutlineComponents(),this.updateControlButtonsPosition(),this.updateLengthTextPosition())}initializeComponents(){this.outlineBorder=this.createOutlineBorder(),this.addChild(this.outlineBorder),this.createWallLine(!1),this.addChild(this.wallLine),this.lengthText=this.createLengthText(),this.addChild(this.lengthText),this.moveLine=this.createMoveLine(),this.addChild(this.moveLine),this.controlButtons=new t,this.controlButtons.visible=this.isEditingEnabled(),this.addChild(this.controlButtons),this.createControlButtons()}createWallLine(t=!0){const{points:i}=this.wallData;if(i.length<2)return;const{lineWidth:e,lineColor:n,editing:l,normal:o}=this.wallConfig,s=this.isEditingEnabled()?l:o;s.isDashed?this.wallLine=new p({start:i[0],end:i[1],style:{color:n.toString(),width:e,dashArray:s.dashArray}}):this.wallLine=this.createSolidLine(i[0],i[1],e,n.toString()),t&&this.setupWallLineInteraction()}createLengthText(){const t=this.calculateWallLengthInMeters(),i=this.formatLengthText(t),e=new w({text:i,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.wallConfig.textColor,align:"center"}});e.anchor.set(.5);const n=this.calculateTextPosition();e.position.set(n.x,n.y);const l=this.calculateTextRotation();return e.rotation=l,e.eventMode="none",e}calculateWallLengthInMeters(){const t=g(),{points:i}=this.wallData;if(i.length<2)return 0;const e=n(i[0],i[1]);return t.pixelsToMeters(e)}formatLengthText(t){return`${t.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateTextPosition(){const t=g(),{points:i}=this.wallData;if(i.length<2)return{x:0,y:0};const[e,n]=i,l=t.getApp().toFixedSize(this.wallConfig.textOffset);return s(e,n,l)}calculateTextRotation(){const{points:t}=this.wallData;if(t.length<2)return 0;const[i,e]=t;return a(i,e)}getOutlineStyle(){return{color:this.wallConfig.outlineStrokeColor,width:this.wallConfig.outlineStrokeWidth,isDashed:this.wallConfig.outlineDashed,dashArray:this.wallConfig.outlineDashArray,fillColor:this.wallConfig.outlineFillColor}}createOutlineBorder(){const t=this.calculateOutlinePoints();return new C({points:t,closePath:!0,style:this.getOutlineStyle()})}createMoveLine(){const t=this.calculateOutlinePoints(),i=this.calculateMoveLinePoints(t);return new C({points:i,closePath:!1,style:this.getOutlineStyle()})}calculateOutlinePoints(t){const i=g(),e=t||this.wallData.points;if(e.length<2)return e;const n=i.getApp().toFixedSize(this.wallConfig.outlineOffset),l=r(e[0],e[1],n);return[l[3],l[2],l[1],l[0]]}calculateMoveLinePoints(t){if(t.length<4)return[];const{MOVE:i}=m.BUTTON_INDICES;return[t[i],this.calculateMoveButtonPosition()]}calculateMoveButtonPosition(){const t=g(),{moveButtonOffset:i}=this.controlsConfig,e=this.calculateOutlinePoints();if(e.length<4)return{x:0,y:0};const{MOVE:n}=m.BUTTON_INDICES,l=e[n],o=e[(n+3)%4],s=e[(n+1)%4],a=t.getApp().toFixedSize(i);return h(l,s,o,a)}createControlButtons(){const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:i,SCALE:e}=m.BUTTON_INDICES;this.removeButton=new f({iconAlias:"deleteIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,onClick:this.handleRemove}),this.removeButton.position.set(t[i].x,t[i].y),this.scaleButton=new L({iconAlias:"scaleIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,getTargetPoints:()=>this.calculateOutlinePoints(),getButtonIndex:()=>e,onScaleStart:this.handleScaleStart,onScaleMove:this.handleScaleMove,onScaleEnd:this.handleScaleEnd}),this.scaleButton.position.set(t[e].x,t[e].y);const n=this.calculateMoveButtonPosition();this.moveButton=new v({iconAlias:"moveIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,onMoveStart:this.handleMoveStart,onMoveMove:this.handleMove,onMoveEnd:this.handleMoveEnd}),this.moveButton.position.set(n.x,n.y),this.controlButtons.addChild(this.removeButton),this.controlButtons.addChild(this.scaleButton),this.controlButtons.addChild(this.moveButton)}handleRemove=()=>{this.wallEvents.onRemove?.(this.wallData.id)};initializeOperation=()=>{this.initialWallPoints=this.wallData.points.map(t=>({...t}))};finalizeOperation=()=>{this.initialWallPoints=[],this.wallEvents.onUpdate?.(this.getWallData())};handleScaleStart=()=>{const t=g();this.initializeOperation(),t.getApp().requestRender("virtualwall-scale",!0)};handleScaleMove=t=>{0!==this.initialWallPoints.length&&this.applyScaleAndRotation(t)};handleScaleEnd=()=>{const t=g();this.finalizeOperation(),t.getApp().stopRender("virtualwall-scale")};handleMoveStart=()=>{const t=g();this.initializeOperation(),t.getApp().requestRender("virtualwall-move",!0)};handleMove=t=>{if(0===this.initialWallPoints.length)return;const i=this.parent.toLocal(t.global),e=this.getDragStartPosition()||this.moveButton?.getDragStartPosition();if(!e)return;const n=i.x-e.x,l=i.y-e.y;this.applyTranslation(n,l)};handleMoveEnd=()=>{const t=g();this.finalizeOperation(),t.getApp().stopRender("virtualwall-move")};applyScaleAndRotation(t){const i=g();if(this.initialWallPoints.length<2)return;const[e,s]=this.initialWallPoints,a=e,r=this.calculateOutlinePoints(this.initialWallPoints);if(r.length<4)return;const h=r[m.BUTTON_INDICES.SCALE],d=o(s,h),c={x:t.x-d.x,y:t.y-d.y},u=o(a,c),p=n(a,c),w=i.metersToPixels(this.wallConfig.minWidth);let C;if(p<w)if(0===p)C={x:a.x+w,y:a.y};else{const t=l(u);C={x:a.x+t.x*w,y:a.y+t.y*w}}else C=c;this.wallData.points=[a,C],this.updateAllComponents(),this.updateControlButtonsPosition()}applyTranslation(t,i){this.wallData.points=this.initialWallPoints.map(e=>({x:e.x+t,y:e.y+i})),this.updateAllComponents(),this.updateControlButtonsPosition()}updateAllComponents(){this.updateWallLine(),this.updateLengthText(),this.updateOutlineComponents()}updateWallLine(){const{points:t}=this.wallData;t.length<2||(this.wallLine instanceof p?this.wallLine.updatePoints(t[0],t[1]):this.redrawSolidLine(),this.setupWallLineHitArea())}updateLengthText(){if(!this.lengthText)return;const t=this.calculateWallLengthInMeters(),i=this.formatLengthText(t);this.lengthText.updateText(i),this.updateLengthTextPosition()}updateLengthTextPosition(){if(!this.lengthText)return;const t=this.calculateTextPosition();this.lengthText.position.set(t.x,t.y);const i=this.calculateTextRotation();this.lengthText.rotation=i}updateOutlineComponents(){const t=this.calculateOutlinePoints();this.outlineBorder.updatePoints(t);const i=this.calculateMoveLinePoints(t);this.moveLine.updatePoints(i)}updateControlButtonsPosition(){if(!this.removeButton||!this.scaleButton||!this.moveButton)return;const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:i,SCALE:e}=m.BUTTON_INDICES,n=this.calculateMoveButtonPosition();this.removeButton.position.set(t[i].x,t[i].y),this.scaleButton.position.set(t[e].x,t[e].y),this.moveButton.position.set(n.x,n.y)}updateEditState(){const t=this.isEditingEnabled();this.controlButtons.visible=t,this.outlineBorder.visible=t,this.moveLine.visible=t,this.lengthText&&(this.lengthText.visible=t),t&&(this.updateOutlineComponents(),this.updateControlButtonsPosition(),this.updateLengthTextPosition()),this.updateWallLineStyle(),this.setupWallLineInteraction(),this.zIndex=t?1e3:0}createSolidLine(t,e,n,l){const o=g(),s=new i;s.eventMode="static";const a=o.getApp().toFixedSize(n);return s.moveTo(t.x,t.y),s.lineTo(e.x,e.y),s.stroke({color:l,width:a}),s}updateWallLineStyle(){const t=this.isEditingEnabled(),{editing:i,normal:e,lineWidth:n,lineColor:l}=this.wallConfig,o=t?i:e;this.wallLine instanceof p!==o.isDashed?(this.removeChild(this.wallLine),this.wallLine.destroy(),this.createWallLine(!1),this.addChild(this.wallLine)):this.wallLine instanceof p?this.wallLine.updateStyle({color:l.toString(),width:n,dashArray:o.dashArray}):this.redrawSolidLine()}registerScaleListener(){const{emitter:t}=g();t.on("antiScale",this.throttledUpdateOutline),t.on("antiScale",this.throttledHandleScaleChange)}redrawSolidLine(){const t=g();if(!this.wallLine||this.wallLine instanceof p)return;const{points:i}=this.wallData;if(i.length<2)return;const{lineWidth:e,lineColor:n}=this.wallConfig,l=t.getApp().toFixedSize(e);this.wallLine.clear(),this.wallLine.setStrokeStyle({color:n.toString(),width:l}).moveTo(i[0].x,i[0].y).lineTo(i[1].x,i[1].y).stroke()}handleScaleChange=()=>{this.redrawSolidLine(),this.setupWallLineHitArea()};setupWallLineInteraction(){if(!this.wallLine)return;this.setupWallLineHitArea();const t=this.isEditingEnabled();this.wallLineClickHandler?.destroy(),this.wallLineClickHandler=null,this.wallLine.off("pointerdown",this.handleWallLinePointerDown),t?this.wallLine.on("pointerdown",this.handleWallLinePointerDown):this.wallLineClickHandler=new u(this.wallLine,{onClick:()=>{this.wallEvents?.onClick?.(this.getWallData())},stopPropagation:!1})}setupDragEventListeners(){const{emitter:t}=g();t.on("gestureHijackPointerMove",this.handleDragPointerMove),t.on("gestureHijackPointerUp",this.handleDragPointerUp),t.on("gestureHijackCancel",this.handleDragCancel)}cleanupDragEventListeners(){const{emitter:t}=g();t.off("gestureHijackPointerMove",this.handleDragPointerMove),t.off("gestureHijackPointerUp",this.handleDragPointerUp),t.off("gestureHijackCancel",this.handleDragCancel)}handleWallLinePointerDown=t=>{this.isEditingEnabled()&&(t.stopPropagation(),this.startDragging(t))};startDragging(t){const i=g();this.isDragging=!0;const e=this.parent.toLocal(t.global);this.dragStartPosition={x:e.x,y:e.y},this.initializeOperation(),i.getApp().requestRender("virtualwall-drag",!0),g().emitter.emit("gestureHijackStart",t)}handleDragPointerMove=t=>{this.isDragging&&this.dragStartPosition&&this.handleMove(t)};handleDragPointerUp=()=>{const t=g();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,t.getApp().stopRender("virtualwall-drag"),this.finalizeOperation())};handleDragCancel=()=>{const t=g();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,t.getApp().stopRender("virtualwall-drag"),this.handleMoveEnd())};getDragStartPosition(){return this.dragStartPosition}setupWallLineHitArea(){const t=g();if(!this.wallLine)return;const{points:i}=this.wallData;if(i.length<2)return;const{hitAreaThickness:n}=this.wallConfig,l=t.getApp().toFixedSize(n),o=d(i[0],i[1],l);if(0===o.length)return;const s=new e(o);this.wallLine.hitArea=s}getWallData(){return{...this.wallData}}updateWallData(t){this.wallData={...t,points:this.validateAndCorrectWallLength(t.points)},this.updateAllComponents(),this.updateControlButtonsPosition()}updateEditingState(){this.updateEditState()}destroy(){g().emitter.off("antiScale",this.throttledUpdateOutline),g().emitter.off("antiScale",this.throttledHandleScaleChange),this.cleanupDragEventListeners(),this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null),this.wallLine&&this.wallLine.off("pointerdown",this.handleWallLinePointerDown),this.wallLineClickHandler?.destroy(),this.wallLineClickHandler=null,this.wallLine?.destroy(),this.lengthText?.destroy(),this.outlineBorder?.destroy(),this.moveLine?.destroy(),this.controlButtons?.destroy(),this.removeButton?.destroy(),this.scaleButton?.destroy(),this.moveButton?.destroy(),this.removeButton=null,this.scaleButton=null,this.moveButton=null,super.destroy()}}export{m as VirtualWall};
1
+ import{Container as t,Graphics as i,Polygon as e}from"pixi.js";import{getDistance as n,normalizeVector as l,createVector as o,calculateLineMidpointOffset as s,calculateUprightLineAngle as a,calculateLineSegmentOutline as r,calculateCornerExtension as h,calculateLineSegmentHitArea as d}from"../../utils/algorithm.js";import{throttle as c}from"lodash-es";import{ClickHandler as u}from"../../mixins/ClickHandler.js";import{Border as g}from"../Base/Border.js";import{DashLine as p}from"../Base/DashLine.js";import{FixedSizeText as w}from"../Base/FixedSizeText.js";import{MoveControlButton as C}from"../Base/MoveControlButton.js";import{RemoveControlButton as f}from"../Base/RemoveControlButton.js";import{ScaleControlButton as L}from"../Base/ScaleControlButton.js";import{useAppService as v}from"../../application/AppService.js";class m extends t{static BUTTON_INDICES={REMOVE:0,SCALE:2,MOVE:3};wallData;wallConfig;controlsConfig;wallEvents;wallLine;outlineBorder;moveLine;lengthText;controlButtons;removeButton=null;scaleButton=null;moveButton=null;initialWallPoints=[];isDragging=!1;dragStartPosition=null;throttledUpdateOutline;throttledHandleScaleChange;wallLineClickHandler=null;constructor(t){super();const{wallData:i,events:e={}}=t;this.wallEvents=e;const n=v();this.wallConfig=n.controlsConfig.virtualWall,this.controlsConfig=n.controlsConfig,this.wallData={...i,points:this.validateAndCorrectWallLength(i.points)},this.throttledHandleScaleChange=c(this.handleScaleChange.bind(this),30,{leading:!0,trailing:!0}),this.throttledUpdateOutline=c(this.updateOutlineForScale.bind(this),30,{leading:!0,trailing:!0}),this.initializeComponents(),this.updateEditState(),this.registerScaleListener(),this.setupDragEventListeners()}validateAndCorrectWallLength(t){const i=v();if(t.length<2)return t;const[e,s]=t,a=i.metersToPixels(this.wallConfig.minWidth),r=n(e,s);if(r>=a)return t;if(0===r)return[e,{x:e.x+a,y:e.y}];const h=l(o(e,s));return[e,{x:e.x+h.x*a,y:e.y+h.y*a}]}isEditingEnabled(){return v().runtimeSnapshot.editingVirtualWallIds.includes(this.wallData.id)}updateOutlineForScale(){this.isEditingEnabled()&&(this.updateOutlineComponents(),this.updateControlButtonsPosition(),this.updateLengthTextPosition())}initializeComponents(){this.outlineBorder=this.createOutlineBorder(),this.addChild(this.outlineBorder),this.createWallLine(!1),this.addChild(this.wallLine),this.lengthText=this.createLengthText(),this.addChild(this.lengthText),this.moveLine=this.createMoveLine(),this.addChild(this.moveLine),this.controlButtons=new t,this.controlButtons.visible=this.isEditingEnabled(),this.addChild(this.controlButtons),this.createControlButtons()}createWallLine(t=!0){const{points:i}=this.wallData;if(i.length<2)return;const{lineWidth:e,lineColor:n,editing:l,normal:o}=this.wallConfig,s=this.isEditingEnabled()?l:o;s.isDashed?this.wallLine=new p({start:i[0],end:i[1],style:{color:n.toString(),width:e,dashArray:s.dashArray}}):this.wallLine=this.createSolidLine(i[0],i[1],e,n.toString()),t&&this.setupWallLineInteraction()}createLengthText(){const t=this.calculateWallLengthInMeters(),i=this.formatLengthText(t),e=new w({text:i,style:{fontSize:this.controlsConfig.textFontSize,fontFamily:this.controlsConfig.textFontFamily,fontWeight:this.controlsConfig.textFontWeight,fill:this.wallConfig.textColor,align:"center"}});e.anchor.set(.5);const n=this.calculateTextPosition();e.position.set(n.x,n.y);const l=this.calculateTextRotation();return e.rotation=l,e.eventMode="none",e}calculateWallLengthInMeters(){const t=v(),{points:i}=this.wallData;if(i.length<2)return 0;const e=n(i[0],i[1]);return t.pixelsToMeters(e)}formatLengthText(t){return`${t.toFixed(1)}${this.controlsConfig.unitLabel}`}calculateTextPosition(){const t=v(),{points:i}=this.wallData;if(i.length<2)return{x:0,y:0};const[e,n]=i,l=t.getApp().toFixedSize(this.wallConfig.textOffset);return s(e,n,l)}calculateTextRotation(){const{points:t}=this.wallData;if(t.length<2)return 0;const[i,e]=t;return a(i,e)}getOutlineStyle(){return{color:this.wallConfig.outlineStrokeColor,width:this.wallConfig.outlineStrokeWidth,isDashed:this.wallConfig.outlineDashed,dashArray:this.wallConfig.outlineDashArray,fillColor:this.wallConfig.outlineFillColor}}createOutlineBorder(){const t=this.calculateOutlinePoints();return new g({points:t,closePath:!0,style:this.getOutlineStyle()})}createMoveLine(){const t=this.calculateOutlinePoints(),i=this.calculateMoveLinePoints(t);return new g({points:i,closePath:!1,style:this.getOutlineStyle()})}calculateOutlinePoints(t){const i=v(),e=t||this.wallData.points;if(e.length<2)return e;const n=i.getApp().toFixedSize(this.wallConfig.outlineOffset),l=r(e[0],e[1],n);return[l[3],l[2],l[1],l[0]]}calculateMoveLinePoints(t){if(t.length<4)return[];const{MOVE:i}=m.BUTTON_INDICES;return[t[i],this.calculateMoveButtonPosition()]}calculateMoveButtonPosition(){const t=v(),{moveButtonOffset:i}=this.controlsConfig,e=this.calculateOutlinePoints();if(e.length<4)return{x:0,y:0};const{MOVE:n}=m.BUTTON_INDICES,l=e[n],o=e[(n+3)%4],s=e[(n+1)%4],a=t.getApp().toFixedSize(i);return h(l,s,o,a)}createControlButtons(){const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:i,SCALE:e}=m.BUTTON_INDICES;this.removeButton=new f({iconAlias:"deleteIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,onClick:this.handleRemove}),this.removeButton.position.set(t[i].x,t[i].y),this.scaleButton=new L({iconAlias:"scaleIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,getTargetPoints:()=>this.calculateOutlinePoints(),getButtonIndex:()=>e,onScaleStart:this.handleScaleStart,onScaleMove:this.handleScaleMove,onScaleEnd:this.handleScaleEnd}),this.scaleButton.position.set(t[e].x,t[e].y);const n=this.calculateMoveButtonPosition();this.moveButton=new C({iconAlias:"moveIcon",backgroundColor:this.wallConfig.iconWrapperFillColor,onMoveStart:this.handleMoveStart,onMoveMove:this.handleMove,onMoveEnd:this.handleMoveEnd}),this.moveButton.position.set(n.x,n.y),this.controlButtons.addChild(this.removeButton),this.controlButtons.addChild(this.scaleButton),this.controlButtons.addChild(this.moveButton)}handleRemove=()=>{this.wallEvents.onRemove?.(this.wallData.id)};initializeOperation=()=>{this.initialWallPoints=this.wallData.points.map(t=>({...t}))};finalizeOperation=()=>{this.initialWallPoints=[],this.wallEvents.onUpdate?.(this.getWallData())};handleScaleStart=()=>{const t=v();this.initializeOperation(),t.getApp().requestRender("virtualwall-scale",!0)};handleScaleMove=t=>{0!==this.initialWallPoints.length&&this.applyScaleAndRotation(t)};handleScaleEnd=()=>{const t=v();this.finalizeOperation(),t.getApp().stopRender("virtualwall-scale")};handleMoveStart=()=>{const t=v();this.initializeOperation(),t.getApp().requestRender("virtualwall-move",!0)};handleMove=t=>{if(0===this.initialWallPoints.length)return;const i=this.parent.toLocal(t.global),e=this.getDragStartPosition()||this.moveButton?.getDragStartPosition();if(!e)return;const n=i.x-e.x,l=i.y-e.y;this.applyTranslation(n,l)};handleMoveEnd=()=>{const t=v();this.finalizeOperation(),t.getApp().stopRender("virtualwall-move")};applyScaleAndRotation(t){const i=v();if(this.initialWallPoints.length<2)return;const[e,s]=this.initialWallPoints,a=e,r=this.calculateOutlinePoints(this.initialWallPoints);if(r.length<4)return;const h=r[m.BUTTON_INDICES.SCALE],d=o(s,h),c={x:t.x-d.x,y:t.y-d.y},u=o(a,c),g=n(a,c),p=i.metersToPixels(this.wallConfig.minWidth);let w;if(g<p)if(0===g)w={x:a.x+p,y:a.y};else{const t=l(u);w={x:a.x+t.x*p,y:a.y+t.y*p}}else w=c;this.wallData.points=[a,w],this.updateAllComponents(),this.updateControlButtonsPosition()}applyTranslation(t,i){this.wallData.points=this.initialWallPoints.map(e=>({x:e.x+t,y:e.y+i})),this.updateAllComponents(),this.updateControlButtonsPosition()}updateAllComponents(){this.updateWallLine(),this.updateLengthText(),this.updateOutlineComponents()}updateWallLine(){const{points:t}=this.wallData;t.length<2||(this.wallLine instanceof p?this.wallLine.updatePoints(t[0],t[1]):this.redrawSolidLine(),this.setupWallLineHitArea())}updateLengthText(){if(!this.lengthText)return;const t=this.calculateWallLengthInMeters(),i=this.formatLengthText(t);this.lengthText.updateText(i),this.updateLengthTextPosition()}updateLengthTextPosition(){if(!this.lengthText)return;const t=this.calculateTextPosition();this.lengthText.position.set(t.x,t.y);const i=this.calculateTextRotation();this.lengthText.rotation=i}updateOutlineComponents(){const t=this.calculateOutlinePoints();this.outlineBorder.updatePoints(t);const i=this.calculateMoveLinePoints(t);this.moveLine.updatePoints(i)}updateControlButtonsPosition(){if(!this.removeButton||!this.scaleButton||!this.moveButton)return;const t=this.calculateOutlinePoints();if(t.length<4)return;const{REMOVE:i,SCALE:e}=m.BUTTON_INDICES,n=this.calculateMoveButtonPosition();this.removeButton.position.set(t[i].x,t[i].y),this.scaleButton.position.set(t[e].x,t[e].y),this.moveButton.position.set(n.x,n.y)}updateEditState(){const t=this.isEditingEnabled();this.controlButtons.visible=t,this.outlineBorder.visible=t,this.moveLine.visible=t,this.lengthText&&(this.lengthText.visible=t),t&&(this.updateOutlineComponents(),this.updateControlButtonsPosition(),this.updateLengthTextPosition()),this.updateWallLineStyle(),this.setupWallLineInteraction(),this.zIndex=t?1e3:0}createSolidLine(t,e,n,l){const o=v(),s=new i;s.eventMode="static";const a=o.getApp().toFixedSize(n);return s.moveTo(t.x,t.y),s.lineTo(e.x,e.y),s.stroke({color:l,width:a}),s}updateWallLineStyle(){const t=this.isEditingEnabled(),{editing:i,normal:e,lineWidth:n,lineColor:l}=this.wallConfig,o=t?i:e;this.wallLine instanceof p!==o.isDashed?(this.removeChild(this.wallLine),this.wallLine.destroy(),this.createWallLine(!1),this.addChild(this.wallLine)):this.wallLine instanceof p?this.wallLine.updateStyle({color:l.toString(),width:n,dashArray:o.dashArray}):this.redrawSolidLine()}registerScaleListener(){const{emitter:t}=v();t.on("antiScale",this.throttledUpdateOutline),t.on("antiScale",this.throttledHandleScaleChange)}redrawSolidLine(){const t=v();if(!this.wallLine||this.wallLine instanceof p)return;const{points:i}=this.wallData;if(i.length<2)return;const{lineWidth:e,lineColor:n}=this.wallConfig,l=t.getApp().toFixedSize(e);this.wallLine.clear(),this.wallLine.setStrokeStyle({color:n.toString(),width:l}).moveTo(i[0].x,i[0].y).lineTo(i[1].x,i[1].y).stroke()}handleScaleChange=()=>{this.redrawSolidLine(),this.setupWallLineHitArea()};setupWallLineInteraction(){if(!this.wallLine)return;this.setupWallLineHitArea();const t=this.isEditingEnabled();this.wallLineClickHandler?.destroy(),this.wallLineClickHandler=null,this.wallLine.off("pointerdown",this.handleWallLinePointerDown),t?this.wallLine.on("pointerdown",this.handleWallLinePointerDown):this.wallLineClickHandler=new u(this.wallLine,{onClick:()=>{this.wallEvents?.onClick?.(this.getWallData())},stopPropagation:!1})}setupDragEventListeners(){const{emitter:t}=v();t.on("gestureHijackPointerMove",this.handleDragPointerMove),t.on("gestureHijackPointerUp",this.handleDragPointerUp),t.on("gestureHijackCancel",this.handleDragCancel)}cleanupDragEventListeners(){const{emitter:t}=v();t.off("gestureHijackPointerMove",this.handleDragPointerMove),t.off("gestureHijackPointerUp",this.handleDragPointerUp),t.off("gestureHijackCancel",this.handleDragCancel)}handleWallLinePointerDown=t=>{this.isEditingEnabled()&&(t.stopPropagation(),this.startDragging(t))};startDragging(t){const i=v();this.isDragging=!0;const e=this.parent.toLocal(t.global);this.dragStartPosition={x:e.x,y:e.y},this.initializeOperation(),i.getApp().requestRender("virtualwall-drag",!0),v().emitter.emit("gestureHijackStart",t)}handleDragPointerMove=t=>{this.isDragging&&this.dragStartPosition&&this.handleMove(t)};handleDragPointerUp=()=>{const t=v();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,t.getApp().stopRender("virtualwall-drag"),this.finalizeOperation())};handleDragCancel=()=>{const t=v();this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null,t.getApp().stopRender("virtualwall-drag"),this.handleMoveEnd())};getDragStartPosition(){return this.dragStartPosition}setupWallLineHitArea(){const t=v();if(!this.wallLine)return;const{points:i}=this.wallData;if(i.length<2)return;const{hitAreaThickness:n}=this.wallConfig,l=t.getApp().toFixedSize(n),o=d(i[0],i[1],l);if(0===o.length)return;const s=new e(o);this.wallLine.hitArea=s}getWallData(){return{...this.wallData}}updateWallData(t){this.wallData={...t,points:this.validateAndCorrectWallLength(t.points)},this.updateAllComponents(),this.updateControlButtonsPosition()}updateEditingState(){this.updateEditState()}destroy(){v().emitter.off("antiScale",this.throttledUpdateOutline),v().emitter.off("antiScale",this.throttledHandleScaleChange),this.cleanupDragEventListeners(),this.isDragging&&(this.isDragging=!1,this.dragStartPosition=null),this.wallLine&&this.wallLine.off("pointerdown",this.handleWallLinePointerDown),this.wallLineClickHandler?.destroy(),this.wallLineClickHandler=null,this.wallLine?.destroy(),this.lengthText?.destroy(),this.outlineBorder?.destroy(),this.moveLine?.destroy(),this.controlButtons?.destroy(),this.removeButton?.destroy(),this.scaleButton?.destroy(),this.moveButton?.destroy(),this.removeButton=null,this.scaleButton=null,this.moveButton=null,super.destroy()}}export{m as VirtualWall};
@@ -1 +1 @@
1
- import{Container as t}from"pixi.js";import{RobotIcon as i}from"./RobotIcon.js";import{SleepAnimation as o}from"./SleepAnimation.js";import{LAYER_ROBOT as s}from"../../application/AppContainer.js";import{subscribeKey as e}from"valtio/vanilla/utils";import{Logger as n}from"../../utils/logger.js";import{useAppService as a}from"../../application/AppService.js";import{Ring as r}from"../Base/Ring.js";class h extends t{robot;ring;sleepAnimation=null;unsubscribeFns=[];targetPosition=null;targetRotation=null;isMoving=!1;pathQueue=[];lastPosition=null;currentPathType=void 0;lastUpdateTime=0;constructor(){super();const t=a();t.appContainer.addToLayer(s,this),this.visible=t.runtimeSnapshot.showPath,this.ring=new r({config:t.robotConfig}),this.ring.visible=t.runtimeSnapshot.showRobotRing,this.addChild(this.ring),this.robot=new i,this.addChild(this.robot),this.lastUpdateTime=Date.now(),t.robotConfig.speed>0&&t.getApp().ticker.add(this.update,this);const o=e(t.runtime,"showRobotRing",t=>{n.log(`[runtime] showRobotRing: ${t}`),this.ring.visible=t});this.unsubscribeFns.push(o)}async initializeSleepAnimation(){try{this.sleepAnimation=await o.create(),this.addChild(this.sleepAnimation),n.log("Sleep animation added to robot")}catch(t){n.error("Failed to initialize sleep animation:",t)}}updatePositionByOrigin(t,i){this.position.set(t,i)}async draw({x:t,y:i,rotation:o}){this.ring.draw({x:t,y:i}),await this.robot.draw({x:t,y:i,rotation:o}),this.sleepAnimation||await this.initializeSleepAnimation(),this.sleepAnimation.draw({x:t,y:i,rotation:o}),this.lastPosition={x:t,y:i}}moveTo(t){this.pathQueue.push(t),this.isMoving||this.processNextPathPoint()}batchProcessQueue(t=!1){if(0===this.pathQueue.length)return;const i=[...this.pathQueue];if(t){const t=i[i.length-1];this.robot.position.set(t.x,t.y),void 0!==t.rotation&&(this.robot.rotation=t.rotation),this.lastPosition={x:t.x,y:t.y},this.pathQueue=[],this.isMoving=!1,this.targetPosition=null}else this.pathQueue.splice(0,i.length),0===this.pathQueue.length?(this.isMoving=!1,this.targetPosition=null):this.processNextPathPoint()}processNextPathPoint(){if(0===this.pathQueue.length)return this.isMoving=!1,this.currentPathType=void 0,this.stopRobotAnimation(),void a().emitter.emit("robotAnimationComplete");this.isMoving||this.startRobotAnimation(),this.isMoving=!0;const t=this.pathQueue[0];this.targetPosition={x:t.x,y:t.y},this.currentPathType=t.type,void 0!==t.rotation&&(this.targetRotation=t.rotation),this.lastPosition||(this.lastPosition={x:this.robot.x,y:this.robot.y})}update(){const t=a(),i=Date.now();if(0===this.lastUpdateTime)return void(this.lastUpdateTime=i);let o=i-this.lastUpdateTime;if(this.lastUpdateTime=i,o>500&&(o=16.67),this.targetPosition){const i=this.targetPosition.x-this.robot.x,s=this.targetPosition.y-this.robot.y,e=Math.sqrt(i*i+s*s),n=t.robotConfig.speed,r=t.getApp().metersToPixels(n);if(0===n)return this.robot.position.set(this.targetPosition.x,this.targetPosition.y),null!==this.targetRotation&&(this.robot.rotation=this.targetRotation,this.targetRotation=null),this.targetPosition=null,this.lastPosition={x:this.robot.x,y:this.robot.y},this.pathQueue.shift(),void this.processNextPathPoint();const h=r*(o/1e3);e<h?(this.robot.position.set(this.targetPosition.x,this.targetPosition.y),null!==this.targetRotation&&(this.robot.rotation=this.targetRotation,this.targetRotation=null),this.targetPosition=null,this.lastPosition={x:this.robot.x,y:this.robot.y},this.pathQueue.shift(),this.processNextPathPoint()):(this.robot.x+=i*(h/e),this.robot.y+=s*(h/e),a().emitter.emit("robotPositionUpdate",{x:this.robot.x,y:this.robot.y,pathType:this.currentPathType}),this.lastPosition={x:this.robot.x,y:this.robot.y})}}startRobotAnimation(){a().getApp().requestRender("robot-animation",!0)}set visible(t){super.visible=t,this.sleepAnimation&&this.sleepAnimation.onRobotVisibilityChanged()}get visible(){return super.visible}stopRobotAnimation(){a().getApp().stopRender("robot-animation")}remove(){this.pathQueue=[],this.isMoving=!1,this.targetPosition=null,this.stopRobotAnimation()}destroy(t){const i=a();this.unsubscribeFns.forEach(t=>t()),this.unsubscribeFns=[],this.stopRobotAnimation(),i.robotConfig.speed>0&&i.getApp().ticker.remove(this.update,this),this.ring.destroy(),super.destroy(t)}}export{h as Robot};
1
+ import{Container as t}from"pixi.js";import{RobotIcon as i}from"./RobotIcon.js";import{SleepAnimation as o}from"./SleepAnimation.js";import{LAYER_ROBOT as s}from"../../application/AppContainer.js";import{Ring as e}from"../Base/Ring.js";import{subscribeKey as n}from"valtio/vanilla/utils";import{Logger as a}from"../../utils/logger.js";import{useAppService as r}from"../../application/AppService.js";class h extends t{robot;ring;sleepAnimation=null;unsubscribeFns=[];targetPosition=null;targetRotation=null;isMoving=!1;pathQueue=[];lastPosition=null;currentPathType=void 0;lastUpdateTime=0;constructor(){super();const t=r();t.appContainer.addToLayer(s,this),this.visible=t.runtimeSnapshot.showPath,this.ring=new e({config:t.robotConfig}),this.ring.visible=t.runtimeSnapshot.showRobotRing,this.addChild(this.ring),this.robot=new i,this.addChild(this.robot),this.lastUpdateTime=Date.now(),t.robotConfig.speed>0&&t.getApp().ticker.add(this.update,this);const o=n(t.runtime,"showRobotRing",t=>{a.log(`[runtime] showRobotRing: ${t}`),this.ring.visible=t});this.unsubscribeFns.push(o)}async initializeSleepAnimation(){try{this.sleepAnimation=await o.create(),this.addChild(this.sleepAnimation),a.log("Sleep animation added to robot")}catch(t){a.error("Failed to initialize sleep animation:",t)}}updatePositionByOrigin(t,i){this.position.set(t,i)}async draw({x:t,y:i,rotation:o}){this.ring.draw({x:t,y:i}),await this.robot.draw({x:t,y:i,rotation:o}),this.sleepAnimation||await this.initializeSleepAnimation(),this.sleepAnimation.draw({x:t,y:i,rotation:o}),this.lastPosition={x:t,y:i}}moveTo(t){this.pathQueue.push(t),this.isMoving||this.processNextPathPoint()}batchProcessQueue(t=!1){if(0===this.pathQueue.length)return;const i=[...this.pathQueue];if(t){const t=i[i.length-1];this.robot.position.set(t.x,t.y),void 0!==t.rotation&&(this.robot.rotation=t.rotation),this.lastPosition={x:t.x,y:t.y},this.pathQueue=[],this.isMoving=!1,this.targetPosition=null}else this.pathQueue.splice(0,i.length),0===this.pathQueue.length?(this.isMoving=!1,this.targetPosition=null):this.processNextPathPoint()}processNextPathPoint(){if(0===this.pathQueue.length)return this.isMoving=!1,this.currentPathType=void 0,this.stopRobotAnimation(),void r().emitter.emit("robotAnimationComplete");this.isMoving||this.startRobotAnimation(),this.isMoving=!0;const t=this.pathQueue[0];this.targetPosition={x:t.x,y:t.y},this.currentPathType=t.type,void 0!==t.rotation&&(this.targetRotation=t.rotation),this.lastPosition||(this.lastPosition={x:this.robot.x,y:this.robot.y})}update(){const t=r(),i=Date.now();if(0===this.lastUpdateTime)return void(this.lastUpdateTime=i);let o=i-this.lastUpdateTime;if(this.lastUpdateTime=i,o>500&&(o=16.67),this.targetPosition){const i=this.targetPosition.x-this.robot.x,s=this.targetPosition.y-this.robot.y,e=Math.sqrt(i*i+s*s),n=t.robotConfig.speed,a=t.getApp().metersToPixels(n);if(0===n)return this.robot.position.set(this.targetPosition.x,this.targetPosition.y),null!==this.targetRotation&&(this.robot.rotation=this.targetRotation,this.targetRotation=null),this.targetPosition=null,this.lastPosition={x:this.robot.x,y:this.robot.y},this.pathQueue.shift(),void this.processNextPathPoint();const h=a*(o/1e3);e<h?(this.robot.position.set(this.targetPosition.x,this.targetPosition.y),null!==this.targetRotation&&(this.robot.rotation=this.targetRotation,this.targetRotation=null),this.targetPosition=null,this.lastPosition={x:this.robot.x,y:this.robot.y},this.pathQueue.shift(),this.processNextPathPoint()):(this.robot.x+=i*(h/e),this.robot.y+=s*(h/e),r().emitter.emit("robotPositionUpdate",{x:this.robot.x,y:this.robot.y,pathType:this.currentPathType}),this.lastPosition={x:this.robot.x,y:this.robot.y})}}startRobotAnimation(){r().getApp().requestRender("robot-animation",!0)}set visible(t){super.visible=t,this.sleepAnimation&&this.sleepAnimation.onRobotVisibilityChanged()}get visible(){return super.visible}stopRobotAnimation(){r().getApp().stopRender("robot-animation")}remove(){this.pathQueue=[],this.isMoving=!1,this.targetPosition=null,this.stopRobotAnimation()}destroy(t){const i=r();this.unsubscribeFns.forEach(t=>t()),this.unsubscribeFns=[],this.stopRobotAnimation(),i.robotConfig.speed>0&&i.getApp().ticker.remove(this.update,this),this.ring.destroy(),super.destroy(t)}}export{h as Robot};
@@ -1 +1 @@
1
- import{Container as e,Graphics as t,Text as o,TextStyle as i}from"pixi.js";import{useAppService as n}from"../../application/AppService.js";import{EnhancedSprite as s}from"../Base/EnhancedSprite.js";class r extends e{background;cleanModeIcon;suctionIcon;cisternIcon;cleanTimesIcon;orderContainer;orderBackground;orderText;bubble=null;isFolded=!1;roomId;roomIndex;constructor(r){super();const c=n(),l=c.roomConfig;this.roomId=r.id,this.roomIndex=r.index,this.background=new t;const{property:h,colors:{propertyTheme:d}}=l;l.property.foldable&&(this.bubble=new t);const a=d[(r.colorIndex??r.index)%d.length];this.cleanModeIcon=new s,this.cleanModeIcon.tint=a,this.cleanModeIcon.anchor.set(0,0),this.suctionIcon=new s,this.suctionIcon.tint=a,this.suctionIcon.anchor.set(0,0),this.cisternIcon=new s,this.cisternIcon.tint=a,this.cisternIcon.anchor.set(0,0),this.cleanTimesIcon=new s,this.cleanTimesIcon.tint=a,this.cleanTimesIcon.anchor.set(0,0),this.orderContainer=new e,this.orderBackground=new t,this.orderText=new o({text:"",style:new i({fontSize:h.cleanOrder.fontSize,fontFamily:h.cleanOrder.fontFamily,fontWeight:h.cleanOrder.fontWeight,fill:h.cleanOrder.color,align:"center",trim:!0})}),this.orderText.anchor.set(.5,.5),this.orderContainer.addChild(this.orderBackground),this.orderContainer.addChild(this.orderText),this.addChild(this.background),this.bubble&&this.addChild(this.bubble),this.addChild(this.cleanModeIcon),this.addChild(this.suctionIcon),this.addChild(this.cisternIcon),this.addChild(this.cleanTimesIcon),this.addChild(this.orderContainer),this.visible=c.runtimeSnapshot.showRoomProperty,this.updateProperty(r)}async updateProperty(e){await this.updateIcons(e),this.updateBackground()}getDisplayElements(e){const t=n(),{displayOrders:o}=t.roomConfig.property,{showRoomOrder:i,showRoomProperty:s}=t.runtimeSnapshot,r=e.order||0,c=i&&r>0,l=s&&o.includes("cleanMode"),h=s&&o.includes("suction"),d=s&&o.includes("cistern"),a=s&&o.includes("cleanTimes")&&e.cleanTimes>0,u={cleanMode:{element:this.cleanModeIcon,show:l,isOrder:!1},suction:{element:this.suctionIcon,show:h,isOrder:!1},cistern:{element:this.cisternIcon,show:d,isOrder:!1},cleanTimes:{element:this.cleanTimesIcon,show:a,isOrder:!1}},b=[];return c&&b.push({element:this.orderContainer,show:!0,isOrder:!0}),o.forEach(e=>{const t=u[e];t&&t.show&&b.push(t)}),{shouldShowOrder:c,shouldShowCleanMode:l,shouldShowSuction:h,shouldShowCistern:d,shouldShowCleanTimes:a,elementsToShow:b,orderValue:r}}async updateIcons(e){const t=n(),{iconWidth:o,iconHeight:i,container:s,cleanOrder:r,foldable:c,iconGap:l}=t.roomConfig.property,{propertyTheme:h}=t.roomConfig.colors,{paddingHorizontal:d,paddingVertical:a}=s,{shouldShowOrder:u,shouldShowCleanMode:b,shouldShowSuction:p,shouldShowCistern:g,shouldShowCleanTimes:m,elementsToShow:I,orderValue:f}=this.getDisplayElements(e);this.orderContainer.visible=u,this.cleanModeIcon.visible=b,this.suctionIcon.visible=p,this.cisternIcon.visible=g,this.cleanTimesIcon.visible=m,c&&this.isFolded&&(this.orderContainer.visible=!1,this.cleanModeIcon.visible=!1,this.suctionIcon.visible=!1,this.cisternIcon.visible=!1,this.cleanTimesIcon.visible=!1);const C=[];if(b&&C.push(this.cleanModeIcon.loadTextureAndSetSize(`cleanMode_${e.cleanMode}`,{width:o,height:i,sizeFixed:!1})),p&&C.push(this.suctionIcon.loadTextureAndSetSize(`fan_${e.suction}`,{width:o,height:i,sizeFixed:!1})),g&&C.push(this.cisternIcon.loadTextureAndSetSize(`water_${e.cistern}`,{width:o,height:i,sizeFixed:!1})),m){const t=e.cleanTimes||1;C.push(this.cleanTimesIcon.loadTextureAndSetSize(`cleanTimes${t}`,{width:o,height:i,sizeFixed:!1}))}if(await Promise.all(C),u){this.orderText.text=f.toString();const e=t.getRoomData(this.roomId),n=e?.colorIndex??this.roomIndex;this.orderBackground.clear(),this.orderBackground.setFillStyle({color:h[n%h.length]}),this.orderBackground.circle(o/2,i/2,o/2).fill(),this.orderText.position.set(o/2,i/2)}let y=d;I.forEach((e,t)=>{const{element:i,isOrder:n}=e;i.position.set(y,a),y+=o,t<I.length-1&&(y+=n?r.gapRight:l)})}updateBackground(){const e=n().roomConfig,{container:t,foldable:o}=e.property,{borderRadius:i,tailHeight:s,tailWidth:r,backgroundColor:c}=t,l=this.calculateContentWidth(),h=this.calculateContentHeight(),d=Math.min(r,l/2);if(this.background.clear(),this.bubble&&this.bubble.clear(),this.background.setFillStyle({color:c}),this.background.roundRect(0,0,l,h,i).fill(),o&&this.bubble){const e=(l-d)/2;this.bubble.setFillStyle({color:c}),this.bubble.poly([e,h-1,e+d,h-1,e+d/2,h+s]).fill()}}calculateContentWidth(){const e=n(),{iconWidth:t,container:o,cleanOrder:i,iconGap:s}=e.roomConfig.property,{paddingHorizontal:r}=o,c=e.getRoomData(this.roomId);if(!c)return 2*r;const{elementsToShow:l}=this.getDisplayElements(c);let h=r;return l.forEach((e,o)=>{const{isOrder:n}=e;h+=t,o<l.length-1&&(h+=n?i.gapRight:s)}),h+=r,h}calculateContentHeight(){const e=n().roomConfig,{iconHeight:t,container:o}=e.property;return o.paddingVertical+t+o.paddingVertical}getTotalHeight(){const e=n(),{foldable:t,container:o}=e.roomConfig.property,{tailHeight:i}=o;return this.calculateContentHeight()+(t?i:0)}getTotalWidth(){return this.calculateContentWidth()}setFolded(e){const t=n(),{foldable:o}=t.roomConfig.property;if(o)if(this.isFolded=e,e)this.background.visible=!1,this.cleanModeIcon.visible=!1,this.suctionIcon.visible=!1,this.cisternIcon.visible=!1,this.cleanTimesIcon.visible=!1,this.orderContainer.visible=!1,this.bubble&&(this.bubble.visible=!0,this.bubble.rotation=Math.PI,this.repositionFoldedBubble());else{this.background.visible=!0,this.bubble&&(this.bubble.visible=!0,this.bubble.rotation=0,this.bubble.position.set(0,0)),this.updateBackground();const e=t.getRoomData(this.roomId);e&&this.updateIcons(e)}}isFoldedState(){const e=n(),{foldable:t}=e.roomConfig.property;return!!t&&this.isFolded}repositionFoldedBubble(){const e=n(),{foldable:t}=e.roomConfig.property;if(!t||!this.bubble)return;const o=e.roomConfig,{tailHeight:i}=o.property.container,s=this.calculateContentWidth(),r=this.calculateContentHeight(),c=s/2;this.bubble.position.set(c,r+i/2)}refreshColor(){const e=n(),{propertyTheme:t}=e.roomConfig.colors,o=e.getRoomData(this.roomId),i=o?.colorIndex??this.roomIndex,s=t[i%t.length];if(this.cleanModeIcon&&(this.cleanModeIcon.tint=s),this.suctionIcon&&(this.suctionIcon.tint=s),this.cisternIcon&&(this.cisternIcon.tint=s),this.cleanTimesIcon&&(this.cleanTimesIcon.tint=s),this.orderBackground&&this.orderBackground.visible){const{property:o}=e.roomConfig,n=o.iconWidth,s=o.iconHeight;this.orderBackground.clear(),this.orderBackground.setFillStyle({color:t[i%t.length]}),this.orderBackground.circle(n/2,s/2,n/2).fill()}}destroy(){this.cleanModeIcon?.destroy(),this.suctionIcon?.destroy(),this.cisternIcon?.destroy(),this.cleanTimesIcon?.destroy(),super.destroy()}}export{r as RoomProperty};
1
+ import{Container as e,Graphics as t,Text as o,TextStyle as i}from"pixi.js";import{EnhancedSprite as n}from"../Base/EnhancedSprite.js";import{useAppService as s}from"../../application/AppService.js";class r extends e{background;cleanModeIcon;suctionIcon;cisternIcon;cleanTimesIcon;orderContainer;orderBackground;orderText;bubble=null;isFolded=!1;roomId;roomIndex;constructor(r){super();const c=s(),l=c.roomConfig;this.roomId=r.id,this.roomIndex=r.index,this.background=new t;const{property:h,colors:{propertyTheme:d}}=l;l.property.foldable&&(this.bubble=new t);const a=d[(r.colorIndex??r.index)%d.length];this.cleanModeIcon=new n,this.cleanModeIcon.tint=a,this.cleanModeIcon.anchor.set(0,0),this.suctionIcon=new n,this.suctionIcon.tint=a,this.suctionIcon.anchor.set(0,0),this.cisternIcon=new n,this.cisternIcon.tint=a,this.cisternIcon.anchor.set(0,0),this.cleanTimesIcon=new n,this.cleanTimesIcon.tint=a,this.cleanTimesIcon.anchor.set(0,0),this.orderContainer=new e,this.orderBackground=new t,this.orderText=new o({text:"",style:new i({fontSize:h.cleanOrder.fontSize,fontFamily:h.cleanOrder.fontFamily,fontWeight:h.cleanOrder.fontWeight,fill:h.cleanOrder.color,align:"center",trim:!0})}),this.orderText.anchor.set(.5,.5),this.orderContainer.addChild(this.orderBackground),this.orderContainer.addChild(this.orderText),this.addChild(this.background),this.bubble&&this.addChild(this.bubble),this.addChild(this.cleanModeIcon),this.addChild(this.suctionIcon),this.addChild(this.cisternIcon),this.addChild(this.cleanTimesIcon),this.addChild(this.orderContainer),this.visible=c.runtimeSnapshot.showRoomProperty,this.updateProperty(r)}async updateProperty(e){await this.updateIcons(e),this.updateBackground()}getDisplayElements(e){const t=s(),{displayOrders:o}=t.roomConfig.property,{showRoomOrder:i,showRoomProperty:n}=t.runtimeSnapshot,r=e.order||0,c=i&&r>0,l=n&&o.includes("cleanMode"),h=n&&o.includes("suction"),d=n&&o.includes("cistern"),a=n&&o.includes("cleanTimes")&&e.cleanTimes>0,u={cleanMode:{element:this.cleanModeIcon,show:l,isOrder:!1},suction:{element:this.suctionIcon,show:h,isOrder:!1},cistern:{element:this.cisternIcon,show:d,isOrder:!1},cleanTimes:{element:this.cleanTimesIcon,show:a,isOrder:!1}},b=[];return c&&b.push({element:this.orderContainer,show:!0,isOrder:!0}),o.forEach(e=>{const t=u[e];t&&t.show&&b.push(t)}),{shouldShowOrder:c,shouldShowCleanMode:l,shouldShowSuction:h,shouldShowCistern:d,shouldShowCleanTimes:a,elementsToShow:b,orderValue:r}}async updateIcons(e){const t=s(),{iconWidth:o,iconHeight:i,container:n,cleanOrder:r,foldable:c,iconGap:l}=t.roomConfig.property,{propertyTheme:h}=t.roomConfig.colors,{paddingHorizontal:d,paddingVertical:a}=n,{shouldShowOrder:u,shouldShowCleanMode:b,shouldShowSuction:p,shouldShowCistern:g,shouldShowCleanTimes:m,elementsToShow:I,orderValue:f}=this.getDisplayElements(e);this.orderContainer.visible=u,this.cleanModeIcon.visible=b,this.suctionIcon.visible=p,this.cisternIcon.visible=g,this.cleanTimesIcon.visible=m,c&&this.isFolded&&(this.orderContainer.visible=!1,this.cleanModeIcon.visible=!1,this.suctionIcon.visible=!1,this.cisternIcon.visible=!1,this.cleanTimesIcon.visible=!1);const C=[];if(b&&C.push(this.cleanModeIcon.loadTextureAndSetSize(`cleanMode_${e.cleanMode}`,{width:o,height:i,sizeFixed:!1})),p&&C.push(this.suctionIcon.loadTextureAndSetSize(`fan_${e.suction}`,{width:o,height:i,sizeFixed:!1})),g&&C.push(this.cisternIcon.loadTextureAndSetSize(`water_${e.cistern}`,{width:o,height:i,sizeFixed:!1})),m){const t=e.cleanTimes||1;C.push(this.cleanTimesIcon.loadTextureAndSetSize(`cleanTimes${t}`,{width:o,height:i,sizeFixed:!1}))}if(await Promise.all(C),u){this.orderText.text=f.toString();const e=t.getRoomData(this.roomId),n=e?.colorIndex??this.roomIndex;this.orderBackground.clear(),this.orderBackground.setFillStyle({color:h[n%h.length]}),this.orderBackground.circle(o/2,i/2,o/2).fill(),this.orderText.position.set(o/2,i/2)}let y=d;I.forEach((e,t)=>{const{element:i,isOrder:n}=e;i.position.set(y,a),y+=o,t<I.length-1&&(y+=n?r.gapRight:l)})}updateBackground(){const e=s().roomConfig,{container:t,foldable:o}=e.property,{borderRadius:i,tailHeight:n,tailWidth:r,backgroundColor:c}=t,l=this.calculateContentWidth(),h=this.calculateContentHeight(),d=Math.min(r,l/2);if(this.background.clear(),this.bubble&&this.bubble.clear(),this.background.setFillStyle({color:c}),this.background.roundRect(0,0,l,h,i).fill(),o&&this.bubble){const e=(l-d)/2;this.bubble.setFillStyle({color:c}),this.bubble.poly([e,h-1,e+d,h-1,e+d/2,h+n]).fill()}}calculateContentWidth(){const e=s(),{iconWidth:t,container:o,cleanOrder:i,iconGap:n}=e.roomConfig.property,{paddingHorizontal:r}=o,c=e.getRoomData(this.roomId);if(!c)return 2*r;const{elementsToShow:l}=this.getDisplayElements(c);let h=r;return l.forEach((e,o)=>{const{isOrder:s}=e;h+=t,o<l.length-1&&(h+=s?i.gapRight:n)}),h+=r,h}calculateContentHeight(){const e=s().roomConfig,{iconHeight:t,container:o}=e.property;return o.paddingVertical+t+o.paddingVertical}getTotalHeight(){const e=s(),{foldable:t,container:o}=e.roomConfig.property,{tailHeight:i}=o;return this.calculateContentHeight()+(t?i:0)}getTotalWidth(){return this.calculateContentWidth()}setFolded(e){const t=s(),{foldable:o}=t.roomConfig.property;if(o)if(this.isFolded=e,e)this.background.visible=!1,this.cleanModeIcon.visible=!1,this.suctionIcon.visible=!1,this.cisternIcon.visible=!1,this.cleanTimesIcon.visible=!1,this.orderContainer.visible=!1,this.bubble&&(this.bubble.visible=!0,this.bubble.rotation=Math.PI,this.repositionFoldedBubble());else{this.background.visible=!0,this.bubble&&(this.bubble.visible=!0,this.bubble.rotation=0,this.bubble.position.set(0,0)),this.updateBackground();const e=t.getRoomData(this.roomId);e&&this.updateIcons(e)}}isFoldedState(){const e=s(),{foldable:t}=e.roomConfig.property;return!!t&&this.isFolded}repositionFoldedBubble(){const e=s(),{foldable:t}=e.roomConfig.property;if(!t||!this.bubble)return;const o=e.roomConfig,{tailHeight:i}=o.property.container,n=this.calculateContentWidth(),r=this.calculateContentHeight(),c=n/2;this.bubble.position.set(c,r+i/2)}refreshColor(){const e=s(),{propertyTheme:t}=e.roomConfig.colors,o=e.getRoomData(this.roomId),i=o?.colorIndex??this.roomIndex,n=t[i%t.length];if(this.cleanModeIcon&&(this.cleanModeIcon.tint=n),this.suctionIcon&&(this.suctionIcon.tint=n),this.cisternIcon&&(this.cisternIcon.tint=n),this.cleanTimesIcon&&(this.cleanTimesIcon.tint=n),this.orderBackground&&this.orderBackground.visible){const{property:o}=e.roomConfig,n=o.iconWidth,s=o.iconHeight;this.orderBackground.clear(),this.orderBackground.setFillStyle({color:t[i%t.length]}),this.orderBackground.circle(n/2,s/2,n/2).fill()}}destroy(){this.cleanModeIcon?.destroy(),this.suctionIcon?.destroy(),this.cisternIcon?.destroy(),this.cleanTimesIcon?.destroy(),super.destroy()}}export{r as RoomProperty};
@@ -1 +1 @@
1
- import{Container as o,Graphics as t}from"pixi.js";import{useAppService as i}from"../../application/AppService.js";import{EnhancedSprite as e}from"../Base/EnhancedSprite.js";class c extends o{background;checkmarkIcon;bubble;roomIndex;roomId;constructor(o){super();const c=i().roomConfig;this.roomId=o.id,this.roomIndex=o.index,this.background=new t,this.bubble=new t;const{colors:{selectionIndicatorIcon:n}}=c;this.checkmarkIcon=new e,this.checkmarkIcon.tint=n[o.index%n.length],this.checkmarkIcon.anchor.set(0,0),this.addChild(this.background),this.addChild(this.bubble),this.addChild(this.checkmarkIcon),this.updateIndicator(o)}async updateIndicator(o){const t=i(),{roomSelectionMode:e,enableRoomSelection:c,selectRoomIds:n}=t.runtimeSnapshot;if(!c||"checkmark"!==e)return void(this.visible=!1);const r=n.includes(o.id);await this.showCheckmarkMode(r),this.updateBackground()}async showCheckmarkMode(o){const t=i(),{selectionIndicator:e}=t.roomConfig,{iconWidth:c,iconHeight:n}=e;if(o){this.visible=!0,this.checkmarkIcon.visible=!0,await this.checkmarkIcon.loadTextureAndSetSize("checkmark",{width:c,height:n,sizeFixed:!1});const o=e.containerWidth/2,t=e.containerHeight/2;this.checkmarkIcon.position.set(o-c/2,t-n/2)}else this.visible=!1}updateBackground(){const o=i(),{selectionIndicator:t,colors:e}=o.roomConfig,{containerWidth:c,containerHeight:n,strokeWidth:r,strokeColor:s,borderRadius:a,tailHeight:h,tailWidth:d}=t,l=o.getRoomData(this.roomId),k=l?.colorIndex??this.roomIndex,m=e.selectionIndicatorBackground[k%e.selectionIndicatorBackground.length];if(this.background.clear(),this.bubble.clear(),this.background.setFillStyle({color:m}).roundRect(0,0,c,n,a).fill().setStrokeStyle({color:s,width:r,alignment:0}).stroke(),h>0&&d>0){const o=(c-d)/2;this.bubble.setFillStyle({color:s});const t=n+r;this.bubble.poly([o,t-1,o+d,t-1,o+d/2,t+h]).fill()}}getTotalHeight(){const o=i(),{selectionIndicator:t}=o.roomConfig,{containerHeight:e,tailHeight:c,strokeWidth:n}=t;return e+n+(c>0?c:0)}getTotalWidth(){const o=i(),{selectionIndicator:t}=o.roomConfig;return t.containerWidth}async refreshColor(){const o=i().getRoomData(this.roomId);o&&await this.updateIndicator(o)}destroy(){this.checkmarkIcon?.destroy(),super.destroy()}}export{c as RoomSelectionIndicator};
1
+ import{Container as o,Graphics as t}from"pixi.js";import{EnhancedSprite as i}from"../Base/EnhancedSprite.js";import{useAppService as e}from"../../application/AppService.js";class c extends o{background;checkmarkIcon;bubble;roomIndex;roomId;constructor(o){super();const c=e().roomConfig;this.roomId=o.id,this.roomIndex=o.index,this.background=new t,this.bubble=new t;const{colors:{selectionIndicatorIcon:n}}=c;this.checkmarkIcon=new i,this.checkmarkIcon.tint=n[o.index%n.length],this.checkmarkIcon.anchor.set(0,0),this.addChild(this.background),this.addChild(this.bubble),this.addChild(this.checkmarkIcon),this.updateIndicator(o)}async updateIndicator(o){const t=e(),{roomSelectionMode:i,enableRoomSelection:c,selectRoomIds:n}=t.runtimeSnapshot;if(!c||"checkmark"!==i)return void(this.visible=!1);const r=n.includes(o.id);await this.showCheckmarkMode(r),this.updateBackground()}async showCheckmarkMode(o){const t=e(),{selectionIndicator:i}=t.roomConfig,{iconWidth:c,iconHeight:n}=i;if(o){this.visible=!0,this.checkmarkIcon.visible=!0,await this.checkmarkIcon.loadTextureAndSetSize("checkmark",{width:c,height:n,sizeFixed:!1});const o=i.containerWidth/2,t=i.containerHeight/2;this.checkmarkIcon.position.set(o-c/2,t-n/2)}else this.visible=!1}updateBackground(){const o=e(),{selectionIndicator:t,colors:i}=o.roomConfig,{containerWidth:c,containerHeight:n,strokeWidth:r,strokeColor:s,borderRadius:a,tailHeight:h,tailWidth:d}=t,l=o.getRoomData(this.roomId),k=l?.colorIndex??this.roomIndex,m=i.selectionIndicatorBackground[k%i.selectionIndicatorBackground.length];if(this.background.clear(),this.bubble.clear(),this.background.setFillStyle({color:m}).roundRect(0,0,c,n,a).fill().setStrokeStyle({color:s,width:r,alignment:0}).stroke(),h>0&&d>0){const o=(c-d)/2;this.bubble.setFillStyle({color:s});const t=n+r;this.bubble.poly([o,t-1,o+d,t-1,o+d/2,t+h]).fill()}}getTotalHeight(){const o=e(),{selectionIndicator:t}=o.roomConfig,{containerHeight:i,tailHeight:c,strokeWidth:n}=t;return i+n+(c>0?c:0)}getTotalWidth(){const o=e(),{selectionIndicator:t}=o.roomConfig;return t.containerWidth}async refreshColor(){const o=e().getRoomData(this.roomId);o&&await this.updateIndicator(o)}destroy(){this.checkmarkIcon?.destroy(),super.destroy()}}export{c as RoomSelectionIndicator};
@@ -1 +1 @@
1
- import o from"../assets/chargingStation.png.js";import e from"../assets/robot.png.js";import t from"../assets/fan0.png.js";import i from"../assets/fan1.png.js";import r from"../assets/fan2.png.js";import s from"../assets/fan3.png.js";import n from"../assets/fan4.png.js";import a from"../assets/water0.png.js";import f from"../assets/water1.png.js";import l from"../assets/water2.png.js";import d from"../assets/water3.png.js";import c from"../assets/cleanMode0.png.js";import h from"../assets/cleanMode1.png.js";import p from"../assets/cleanMode2.png.js";import m from"../assets/cleanMode3.png.js";import g from"../assets/cleanTimes1.png.js";import b from"../assets/cleanTimes2.png.js";import S from"../assets/controlScale.png.js";import C from"../assets/controlDelete.png.js";import u from"../assets/controlRotate.png.js";import W from"../assets/controlMove.png.js";import k from"../assets/checkmark.png.js";import y from"../assets/spot.png.js";import D from"../assets/floorType1.png.js";import j from"../assets/floorType2.png.js";import x from"../assets/floorType3.png.js";import F from"../assets/carpet.png.js";import A from"../assets/sleep.json.js";import{SPECIAL_ROOM_IDS as O}from"@ray-js/robot-protocol";const w="system-ui, -apple-system, sans-serif",R=["#2563b8","#26966b","#7c3fb8","#d97706"],P={global:{containerTop:"0px",containerLeft:"0px",containerWidth:"100%",containerHeight:"100%",backgroundColor:"#f6f6f6"},map:{autoPaddingPercent:.05,adjacencyThreshold:3,obstacleColor:"#999999",freeColor:"#ebebeb"},room:{colors:{active:["#a8c8f5","#9de5c7","#d4b9f7","#ffd399"],inactive:["#d6e7fc","#d1f4e5","#ece0fb","#fff0d9"],name:[...R],propertyTheme:[...R],selectionIndicatorBackground:[...R],selectionIndicatorIcon:["#ffffff","#ffffff","#ffffff","#ffffff"],[O.NO_ROOM_DATA]:"#ebebeb",[O.ROOM_GAP]:"#ebebeb",[O.OBSTACLE_ROOM]:"#ebebeb",[O.UNKNOWN_ROOM]:"#ebebeb"},nameLabel:{fontSize:10,fontFamily:w,fontWeight:"500"},property:{displayOrders:["cleanMode","suction","cistern","cleanTimes"],iconWidth:12,iconHeight:12,foldable:!0,offsetX:0,offsetY:4,iconGap:0,container:{backgroundColor:"#ffffff",paddingVertical:1.5,paddingHorizontal:1.5,borderRadius:16,tailHeight:2,tailWidth:10},suction:{assets:[t,i,r,s,n]},cistern:{assets:[a,f,l,d]},cleanMode:{assets:[c,h,p,m]},cleanTimes:{assets:[g,b]},cleanOrder:{color:"#ffffff",fontFamily:w,fontWeight:"400",fontSize:8,gapRight:2}},selectionIndicator:{iconSrc:k,iconWidth:12,iconHeight:12,containerWidth:16,containerHeight:16,strokeWidth:2,strokeColor:"#ffffff",borderRadius:16,offsetY:4,offsetX:0,tailHeight:2,tailWidth:6},floorType:{assets:["",D,j,x],opacity:.1,scale:.2}},path:{lineWidthFixed:!1,incrementalThreshold:5,commonPath:{visible:!0,color:"#ffffff",width:.5},transitionPath:{visible:!1,color:"#ffffff",width:.5},chargePath:{visible:!1,color:"#ffffff",width:.5}},carpet:{src:F,opacity:.5,scale:.2},robot:{icon:{sizeFixed:!1,width:8,height:8,src:e},speed:0,rotationCorrection:0,sleepAnimation:{jsonSrc:A,framePrefix:"sleep_",width:16,height:16,sizeFixed:!1,frameCount:96,offsetX:8,offsetY:-8},ringSize:1,ringColor:"rgba(255, 68, 68, 0.2)",ringStrokeWidth:1,ringStrokeColor:"#ffffff",ringStrokeDashed:!0,ringStrokeDashArray:[4,4]},chargingStation:{icon:{sizeFixed:!1,width:8,height:8,src:o},rotationCorrection:0,ringSize:1,ringColor:"rgba(255, 68, 68, 0.2)",ringStrokeWidth:1,ringStrokeColor:"#ffffff",ringStrokeDashed:!0,ringStrokeDashArray:[4,4]},interaction:{zoomRange:{min:.5,max:8},fitMinScale:1,fitMaxScale:4,enableDoubleTapZoom:!0},controls:{iconWrapperWidth:24,iconWrapperHeight:24,iconWrapperBorderRadius:16,iconWidth:12,iconHeight:12,deleteIconSrc:C,rotateIconSrc:u,scaleIconSrc:S,moveIconSrc:W,moveButtonOffset:30,textFontSize:12,textFontFamily:w,textFontWeight:"400",unitLabel:"m",forbiddenSweepZone:{minSize:1,iconWrapperFillColor:"#ff4444",strokeColor:"#ff4444",strokeWidth:2,fillColor:"rgba(255, 68, 68, 0.1)",outlineOffset:16,outlineStrokeColor:"#ff4444",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(255, 68, 68, 0.05)",textColor:"#ff4444",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},forbiddenMopZone:{minSize:1,iconWrapperFillColor:"#fe8a07",strokeColor:"#fe8a07",strokeWidth:2,fillColor:"rgba(254, 138, 7, 0.1)",outlineOffset:16,outlineStrokeColor:"#fe8a07",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(254, 138, 7, 0.05)",textColor:"#fe8a07",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},cleanZone:{minSize:1,iconWrapperFillColor:"#5d68fe",strokeColor:"#5d68fe",strokeWidth:2,fillColor:"rgba(93, 104, 254, 0.1)",outlineOffset:16,outlineStrokeColor:"#5d68fe",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(93, 104, 254, 0.05)",textColor:"#5d68fe",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},virtualWall:{iconWrapperFillColor:"#ff4444",lineWidth:2,lineColor:"#ff4444",hitAreaThickness:30,outlineOffset:16,outlineStrokeColor:"#ff4444",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(255, 68, 68, 0.05)",minWidth:1,textColor:"#ff4444",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},spot:{iconSrc:y,iconSize:8,size:1,strokeColor:"#5d68fe",strokeWidth:2,fillColor:"rgba(93, 104, 254, 0.1)",textColor:"#5d68fe",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}}},divider:{lineColor:"#ff4444",dashLineWidth:2,dashLineDashArray:[4,3],solidLineWidth:2,endPointSize:12,endPointColor:"#ff4444",endPointStrokeColor:"#ffffff",endPointStrokeWidth:2,hitAreaThickness:30,resetDividerWhenOutOfRoom:!0,defaultExtension:20,defaultDirection:"horizontal"},detectedObject:{height:43,width:38,interactive:!1},heatmap:{cellSize:2,maxDistance:14,smoothIterations:10,heatmapAlpha:.8,colorGradients:["#FF3B30","#FF7A00","#FFA100","#FFD700","#99DD70","#2EC070","#40E0D0","#88D0E9"]},snapshot:{format:"png",quality:1,antialias:!0,resolution:window?.devicePixelRatio||1}},z={dividingRoomId:null,enableRoomSelection:!1,editingForbiddenSweepZoneIds:[],editingForbiddenMopZoneIds:[],editingCleanZoneIds:[],editingVirtualWallIds:[],editingSpotIds:[],roomPropertyFoldIds:[],roomSelectionMode:"checkmark",selectRoomIds:[],showRoomProperty:!1,showRoomOrder:!0,showRoomName:!0,showPath:!0,showChargingStation:!0,showRoomFloorType:!0,showCarpet:!0,showChargingStationRing:!1,showRobotRing:!1,showRobotSleepAnimation:!1};export{P as DEFAULT_CONFIG,z as DEFAULT_RUNTIME_CONFIG,w as TEXT_FONT_FAMILY};
1
+ import o from"../assets/chargingStation.png.js";import e from"../assets/robot.png.js";import t from"../assets/fan0.png.js";import i from"../assets/fan1.png.js";import r from"../assets/fan2.png.js";import s from"../assets/fan3.png.js";import n from"../assets/fan4.png.js";import a from"../assets/water0.png.js";import f from"../assets/water1.png.js";import l from"../assets/water2.png.js";import d from"../assets/water3.png.js";import h from"../assets/cleanMode0.png.js";import c from"../assets/cleanMode1.png.js";import p from"../assets/cleanMode2.png.js";import m from"../assets/cleanMode3.png.js";import g from"../assets/cleanTimes1.png.js";import b from"../assets/cleanTimes2.png.js";import S from"../assets/controlScale.png.js";import u from"../assets/controlDelete.png.js";import C from"../assets/controlRotate.png.js";import W from"../assets/controlMove.png.js";import k from"../assets/checkmark.png.js";import y from"../assets/spot.png.js";import D from"../assets/floorType1.png.js";import j from"../assets/floorType2.png.js";import x from"../assets/floorType3.png.js";import F from"../assets/carpet.png.js";import w from"../assets/sleep.json.js";import{SPECIAL_ROOM_IDS as A}from"@ray-js/robot-protocol";const O="system-ui, -apple-system, sans-serif",R=["#2563b8","#26966b","#7c3fb8","#d97706"],P={global:{containerTop:"0px",containerLeft:"0px",containerWidth:"100%",containerHeight:"100%",backgroundColor:"#f6f6f6"},map:{autoPaddingPercent:.05,adjacencyThreshold:3,obstacleColor:"#999999",freeColor:"#ebebeb"},room:{colors:{active:["#a8c8f5","#9de5c7","#d4b9f7","#ffd399"],inactive:["#d6e7fc","#d1f4e5","#ece0fb","#fff0d9"],name:[...R],propertyTheme:[...R],selectionIndicatorBackground:[...R],selectionIndicatorIcon:["#ffffff","#ffffff","#ffffff","#ffffff"],[A.NO_ROOM_DATA]:"#ebebeb",[A.ROOM_GAP]:"#ebebeb",[A.OBSTACLE_ROOM]:"#ebebeb",[A.UNKNOWN_ROOM]:"#ebebeb"},nameLabel:{fontSize:10,fontFamily:O,fontWeight:"500"},property:{displayOrders:["cleanMode","suction","cistern","cleanTimes"],iconWidth:12,iconHeight:12,foldable:!0,offsetX:0,offsetY:4,iconGap:0,container:{backgroundColor:"#ffffff",paddingVertical:1.5,paddingHorizontal:1.5,borderRadius:16,tailHeight:2,tailWidth:10},suction:{assets:[t,i,r,s,n]},cistern:{assets:[a,f,l,d]},cleanMode:{assets:[h,c,p,m]},cleanTimes:{assets:[g,b]},cleanOrder:{color:"#ffffff",fontFamily:O,fontWeight:"400",fontSize:8,gapRight:2}},selectionIndicator:{iconSrc:k,iconWidth:12,iconHeight:12,containerWidth:16,containerHeight:16,strokeWidth:2,strokeColor:"#ffffff",borderRadius:16,offsetY:4,offsetX:0,tailHeight:2,tailWidth:6},floorType:{assets:["",D,j,x],opacity:.1,scale:.2}},path:{lineWidthFixed:!1,incrementalThreshold:5,commonPath:{visible:!0,color:"#ffffff",width:.5},transitionPath:{visible:!1,color:"#ffffff",width:.5},chargePath:{visible:!1,color:"#ffffff",width:.5}},carpet:{src:F,opacity:.5,scale:.2},robot:{icon:{sizeFixed:!1,width:8,height:8,src:e},speed:0,rotationCorrection:0,sleepAnimation:{jsonSrc:w,framePrefix:"sleep_",width:16,height:16,sizeFixed:!1,frameCount:96,offsetX:8,offsetY:-8},ringSize:1,ringColor:"rgba(255, 68, 68, 0.2)",ringStrokeWidth:1,ringStrokeColor:"#ffffff",ringStrokeDashed:!0,ringStrokeDashArray:[4,4]},chargingStation:{icon:{sizeFixed:!1,width:8,height:8,src:o},rotationCorrection:0,ringSize:1,ringColor:"rgba(255, 68, 68, 0.2)",ringStrokeWidth:1,ringStrokeColor:"#ffffff",ringStrokeDashed:!0,ringStrokeDashArray:[4,4]},interaction:{zoomRange:{min:.5,max:8},fitMinScale:1,fitMaxScale:4,enableDoubleTapZoom:!0},controls:{iconWrapperWidth:24,iconWrapperHeight:24,iconWrapperBorderRadius:16,iconWidth:12,iconHeight:12,deleteIconSrc:u,rotateIconSrc:C,scaleIconSrc:S,moveIconSrc:W,moveButtonOffset:30,textFontSize:12,textFontFamily:O,textFontWeight:"400",unitLabel:"m",forbiddenSweepZone:{minSize:1,iconWrapperFillColor:"#ff4444",strokeColor:"#ff4444",strokeWidth:2,fillColor:"rgba(255, 68, 68, 0.1)",outlineOffset:16,outlineStrokeColor:"#ff4444",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(255, 68, 68, 0.05)",showRotateButton:!0,textColor:"#ff4444",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},forbiddenMopZone:{minSize:1,iconWrapperFillColor:"#fe8a07",strokeColor:"#fe8a07",strokeWidth:2,fillColor:"rgba(254, 138, 7, 0.1)",outlineOffset:16,outlineStrokeColor:"#fe8a07",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(254, 138, 7, 0.05)",showRotateButton:!0,textColor:"#fe8a07",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},cleanZone:{minSize:1,iconWrapperFillColor:"#5d68fe",strokeColor:"#5d68fe",strokeWidth:2,fillColor:"rgba(93, 104, 254, 0.1)",outlineOffset:16,outlineStrokeColor:"#5d68fe",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(93, 104, 254, 0.05)",showRotateButton:!0,textColor:"#5d68fe",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},virtualWall:{iconWrapperFillColor:"#ff4444",lineWidth:2,lineColor:"#ff4444",hitAreaThickness:30,outlineOffset:16,outlineStrokeColor:"#ff4444",outlineStrokeWidth:2,outlineDashed:!0,outlineDashArray:[4,3],outlineFillColor:"rgba(255, 68, 68, 0.05)",minWidth:1,textColor:"#ff4444",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}},spot:{iconSrc:y,iconSize:8,size:1,strokeColor:"#5d68fe",strokeWidth:2,fillColor:"rgba(93, 104, 254, 0.1)",textColor:"#5d68fe",textPosition:"bottom",textOffset:8,editing:{isDashed:!1,dashArray:[0,0]},normal:{isDashed:!1,dashArray:[0,0]}}},divider:{lineColor:"#ff4444",dashLineWidth:2,dashLineDashArray:[4,3],solidLineWidth:2,endPointSize:12,endPointColor:"#ff4444",endPointStrokeColor:"#ffffff",endPointStrokeWidth:2,hitAreaThickness:30,resetDividerWhenOutOfRoom:!1,defaultExtension:20,defaultDirection:"horizontal"},detectedObject:{height:43,width:38,interactive:!1},heatmap:{cellSize:2,maxDistance:14,smoothIterations:10,heatmapAlpha:.8,colorGradients:["#FF3B30","#FF7A00","#FFA100","#FFD700","#99DD70","#2EC070","#40E0D0","#88D0E9"]},snapshot:{format:"png",quality:1,antialias:!0,resolution:window?.devicePixelRatio||1}},z={dividingRoomId:null,enableRoomSelection:!1,editingForbiddenSweepZoneIds:[],editingForbiddenMopZoneIds:[],editingCleanZoneIds:[],editingVirtualWallIds:[],editingSpotIds:[],roomPropertyFoldIds:[],roomSelectionMode:"checkmark",selectRoomIds:[],showRoomProperty:!1,showRoomOrder:!0,showRoomName:!0,showPath:!0,showChargingStation:!0,showRoomFloorType:!0,showCarpet:!0,showChargingStationRing:!1,showRobotRing:!1,showRobotSleepAnimation:!1};export{P as DEFAULT_CONFIG,z as DEFAULT_RUNTIME_CONFIG,O as TEXT_FONT_FAMILY};
@@ -1 +1 @@
1
- const e=["areRoomsAdjacent","resetPanZoom","getForbiddenSweepZones","getForbiddenMopZones","getCleanZones","getVirtualWalls","getSpots","getViewportCenterPoint","getMapCenterPoint","getWallPointsByViewportCenter","getForbiddenSweepZonePointsByViewportCenter","getForbiddenMopZonePointsByViewportCenter","getCleanZonePointsByViewportCenter","getSpotPointByViewportCenter","getEffectiveDividerPoints","getDividerEndPoints","snapshot","snapshotByData"],o=["onMapFirstDrawed","onMapDrawed","onPathDrawed","onRoomPropertiesDrawed","onClickRoom","onClickRoomProperties","onRemoveForbiddenSweepZone","onRemoveForbiddenMopZone","onRemoveCleanZone","onRemoveVirtualWall","onUpdateForbiddenSweepZone","onUpdateForbiddenMopZone","onUpdateCleanZone","onUpdateVirtualWall","onUpdateSpot","onUpdateDivider","onClickForbiddenSweepZone","onClickForbiddenMopZone","onClickCleanZone","onClickVirtualWall","onClickSpot","onClickDetectedObject","onClickCustomElement"];export{e as MAP_API_METHODS,o as MAP_CALLBACK_METHODS};
1
+ const e=["areRoomsAdjacent","getForbiddenSweepZones","getForbiddenMopZones","getCleanZones","getVirtualWalls","getSpots","getViewportCenterPoint","getMapCenterPoint","getWallPointsByViewportCenter","getForbiddenSweepZonePointsByViewportCenter","getForbiddenMopZonePointsByViewportCenter","getCleanZonePointsByViewportCenter","getSpotPointByViewportCenter","getEffectiveDividerPoints","getDividerEndPoints","isPointInAnyRoom","resetPanZoom","snapshot","snapshotByData"],o=["onMapFirstDrawed","onMapDrawed","onPathDrawed","onRoomPropertiesDrawed","onClickRoom","onClickRoomProperties","onRemoveForbiddenSweepZone","onRemoveForbiddenMopZone","onRemoveCleanZone","onRemoveVirtualWall","onUpdateForbiddenSweepZone","onUpdateForbiddenMopZone","onUpdateCleanZone","onUpdateVirtualWall","onUpdateSpot","onUpdateDivider","onClickForbiddenSweepZone","onClickForbiddenMopZone","onClickCleanZone","onClickVirtualWall","onClickSpot","onClickDetectedObject","onClickCustomElement"];export{e as MAP_API_METHODS,o as MAP_CALLBACK_METHODS};
package/dist/index.d.ts CHANGED
@@ -765,7 +765,8 @@ export declare type BaseCustomElementParam = {
765
765
  /** 是否可交互 */
766
766
  interactive?: boolean
767
767
  /** 自定义数据 */
768
- customData?: Record<string, unknown>
768
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
769
+ customData?: Record<string, any>
769
770
  /** 尺寸是否固定 */
770
771
  sizeFixed?: boolean
771
772
  }
@@ -1197,6 +1198,9 @@ export declare type DetectedObjectParam = {
1197
1198
  height?: number
1198
1199
  /** 宽度 */
1199
1200
  width?: number
1201
+ /** 自定义数据 */
1202
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1203
+ customData?: Record<string, any>
1200
1204
  }
1201
1205
 
1202
1206
  /** 方向 */
@@ -1739,7 +1743,7 @@ declare type Managers = {
1739
1743
  roomsManager: RoomManager;
1740
1744
  };
1741
1745
 
1742
- export declare const MAP_API_METHODS: readonly ["areRoomsAdjacent", "resetPanZoom", "getForbiddenSweepZones", "getForbiddenMopZones", "getCleanZones", "getVirtualWalls", "getSpots", "getViewportCenterPoint", "getMapCenterPoint", "getWallPointsByViewportCenter", "getForbiddenSweepZonePointsByViewportCenter", "getForbiddenMopZonePointsByViewportCenter", "getCleanZonePointsByViewportCenter", "getSpotPointByViewportCenter", "getEffectiveDividerPoints", "getDividerEndPoints", "snapshot", "snapshotByData"];
1746
+ export declare const MAP_API_METHODS: readonly ["areRoomsAdjacent", "getForbiddenSweepZones", "getForbiddenMopZones", "getCleanZones", "getVirtualWalls", "getSpots", "getViewportCenterPoint", "getMapCenterPoint", "getWallPointsByViewportCenter", "getForbiddenSweepZonePointsByViewportCenter", "getForbiddenMopZonePointsByViewportCenter", "getCleanZonePointsByViewportCenter", "getSpotPointByViewportCenter", "getEffectiveDividerPoints", "getDividerEndPoints", "isPointInAnyRoom", "resetPanZoom", "snapshot", "snapshotByData"];
1743
1747
 
1744
1748
  export declare const MAP_CALLBACK_METHODS: readonly ["onMapFirstDrawed", "onMapDrawed", "onPathDrawed", "onRoomPropertiesDrawed", "onClickRoom", "onClickRoomProperties", "onRemoveForbiddenSweepZone", "onRemoveForbiddenMopZone", "onRemoveCleanZone", "onRemoveVirtualWall", "onUpdateForbiddenSweepZone", "onUpdateForbiddenMopZone", "onUpdateCleanZone", "onUpdateVirtualWall", "onUpdateSpot", "onUpdateDivider", "onClickForbiddenSweepZone", "onClickForbiddenMopZone", "onClickCleanZone", "onClickVirtualWall", "onClickSpot", "onClickDetectedObject", "onClickCustomElement"];
1745
1749
 
@@ -1907,6 +1911,17 @@ export declare interface MapApi {
1907
1911
  * @returns 是否所有指定的房间都相邻(连通)
1908
1912
  */
1909
1913
  areRoomsAdjacent(roomIds: number[]): boolean;
1914
+ /**
1915
+ * 判断一个点是否在任意房间内
1916
+ *
1917
+ * 接受原点坐标系的点(相对于origin的坐标),遍历所有房间,
1918
+ * 判断该点是否在某个房间内。支持结构化地图和点阵地图两种协议。
1919
+ * 方法内部会自动将原点坐标系转换为地图坐标系进行检测。
1920
+ *
1921
+ * @param point - 待检测的点坐标(原点坐标系,与Zone、VirtualWall等使用相同的坐标系)
1922
+ * @returns 如果点在某个房间内,返回该房间的RoomData;否则返回null
1923
+ */
1924
+ isPointInAnyRoom(point: Point): RoomData | null;
1910
1925
  /**
1911
1926
  * 地图截图
1912
1927
  *
@@ -2295,6 +2310,30 @@ export declare class MapApplication extends Application implements MapApi {
2295
2310
  * ```
2296
2311
  */
2297
2312
  areRoomsAdjacent(roomIds: number[]): boolean;
2313
+ /**
2314
+ * 判断一个点是否在任意房间内
2315
+ *
2316
+ * 接受原点坐标系的点(相对于origin的坐标),遍历所有房间,
2317
+ * 判断该点是否在某个房间内。支持结构化地图和点阵地图两种协议。
2318
+ * 方法内部会自动将原点坐标系转换为地图坐标系进行检测。
2319
+ *
2320
+ * @param point - 待检测的点坐标(原点坐标系,与Zone、VirtualWall等使用相同的坐标系)
2321
+ * @returns 如果点在某个房间内,返回该房间的RoomData;否则返回null
2322
+ *
2323
+ * @example
2324
+ * ```typescript
2325
+ * // 判断一个点是否在房间内
2326
+ * const roomData = mapApi.isPointInAnyRoom({ x: 100, y: 200 })
2327
+ * if (roomData) {
2328
+ * console.log(`点在房间 ${roomData.name} 内`)
2329
+ * } else {
2330
+ * console.log('点不在任何房间内')
2331
+ * }
2332
+ * ```
2333
+ */
2334
+ isPointInAnyRoom(point: Point): RoomData | null;
2335
+ /* Excluded from this release type: isPointInAnyRoomStructuredInternal */
2336
+ /* Excluded from this release type: isPointInAnyRoomRasterInternal */
2298
2337
  /* Excluded from this release type: areStructuredRoomsAdjacentInternal */
2299
2338
  /* Excluded from this release type: areRasterRoomsAdjacentInternal */
2300
2339
  /**
@@ -2687,6 +2726,10 @@ declare class MapManager {
2687
2726
  * 根据ID查找房间几何信息
2688
2727
  */
2689
2728
  getRoomById(id: number): Room | undefined;
2729
+ /**
2730
+ * 获取所有房间的几何信息
2731
+ */
2732
+ getAllRooms(): Room[];
2690
2733
  /**
2691
2734
  * 清空地图组件
2692
2735
  */
@@ -2751,8 +2794,19 @@ export declare type MapState = {
2751
2794
  * 地图协议版本号
2752
2795
  */
2753
2796
  version?: number
2797
+ /**
2798
+ * 地图类型
2799
+ * - 'structured': 结构化地图(基于轮廓点)
2800
+ * - 'raster': 点阵地图(基于像素)
2801
+ */
2802
+ mapType: MapType
2754
2803
  }
2755
2804
 
2805
+ /**
2806
+ * 地图类型
2807
+ */
2808
+ export declare type MapType = 'structured' | 'raster'
2809
+
2756
2810
  declare class Obstacle extends Graphics {
2757
2811
  constructor();
2758
2812
  /**
@@ -2771,6 +2825,15 @@ declare class Obstacle extends Graphics {
2771
2825
  destroy(options?: DestroyOptions | boolean): void;
2772
2826
  }
2773
2827
 
2828
+ /**
2829
+ * 对点位进行偏移,避免与已存在的点位重叠
2830
+ * 使用递增偏移策略,每次偏移5个单位,直到找到不重叠的位置
2831
+ * @param points 需要偏移的点位数组
2832
+ * @param existingPointsArray 已存在的点位数组
2833
+ * @param maxAttempts 最大尝试次数,默认20次(最多偏移100个单位)
2834
+ */
2835
+ export declare const offsetPointsToAvoidOverlap: (points: Point[], existingPointsArray: Point[][], maxAttempts?: number) => Point[];
2836
+
2774
2837
  /**
2775
2838
  * 解析后的点阵地图数据
2776
2839
  */
@@ -3583,6 +3646,8 @@ export declare type ZoneConfig = {
3583
3646
  outlineDashed: boolean
3584
3647
  /** 轮廓虚线数组 */
3585
3648
  outlineDashArray: [number, number]
3649
+ /** 是否显示旋转图标 */
3650
+ showRotateButton: boolean
3586
3651
  /** 文本颜色 */
3587
3652
  textColor: ColorSource
3588
3653
  /** 文本位置 */
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{decodeRoomProperties as o}from"./utils/index.js";import{MapApplication as p}from"./application/MapApplication.js";import{AppContext as i,useAppService as t}from"./application/AppService.js";import{MAP_API_METHODS as r,MAP_CALLBACK_METHODS as m}from"./constant/methods.js";export{i as AppContext,r as MAP_API_METHODS,m as MAP_CALLBACK_METHODS,p as MapApplication,o as decodeRoomProperties,t as useAppService};
1
+ import{decodeRoomProperties as o,offsetPointsToAvoidOverlap as p}from"./utils/index.js";import{MapApplication as i}from"./application/MapApplication.js";import{AppContext as t,useAppService as r}from"./application/AppService.js";import{MAP_API_METHODS as m,MAP_CALLBACK_METHODS as a}from"./constant/methods.js";export{t as AppContext,m as MAP_API_METHODS,a as MAP_CALLBACK_METHODS,i as MapApplication,o as decodeRoomProperties,p as offsetPointsToAvoidOverlap,r as useAppService};