perf(iso): ускорить точный граничный поиск (#585)

Issue: #585
User-Visible: no
This commit is contained in:
Claude
2026-09-20 01:51:19 +03:00
parent 3c2ab9b764
commit e793993c66
49 changed files with 739 additions and 606 deletions
@@ -1,309 +1,309 @@
{
"schema": 1,
"fingerprint": "88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9",
"fingerprint": "f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291517,
"initialViewGzipBytes": 291531,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 293039,
"initialPanelGzipBytes": 293054,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2324,
"initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/fr-Dy8iiwy_.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"houseplan-assets/pdf-export-eMxHYpi-.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
],
"lazyGzipBytes": 441076,
"lazyGzipBytes": 441788,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"lazyEditorGzipBytes": 222197,
"lazyEditorGzipBytes": 222205,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js"
],
"lazyOnboardingGzipBytes": 13918,
"lazyOnboardingGzipBytes": 13919,
"lazyLocaleFiles": [
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/fr-Dy8iiwy_.js"
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/fr-a1RH1L3D.js"
],
"lazyLocaleGzipBytes": 56352,
"lazyLocaleGzipBytes": 56366,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DhtLxqcj.js"
"houseplan-assets/iso-scene-render-DJ5weuvD.js"
],
"lazyIsometricGzipBytes": 16792,
"lazyIsometricGzipBytes": 17468,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js"
],
"lazyFurnitureArtGzipBytes": 16944,
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/pdf-export-eMxHYpi-.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/pdf-export-CekmWtl5.js"
],
"lazyPdfGzipBytes": 126817,
"lazyPdfGzipBytes": 126814,
"files": [
{
"path": "houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"sha256": "a17a0059314b4275a5560c5235afe05c93ee0590ec5797b6eb9e793b34904820",
"path": "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"sha256": "900db7fb5992afbe29bc233852026cdec275236b153e7ddac0c0dda39e6bf271",
"rawBytes": 19959,
"gzipBytes": 6883,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-qGelgWw2.js",
"sha256": "5734db4624e6770a5f56defbe2626d2e5082fa662c93048c6214f51056080d57",
"path": "houseplan-assets/de-DNwtZhVG.js",
"sha256": "42b5b3aae036198a6000575bfad2ab4a6887cf1577aaee89e46807d811a4b41c",
"rawBytes": 93989,
"gzipBytes": 28441,
"gzipBytes": 28448,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-fzEJ3Sy_.js",
"sha256": "3fae1734402588dd4a0526ce2fcc568aa7d9ebfd95ba039407e2605d0bd035f0",
"path": "houseplan-assets/editor-BMFNgL2p.js",
"sha256": "19c12c4e6b3852fc10c27e4bda3e18dc5447ea437d6ad51b07f63a8ef9ebe448",
"rawBytes": 3833,
"gzipBytes": 1583,
"gzipBytes": 1585,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-BW84Z22H.js",
"sha256": "e24b9470e6f4fa894d108f27c31e6a6919e61971d7ba7271eb96fe6f53eea589",
"path": "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"sha256": "64145e5cfe224a062c9f30c3a2b13566915da2f34f9d01a2132b239d7a89943f",
"rawBytes": 3615,
"gzipBytes": 1233,
"gzipBytes": 1235,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Dy8iiwy_.js",
"sha256": "77c85c92191fbaf644d15aaced93611c37f3459c86ea8136acabb1c35269e119",
"path": "houseplan-assets/fr-a1RH1L3D.js",
"sha256": "404653aacaf79acdbe7e357c6427acf1cee8448b516bce2b7613a45cf31a9ab7",
"rawBytes": 96460,
"gzipBytes": 27911,
"gzipBytes": 27918,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"sha256": "1df63e447d66a02eb7039337ef16198f3b457d78c23622e1f33a90c6d1f0bc1f",
"path": "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"sha256": "4713caf365b8e228e88a0220a77f4603f6045431d57b768fcbbe6b4cc27de1d2",
"rawBytes": 52033,
"gzipBytes": 16944,
"gzipBytes": 16940,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-CdCQB6rW.js",
"sha256": "17d647662295c586c4ea81e8c8a3c194afe776da43e75830666dae882f001b52",
"path": "houseplan-assets/houseplan-card-DrP8_MdR.js",
"sha256": "dc471e9ada8f0113de4e5acb7743e3377f7c8274fa19e7a7d9363385a161222d",
"rawBytes": 1035518,
"gzipBytes": 290715,
"gzipBytes": 290727,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/fr-Dy8iiwy_.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"houseplan-assets/pdf-export-eMxHYpi-.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js"
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"sha256": "16af54e5252363307e7a1384305096395836362a9a34d77d837503fb41bd43bd",
"path": "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"sha256": "a9975e514b2ab69a61beeb4b6fb99ae7ca965ab849c730861edf6b330173a4b1",
"rawBytes": 689688,
"gzipBytes": 188130,
"gzipBytes": 188131,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"sha256": "229bbb57e3928c39f46e40824ebdfaa2ba87fe5af6c4a3e9187773c9709185ab",
"path": "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"sha256": "208379c3485b77ef3a681ac46de8e74a02faa8ab51bf7dec3bb6001b99266fe3",
"rawBytes": 28289,
"gzipBytes": 7035,
"gzipBytes": 7036,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"sha256": "e6ce493c3b1a44eb654188d4d148e5dabe237fa1edd6694f3bbce99b2105fd49",
"path": "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"sha256": "4ecedcacf6021d94b060d0978e17059bf4bd031cb0db7b603ce645160c89c26a",
"rawBytes": 10759,
"gzipBytes": 3684,
"gzipBytes": 3689,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-DhtLxqcj.js",
"sha256": "4dd8c9fa88224e480f3c50d89c2c3b073f74dd1bed6cfeb6196f301aade77ded",
"rawBytes": 50012,
"gzipBytes": 16792,
"path": "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"sha256": "e96e245dc9c2cff1c1d7408393f2440ac26e2f3694d7f37b2b8f76efe8b15ca3",
"rawBytes": 51348,
"gzipBytes": 17468,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"sha256": "b623081e5e869c80bc73a9173eb072cb3686b06244105fbbafa2b7a03da374d3",
"path": "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"sha256": "d2980077723e8b35da04f327f07d8d404207f3ddb057c7306a52a5525c182879",
"rawBytes": 8216,
"gzipBytes": 3207,
"gzipBytes": 3209,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-eMxHYpi-.js",
"sha256": "43581b2fd6d3b12389e6fda98d36ff4250a0a4fe59f9e52668937e3307f95cbb",
"path": "houseplan-assets/pdf-export-CekmWtl5.js",
"sha256": "a4d5a8dc54c4615b8e7806ecdd1fc6b940c82d76b8c84fa30b9680afeed047c0",
"rawBytes": 236247,
"gzipBytes": 109873,
"gzipBytes": 109874,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-f3elPcdE.js",
"sha256": "727df14b390c264979ad8c07ca57d994a8c0c3caa73bc6e7f793745f3adc85d1",
"path": "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"sha256": "0337b078d59d0b6281809fae10f0a353cd0d706c1f71ce42350081fc5c3cd7ec",
"rawBytes": 14862,
"gzipBytes": 3425,
"gzipBytes": 3426,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js"
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-CzwbD9VU.js",
"sha256": "fabd124197786f937775ede672afd5c5c72bab82b997cb5ccf84324d9d872de9",
"path": "houseplan-assets/summary-panel-metrics-BZroKqza.js",
"sha256": "abaaf95c3717ccbd1b01181767e6198b25b5d8b50b2ed12dc88c67c860e28be5",
"rawBytes": 2611,
"gzipBytes": 1306,
"gzipBytes": 1309,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js",
"sha256": "4b6fe585ffe7ac0d299691195754879f645507176e1c2365a85cb13655edb17c",
"path": "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"sha256": "7a3fb4366d86299ee5b81b4cfd4f8232989ea6064c98437c439deb0359107747",
"rawBytes": 72733,
"gzipBytes": 20173,
"gzipBytes": 20176,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-f3elPcdE.js",
"houseplan-assets/summary-panel-metrics-CzwbD9VU.js"
"houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"houseplan-assets/summary-panel-metrics-BZroKqza.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-Km5WY9re.js",
"sha256": "ca81df585fa1aeb2568dc373e5533f3b0b6a88ed5f11083e022f1316595fd079",
"path": "houseplan-assets/zigbee-topology-C-kzak0j.js",
"sha256": "080ae360ef3f1640ef0a16cf787cc7984687dff4e9a159a5076531b8894f46a4",
"rawBytes": 18962,
"gzipBytes": 7424,
"gzipBytes": 7431,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js",
"sha256": "53f5b9b40e8d868ab187aff1b66b410cb526ed1ae7132c55005fc0d929fc7058",
"path": "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js",
"sha256": "1788037ba347b556f50bcadee7e9ce2ac54d66370426ffcd694713b0edb66f6f",
"rawBytes": 3942,
"gzipBytes": 1763,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "eaaf069917dd00f4b4f73e114304cdbb289cf9a0e5fc1b49205741f0ae9b40c1",
"sha256": "8155cac3c10cc2682c573aa678551714efe70c93e6e80b532bbf45d7cf5618f1",
"rawBytes": 1205,
"gzipBytes": 802,
"gzipBytes": 804,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "6df398c5faa4791f14e9a0358e584c58972cc159c717e32f8f0ffdcbf9dcf0f4",
"sha256": "d89caea13550eb2aae4736804bff3a77e4dd649a0c5c5e787542da0350836b37",
"rawBytes": 6165,
"gzipBytes": 2324,
"gzipBytes": 2327,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
}
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-CdCQB6rW.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-DrP8_MdR.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-CdCQB6rW.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-Pc0BlKD3.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-DrP8_MdR.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-2rRBIPzi.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{c as a,A as e}from"./houseplan-card-CdCQB6rW.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-ClIYcGcH.js";import"./form-kit.styles-BW84Z22H.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{c as a,A as e}from"./houseplan-card-DrP8_MdR.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-rHMkdk8Q.js";import"./form-kit.styles-1SWKbgIc.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as c,b2 as l,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-DrP8_MdR.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*h(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as l,b2 as c,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-CdCQB6rW.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,d="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,d=_){try{let u=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{n as t,b as n}from"./zigbee-topology-Km5WY9re.js";import{aR as e}from"./houseplan-card-CdCQB6rW.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{n as t,b as n}from"./zigbee-topology-C-kzak0j.js";import{aR as e}from"./houseplan-card-DrP8_MdR.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";try{await import("./houseplan-assets/houseplan-card-CdCQB6rW.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";try{await import("./houseplan-assets/houseplan-card-DrP8_MdR.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
File diff suppressed because one or more lines are too long
+141 -141
View File
@@ -1,309 +1,309 @@
{
"schema": 1,
"fingerprint": "88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9",
"fingerprint": "f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291517,
"initialViewGzipBytes": 291531,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 293039,
"initialPanelGzipBytes": 293054,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2324,
"initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/fr-Dy8iiwy_.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"houseplan-assets/pdf-export-eMxHYpi-.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
],
"lazyGzipBytes": 441076,
"lazyGzipBytes": 441788,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"lazyEditorGzipBytes": 222197,
"lazyEditorGzipBytes": 222205,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js"
],
"lazyOnboardingGzipBytes": 13918,
"lazyOnboardingGzipBytes": 13919,
"lazyLocaleFiles": [
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/fr-Dy8iiwy_.js"
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/fr-a1RH1L3D.js"
],
"lazyLocaleGzipBytes": 56352,
"lazyLocaleGzipBytes": 56366,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DhtLxqcj.js"
"houseplan-assets/iso-scene-render-DJ5weuvD.js"
],
"lazyIsometricGzipBytes": 16792,
"lazyIsometricGzipBytes": 17468,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js"
],
"lazyFurnitureArtGzipBytes": 16944,
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/pdf-export-eMxHYpi-.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/pdf-export-CekmWtl5.js"
],
"lazyPdfGzipBytes": 126817,
"lazyPdfGzipBytes": 126814,
"files": [
{
"path": "houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"sha256": "a17a0059314b4275a5560c5235afe05c93ee0590ec5797b6eb9e793b34904820",
"path": "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"sha256": "900db7fb5992afbe29bc233852026cdec275236b153e7ddac0c0dda39e6bf271",
"rawBytes": 19959,
"gzipBytes": 6883,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-qGelgWw2.js",
"sha256": "5734db4624e6770a5f56defbe2626d2e5082fa662c93048c6214f51056080d57",
"path": "houseplan-assets/de-DNwtZhVG.js",
"sha256": "42b5b3aae036198a6000575bfad2ab4a6887cf1577aaee89e46807d811a4b41c",
"rawBytes": 93989,
"gzipBytes": 28441,
"gzipBytes": 28448,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-fzEJ3Sy_.js",
"sha256": "3fae1734402588dd4a0526ce2fcc568aa7d9ebfd95ba039407e2605d0bd035f0",
"path": "houseplan-assets/editor-BMFNgL2p.js",
"sha256": "19c12c4e6b3852fc10c27e4bda3e18dc5447ea437d6ad51b07f63a8ef9ebe448",
"rawBytes": 3833,
"gzipBytes": 1583,
"gzipBytes": 1585,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-BW84Z22H.js",
"sha256": "e24b9470e6f4fa894d108f27c31e6a6919e61971d7ba7271eb96fe6f53eea589",
"path": "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"sha256": "64145e5cfe224a062c9f30c3a2b13566915da2f34f9d01a2132b239d7a89943f",
"rawBytes": 3615,
"gzipBytes": 1233,
"gzipBytes": 1235,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Dy8iiwy_.js",
"sha256": "77c85c92191fbaf644d15aaced93611c37f3459c86ea8136acabb1c35269e119",
"path": "houseplan-assets/fr-a1RH1L3D.js",
"sha256": "404653aacaf79acdbe7e357c6427acf1cee8448b516bce2b7613a45cf31a9ab7",
"rawBytes": 96460,
"gzipBytes": 27911,
"gzipBytes": 27918,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"sha256": "1df63e447d66a02eb7039337ef16198f3b457d78c23622e1f33a90c6d1f0bc1f",
"path": "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"sha256": "4713caf365b8e228e88a0220a77f4603f6045431d57b768fcbbe6b4cc27de1d2",
"rawBytes": 52033,
"gzipBytes": 16944,
"gzipBytes": 16940,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-CdCQB6rW.js",
"sha256": "17d647662295c586c4ea81e8c8a3c194afe776da43e75830666dae882f001b52",
"path": "houseplan-assets/houseplan-card-DrP8_MdR.js",
"sha256": "dc471e9ada8f0113de4e5acb7743e3377f7c8274fa19e7a7d9363385a161222d",
"rawBytes": 1035518,
"gzipBytes": 290715,
"gzipBytes": 290727,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-qGelgWw2.js",
"houseplan-assets/editor-fzEJ3Sy_.js",
"houseplan-assets/fr-Dy8iiwy_.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"houseplan-assets/pdf-export-eMxHYpi-.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js"
"houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-C7V34E2J.js",
"sha256": "16af54e5252363307e7a1384305096395836362a9a34d77d837503fb41bd43bd",
"path": "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"sha256": "a9975e514b2ab69a61beeb4b6fb99ae7ca965ab849c730861edf6b330173a4b1",
"rawBytes": 689688,
"gzipBytes": 188130,
"gzipBytes": 188131,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js",
"sha256": "229bbb57e3928c39f46e40824ebdfaa2ba87fe5af6c4a3e9187773c9709185ab",
"path": "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"sha256": "208379c3485b77ef3a681ac46de8e74a02faa8ab51bf7dec3bb6001b99266fe3",
"rawBytes": 28289,
"gzipBytes": 7035,
"gzipBytes": 7036,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js",
"sha256": "e6ce493c3b1a44eb654188d4d148e5dabe237fa1edd6694f3bbce99b2105fd49",
"path": "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"sha256": "4ecedcacf6021d94b060d0978e17059bf4bd031cb0db7b603ce645160c89c26a",
"rawBytes": 10759,
"gzipBytes": 3684,
"gzipBytes": 3689,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-DhtLxqcj.js",
"sha256": "4dd8c9fa88224e480f3c50d89c2c3b073f74dd1bed6cfeb6196f301aade77ded",
"rawBytes": 50012,
"gzipBytes": 16792,
"path": "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"sha256": "e96e245dc9c2cff1c1d7408393f2440ac26e2f3694d7f37b2b8f76efe8b15ca3",
"rawBytes": 51348,
"gzipBytes": 17468,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-bgXukYTl.js",
"sha256": "b623081e5e869c80bc73a9173eb072cb3686b06244105fbbafa2b7a03da374d3",
"path": "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"sha256": "d2980077723e8b35da04f327f07d8d404207f3ddb057c7306a52a5525c182879",
"rawBytes": 8216,
"gzipBytes": 3207,
"gzipBytes": 3209,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-eMxHYpi-.js",
"sha256": "43581b2fd6d3b12389e6fda98d36ff4250a0a4fe59f9e52668937e3307f95cbb",
"path": "houseplan-assets/pdf-export-CekmWtl5.js",
"sha256": "a4d5a8dc54c4615b8e7806ecdd1fc6b940c82d76b8c84fa30b9680afeed047c0",
"rawBytes": 236247,
"gzipBytes": 109873,
"gzipBytes": 109874,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-f3elPcdE.js",
"sha256": "727df14b390c264979ad8c07ca57d994a8c0c3caa73bc6e7f793745f3adc85d1",
"path": "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"sha256": "0337b078d59d0b6281809fae10f0a353cd0d706c1f71ce42350081fc5c3cd7ec",
"rawBytes": 14862,
"gzipBytes": 3425,
"gzipBytes": 3426,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js"
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-CzwbD9VU.js",
"sha256": "fabd124197786f937775ede672afd5c5c72bab82b997cb5ccf84324d9d872de9",
"path": "houseplan-assets/summary-panel-metrics-BZroKqza.js",
"sha256": "abaaf95c3717ccbd1b01181767e6198b25b5d8b50b2ed12dc88c67c860e28be5",
"rawBytes": 2611,
"gzipBytes": 1306,
"gzipBytes": 1309,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js",
"sha256": "4b6fe585ffe7ac0d299691195754879f645507176e1c2365a85cb13655edb17c",
"path": "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"sha256": "7a3fb4366d86299ee5b81b4cfd4f8232989ea6064c98437c439deb0359107747",
"rawBytes": 72733,
"gzipBytes": 20173,
"gzipBytes": 20176,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-f3elPcdE.js",
"houseplan-assets/summary-panel-metrics-CzwbD9VU.js"
"houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"houseplan-assets/summary-panel-metrics-BZroKqza.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-Km5WY9re.js",
"sha256": "ca81df585fa1aeb2568dc373e5533f3b0b6a88ed5f11083e022f1316595fd079",
"path": "houseplan-assets/zigbee-topology-C-kzak0j.js",
"sha256": "080ae360ef3f1640ef0a16cf787cc7984687dff4e9a159a5076531b8894f46a4",
"rawBytes": 18962,
"gzipBytes": 7424,
"gzipBytes": 7431,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js",
"sha256": "53f5b9b40e8d868ab187aff1b66b410cb526ed1ae7132c55005fc0d929fc7058",
"path": "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js",
"sha256": "1788037ba347b556f50bcadee7e9ce2ac54d66370426ffcd694713b0edb66f6f",
"rawBytes": 3942,
"gzipBytes": 1763,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-C-kzak0j.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "eaaf069917dd00f4b4f73e114304cdbb289cf9a0e5fc1b49205741f0ae9b40c1",
"sha256": "8155cac3c10cc2682c573aa678551714efe70c93e6e80b532bbf45d7cf5618f1",
"rawBytes": 1205,
"gzipBytes": 802,
"gzipBytes": 804,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "6df398c5faa4791f14e9a0358e584c58972cc159c717e32f8f0ffdcbf9dcf0f4",
"sha256": "d89caea13550eb2aae4736804bff3a77e4dd649a0c5c5e787542da0350836b37",
"rawBytes": 6165,
"gzipBytes": 2324,
"gzipBytes": 2327,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js"
"houseplan-assets/houseplan-card-DrP8_MdR.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-CdCQB6rW.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-DrP8_MdR.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-CdCQB6rW.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-Pc0BlKD3.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-DrP8_MdR.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-2rRBIPzi.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{c as a,A as e}from"./houseplan-card-CdCQB6rW.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-ClIYcGcH.js";import"./form-kit.styles-BW84Z22H.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{c as a,A as e}from"./houseplan-card-DrP8_MdR.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-rHMkdk8Q.js";import"./form-kit.styles-1SWKbgIc.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as c,b2 as l,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-DrP8_MdR.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*h(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as l,b2 as c,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-CdCQB6rW.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,d="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,d=_){try{let u=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{n as t,b as n}from"./zigbee-topology-Km5WY9re.js";import{aR as e}from"./houseplan-card-CdCQB6rW.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{n as t,b as n}from"./zigbee-topology-C-kzak0j.js";import{aR as e}from"./houseplan-card-DrP8_MdR.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";try{await import("./houseplan-assets/houseplan-card-CdCQB6rW.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";try{await import("./houseplan-assets/houseplan-card-DrP8_MdR.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
+1 -1
View File
File diff suppressed because one or more lines are too long
+287 -180
View File
@@ -117,6 +117,8 @@ export interface IsoOverlayCollisionItem {
placement: IsoOverlayPlacement;
/** Axis-aligned screen-facing half-size in scene units. */
screenHalfSize: PlanPoint;
/** Previous exact result as an upper bound; every nearer event is still checked. */
nudgeHintCss?: ScenePoint;
}
export interface IsoOverlayCollisionInput {
@@ -201,15 +203,18 @@ function validRoom(room: IsoOverlayRoom): boolean {
&& roomArea(room) > EPS;
}
function pointStrictlyInRoom(point: PlanPoint, room: IsoOverlayRoom): boolean {
if (!validRoom(room) || pointOnRing(point, room.outer) || !pointInRing(point, room.outer))
return false;
function pointStrictlyInValidatedRoom(point: PlanPoint, room: IsoOverlayRoom): boolean {
if (pointOnRing(point, room.outer) || !pointInRing(point, room.outer)) return false;
for (const hole of room.holes || []) {
if (pointOnRing(point, hole) || pointInRing(point, hole)) return false;
}
return true;
}
function pointStrictlyInRoom(point: PlanPoint, room: IsoOverlayRoom): boolean {
return validRoom(room) && pointStrictlyInValidatedRoom(point, room);
}
function roomBoundaryDistance(point: PlanPoint, room: IsoOverlayRoom): number {
let distance = Infinity;
for (const ring of [room.outer, ...(room.holes || [])]) {
@@ -364,6 +369,20 @@ function ringBounds(ring: readonly (readonly number[])[]): Bounds | null {
return [minX, minY, maxX, maxY];
}
function axisAlignedRoomBox(room: IsoOverlayRoom): Bounds | null {
if (room.outer.length !== 4 || (room.holes?.length || 0) !== 0) return null;
const bounds = ringBounds(room.outer);
if (!bounds) return null;
const corners = new Set(room.outer.map((point) => {
const x = Math.abs(point[0] - bounds[0]) <= EPS ? 0
: Math.abs(point[0] - bounds[2]) <= EPS ? 1 : -1;
const y = Math.abs(point[1] - bounds[1]) <= EPS ? 0
: Math.abs(point[1] - bounds[3]) <= EPS ? 1 : -1;
return x < 0 || y < 0 ? '' : `${x}:${y}`;
}));
return corners.size === 4 && !corners.has('') ? bounds : null;
}
function silhouetteBounds(silhouette: IsoWallSilhouette, cache: boolean): Bounds | null {
if (!cache) return ringBounds(silhouette.outer);
if (silhouetteBoundsCache.has(silhouette)) return silhouetteBoundsCache.get(silhouette) ?? null;
@@ -419,6 +438,12 @@ function validSilhouette(silhouette: IsoWallSilhouette): boolean {
/** A straight nudge must never cut through a concavity or an island hole. */
function segmentStrictlyInRoom(start: PlanPoint, end: PlanPoint, room: IsoOverlayRoom): boolean {
if (!pointStrictlyInRoom(start, room) || !pointStrictlyInRoom(end, room)) return false;
return segmentBetweenStrictRoomPoints(start, end, room);
}
function segmentBetweenStrictRoomPoints(
start: PlanPoint, end: PlanPoint, room: IsoOverlayRoom,
): boolean {
for (const ring of [room.outer, ...(room.holes || [])]) {
for (let index = 0; index < ring.length; index++) {
if (segmentsIntersect(start, end, ring[index], ring[(index + 1) % ring.length]))
@@ -640,9 +665,22 @@ const ISO_OVERLAY_GROUP_CELL_CSS_PX = 64;
/** Candidate displacement together with its stable distance ordering. */
interface GroupOffset { readonly offset: ScenePoint; readonly distance: number }
type BoundaryCandidateMap = Map<string, ScenePoint>;
type BoundaryCandidateMap = {
readonly points: Map<number | string, ScenePoint>;
readonly pending: ScenePoint[];
};
function boundaryCandidateKey(x: number, y: number): string {
function createBoundaryCandidates(): BoundaryCandidateMap {
return { points: new Map(), pending: [] };
}
function boundaryCandidateKey(x: number, y: number): number | string {
// Production is bounded by 48 CSS px. Keep that hot path on V8's numeric
// Map representation; the string fallback preserves the helper's general
// finite-input contract without admitting packed-key collisions.
if (Number.isInteger(x) && Number.isInteger(y)
&& x >= -32768 && x <= 32767 && y >= -32768 && y <= 32767)
return (x + 32768) * 65536 + y + 32768;
return `${x}:${y}`;
}
@@ -664,7 +702,11 @@ function addBoundaryCandidate(
if (candidateX * candidateX + candidateY * candidateY > maxNudge * maxNudge + EPS)
continue;
const key = boundaryCandidateKey(candidateX, candidateY);
if (!candidates.has(key)) candidates.set(key, [candidateX, candidateY]);
if (!candidates.points.has(key)) {
const point: ScenePoint = [candidateX, candidateY];
candidates.points.set(key, point);
candidates.pending.push(point);
}
}
}
}
@@ -695,23 +737,26 @@ function clipBoundarySegment(
];
}
function addBoundaryRectangleEvents(
candidates: BoundaryCandidateMap, rectangles: readonly Bounds[], maxNudge: number,
function addBoundaryRectangle(
candidates: BoundaryCandidateMap, bounds: Bounds, maxNudge: number,
): void {
addBoundaryCandidate(candidates,
[bounds[0], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[bounds[2], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[1]], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[3]], maxNudge);
}
function addBoundaryRectangleIntersections(
candidates: BoundaryCandidateMap, left: Bounds, right: Bounds, maxNudge: number,
): void {
for (const bounds of rectangles) {
addBoundaryCandidate(candidates,
[bounds[0], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[bounds[2], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[1]], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[3]], maxNudge);
}
// Only intersections of FINITE rectangle edges are critical. Combining
// every X with every unrelated Y forms an artificial O(n²) interior grid;
// on the 200-device benchmark it produced almost five thousand candidates
@@ -725,10 +770,19 @@ function addBoundaryRectangleEvents(
}
}
};
addIntersections(left, right);
addIntersections(right, left);
}
function addBoundaryRectangleEvents(
candidates: BoundaryCandidateMap, rectangles: readonly Bounds[], maxNudge: number,
): void {
for (const bounds of rectangles) addBoundaryRectangle(candidates, bounds, maxNudge);
for (let left = 0; left < rectangles.length; left++) {
for (let right = left + 1; right < rectangles.length; right++) {
addIntersections(rectangles[left], rectangles[right]);
addIntersections(rectangles[right], rectangles[left]);
addBoundaryRectangleIntersections(
candidates, rectangles[left], rectangles[right], maxNudge,
);
}
}
}
@@ -743,7 +797,7 @@ export function buildIsoOverlayBoundaryCandidates(
): readonly ScenePoint[] {
if (!(maxNudge >= 0) || !Number.isFinite(maxNudge))
throw new Error('invalid isometric overlay boundary input');
const candidates: BoundaryCandidateMap = new Map();
const candidates = createBoundaryCandidates();
addBoundaryRectangleEvents(candidates, rectangles, maxNudge);
return Object.freeze(sortedBoundaryCandidates(candidates).map(({ offset }) =>
Object.freeze(offset) as ScenePoint));
@@ -780,55 +834,57 @@ function addCriticalBoundaryRectangle(
type BoundarySegment = readonly [start: ScenePoint, end: ScenePoint];
function addBoundarySegmentRectangleIntersections(
function addBoundarySegmentRectangleIntersection(
candidates: BoundaryCandidateMap, segment: BoundarySegment,
rectangles: readonly Bounds[], maxNudge: number,
bounds: Bounds, maxNudge: number,
): void {
const [start, end] = segment;
const dx = end[0] - start[0], dy = end[1] - start[1];
for (const bounds of rectangles) {
if (Math.abs(dx) > EPS) {
for (const x of [bounds[0], bounds[2]]) {
const ratio = (x - start[0]) / dx;
if (ratio < -EPS || ratio > 1 + EPS) continue;
const y = start[1] + dy * ratio;
if (y >= bounds[1] - EPS && y <= bounds[3] + EPS)
addBoundaryCandidate(candidates, [x, y], maxNudge);
}
if (Math.abs(dx) > EPS) {
for (const x of [bounds[0], bounds[2]]) {
const ratio = (x - start[0]) / dx;
if (ratio < -EPS || ratio > 1 + EPS) continue;
const y = start[1] + dy * ratio;
if (y >= bounds[1] - EPS && y <= bounds[3] + EPS)
addBoundaryCandidate(candidates, [x, y], maxNudge);
}
if (Math.abs(dy) > EPS) {
for (const y of [bounds[1], bounds[3]]) {
const ratio = (y - start[1]) / dy;
if (ratio < -EPS || ratio > 1 + EPS) continue;
const x = start[0] + dx * ratio;
if (x >= bounds[0] - EPS && x <= bounds[2] + EPS)
addBoundaryCandidate(candidates, [x, y], maxNudge);
}
}
if (Math.abs(dy) > EPS) {
for (const y of [bounds[1], bounds[3]]) {
const ratio = (y - start[1]) / dy;
if (ratio < -EPS || ratio > 1 + EPS) continue;
const x = start[0] + dx * ratio;
if (x >= bounds[0] - EPS && x <= bounds[2] + EPS)
addBoundaryCandidate(candidates, [x, y], maxNudge);
}
}
}
function addBoundaryLineIntersections(
candidates: BoundaryCandidateMap, segments: readonly BoundarySegment[], maxNudge: number,
function addBoundarySegmentRectangleIntersections(
candidates: BoundaryCandidateMap, segment: BoundarySegment,
rectangles: readonly Bounds[], maxNudge: number,
): void {
for (let left = 0; left < segments.length; left++) {
const [a, b] = segments[left];
const ab: ScenePoint = [b[0] - a[0], b[1] - a[1]];
for (let right = left + 1; right < segments.length; right++) {
const [c, d] = segments[right];
const cd: ScenePoint = [d[0] - c[0], d[1] - c[1]];
const denominator = ab[0] * cd[1] - ab[1] * cd[0];
if (Math.abs(denominator) <= EPS) continue;
const ac: ScenePoint = [c[0] - a[0], c[1] - a[1]];
const ratio = (ac[0] * cd[1] - ac[1] * cd[0]) / denominator;
const otherRatio = (ac[0] * ab[1] - ac[1] * ab[0]) / denominator;
if (ratio < -EPS || ratio > 1 + EPS
|| otherRatio < -EPS || otherRatio > 1 + EPS) continue;
const point: ScenePoint = [a[0] + ab[0] * ratio, a[1] + ab[1] * ratio];
if (Math.hypot(point[0], point[1]) <= maxNudge + 2)
addBoundaryCandidate(candidates, point, maxNudge);
}
}
for (const bounds of rectangles)
addBoundarySegmentRectangleIntersection(candidates, segment, bounds, maxNudge);
}
function addBoundaryLineIntersection(
candidates: BoundaryCandidateMap, left: BoundarySegment,
right: BoundarySegment, maxNudge: number,
): void {
const [a, b] = left, [c, d] = right;
const ab: ScenePoint = [b[0] - a[0], b[1] - a[1]];
const cd: ScenePoint = [d[0] - c[0], d[1] - c[1]];
const denominator = ab[0] * cd[1] - ab[1] * cd[0];
if (Math.abs(denominator) <= EPS) return;
const ac: ScenePoint = [c[0] - a[0], c[1] - a[1]];
const ratio = (ac[0] * cd[1] - ac[1] * cd[0]) / denominator;
const otherRatio = (ac[0] * ab[1] - ac[1] * ab[0]) / denominator;
if (ratio < -EPS || ratio > 1 + EPS
|| otherRatio < -EPS || otherRatio > 1 + EPS) return;
const point: ScenePoint = [a[0] + ab[0] * ratio, a[1] + ab[1] * ratio];
if (Math.hypot(point[0], point[1]) <= maxNudge + 2)
addBoundaryCandidate(candidates, point, maxNudge);
}
/**
@@ -837,11 +893,20 @@ function addBoundaryLineIntersections(
* the straight part of the Minkowski boundary; the final polygon predicate
* still decides legality around vertices and concavities.
*/
function addExpandedWallBoundarySegments(
candidates: BoundaryCandidateMap, wall: IsoWallSilhouette,
footprint: readonly ScenePoint[], gapUnits: number, unitsPerPixel: number,
maxNudge: number, rectangles: readonly Bounds[], segments?: BoundarySegment[],
): void {
type WallBoundaryEdge = {
readonly tangent: ScenePoint;
readonly normal: ScenePoint;
readonly tangentMin: number;
readonly tangentMax: number;
readonly normalOffset: number;
};
const wallBoundaryEdgeCache = new WeakMap<IsoWallSilhouette, readonly WallBoundaryEdge[]>();
function wallBoundaryEdges(wall: IsoWallSilhouette): readonly WallBoundaryEdge[] {
const cached = wallBoundaryEdgeCache.get(wall);
if (cached) return cached;
const result: WallBoundaryEdge[] = [];
for (const ring of [wall.outer, ...(wall.holes || [])]) {
for (let index = 0; index < ring.length; index++) {
const wallStart = ring[index], wallEnd = ring[(index + 1) % ring.length];
@@ -850,20 +915,43 @@ function addExpandedWallBoundarySegments(
if (edgeLength <= EPS) continue;
const tangent: ScenePoint = [edgeX / edgeLength, edgeY / edgeLength];
const normal: ScenePoint = [-tangent[1], tangent[0]];
const tangentStart = wallStart[0] * tangent[0] + wallStart[1] * tangent[1];
const tangentEnd = wallEnd[0] * tangent[0] + wallEnd[1] * tangent[1];
result.push({
tangent, normal,
tangentMin: Math.min(tangentStart, tangentEnd),
tangentMax: Math.max(tangentStart, tangentEnd),
normalOffset: wallStart[0] * normal[0] + wallStart[1] * normal[1],
});
}
}
wallBoundaryEdgeCache.set(wall, result);
return result;
}
function addExpandedWallBoundarySegments(
candidates: BoundaryCandidateMap, wall: IsoWallSilhouette,
footprint: readonly ScenePoint[], gapUnits: number, unitsPerPixel: number,
maxNudge: number, rectangles: readonly Bounds[], segments?: BoundarySegment[],
): void {
for (const edge of wallBoundaryEdges(wall)) {
const { tangent, normal } = edge;
const dot = (point: readonly number[], axis: ScenePoint): number =>
point[0] * axis[0] + point[1] * axis[1];
const wallTangentStart = dot(wallStart, tangent);
const wallTangentEnd = dot(wallEnd, tangent);
const wallTangentMin = Math.min(wallTangentStart, wallTangentEnd);
const wallTangentMax = Math.max(wallTangentStart, wallTangentEnd);
const wallNormal = dot(wallStart, normal);
const footprintTangents = footprint.map((point) => dot(point, tangent));
const footprintNormals = footprint.map((point) => dot(point, normal));
const tangentMin = wallTangentMin - Math.max(...footprintTangents) - gapUnits;
const tangentMax = wallTangentMax - Math.min(...footprintTangents) + gapUnits;
let footprintTangentMin = Infinity, footprintTangentMax = -Infinity;
let footprintNormalMin = Infinity, footprintNormalMax = -Infinity;
for (const point of footprint) {
const tangentOffset = dot(point, tangent), normalOffset = dot(point, normal);
footprintTangentMin = Math.min(footprintTangentMin, tangentOffset);
footprintTangentMax = Math.max(footprintTangentMax, tangentOffset);
footprintNormalMin = Math.min(footprintNormalMin, normalOffset);
footprintNormalMax = Math.max(footprintNormalMax, normalOffset);
}
const tangentMin = edge.tangentMin - footprintTangentMax - gapUnits;
const tangentMax = edge.tangentMax - footprintTangentMin + gapUnits;
const normalOffsets = [
wallNormal - gapUnits - Math.max(...footprintNormals),
wallNormal + gapUnits - Math.min(...footprintNormals),
edge.normalOffset - gapUnits - footprintNormalMax,
edge.normalOffset + gapUnits - footprintNormalMin,
];
for (const normalOffset of normalOffsets) {
const toPoint = (tangentOffset: number): ScenePoint => [
@@ -880,7 +968,6 @@ function addExpandedWallBoundarySegments(
candidates, clipped, rectangles, maxNudge,
);
}
}
}
}
@@ -902,31 +989,12 @@ function addBoundaryCircle(
}
function sortedBoundaryCandidates(candidates: BoundaryCandidateMap): GroupOffset[] {
return [...candidates.values()].map((offset) => ({
return [...candidates.points.values()].map((offset) => ({
offset, distance: Math.hypot(offset[0], offset[1]),
})).sort((a, b) => a.distance - b.distance
|| a.offset[1] - b.offset[1] || a.offset[0] - b.offset[0]);
}
/**
* Snap a continuous boundary event back to the exact integer-pixel result.
* The bounded 9x9 neighbourhood replaces the old complete 7,238-point disk.
*/
function localRefinementOffsets(
around: ScenePoint, maxNudge: number, reach = 4,
): readonly GroupOffset[] {
const offsets: GroupOffset[] = [];
for (let y = Math.floor(around[1] - reach); y <= Math.ceil(around[1] + reach); y++) {
for (let x = Math.floor(around[0] - reach); x <= Math.ceil(around[0] + reach); x++) {
const distance = Math.hypot(x, y);
if (distance <= maxNudge + EPS) offsets.push({ offset: [x, y], distance });
}
}
offsets.sort((a, b) => a.distance - b.distance
|| a.offset[1] - b.offset[1] || a.offset[0] - b.offset[0]);
return offsets;
}
function overlayRootBounds(
item: IsoOverlayCollisionItem, center: ScenePoint,
): Bounds {
@@ -1024,14 +1092,29 @@ export function resolveIsoOverlayCollisions(
const gapUnits = safetyGap * unitsPerPixel;
const cellUnits = ISO_OVERLAY_GROUP_CELL_CSS_PX * unitsPerPixel;
const rooms = new Map(input.rooms.filter(validRoom).map((room) => [room.id, room]));
const roomBounds = new Map([...rooms].map(([id, room]) => [
id, ringBounds(room.outer as readonly ScenePoint[]),
]));
const axisAlignedRoomBoxes = new Map([...rooms].flatMap(([id, room]) => {
const bounds = axisAlignedRoomBox(room);
return bounds ? [[id, bounds] as const] : [];
}));
const wallsValid = input.wallSilhouettes.every(validSilhouette);
const wallRows = input.wallSilhouettes.map((wall) => ({
wall, bounds: silhouetteBounds(wall, true),
}));
const accepted: AcceptedOverlay[] = [];
const cells = new Map<string, number[]>();
const cells = new Map<number | string, number[]>();
const placements = new Map<string, IsoOverlayPlacement>();
const residualPairs: Array<readonly [string, string]> = [];
const stableItems = [...input.items].sort((a, b) =>
a.placement.nudgeDistanceCss - b.placement.nudgeDistanceCss
|| isoOverlayCollisionKey(a.kind, a.id).localeCompare(isoOverlayCollisionKey(b.kind, b.id)));
const rot = camera.rotDeg * Math.PI / 180;
const tilt = camera.tiltDeg * Math.PI / 180;
const inverseX = 1 / camera.xyScale;
const inverseY = 1 / (camera.xyScale * Math.cos(tilt));
const cosRot = Math.cos(rot), sinRot = Math.sin(rot);
const cellRange = (bounds: Bounds): readonly [number, number, number, number] => [
Math.floor(bounds[0] / cellUnits), Math.floor(bounds[1] / cellUnits),
@@ -1042,7 +1125,7 @@ export function resolveIsoOverlayCollisions(
const result = new Set<number>();
for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) {
for (const index of cells.get(`${x}:${y}`) || []) result.add(index);
for (const index of cells.get(boundaryCandidateKey(x, y)) || []) result.add(index);
}
}
return [...result].sort((a, b) => a - b);
@@ -1052,7 +1135,7 @@ export function resolveIsoOverlayCollisions(
const [minX, minY, maxX, maxY] = cellRange(value.bounds);
for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) {
const key = `${x}:${y}`;
const key = boundaryCandidateKey(x, y);
const list = cells.get(key) || [];
list.push(index);
cells.set(key, list);
@@ -1072,16 +1155,15 @@ export function resolveIsoOverlayCollisions(
] as ScenePoint);
const ownerRoom = base.owner ? rooms.get(base.owner.id) || null : null;
const currentPlan = raisedSceneToPlan(base.visualScene, visualOffset, camera);
const baseFootprintBounds = ringBounds(baseFootprint);
const wallCandidates = wallsValid && baseFootprint.length
? input.wallSilhouettes.filter((wall) => {
const wallBounds = silhouetteBounds(wall, true);
? wallRows.filter(({ bounds: wallBounds }) => {
if (!wallBounds) return false;
const radius = maxNudge * unitsPerPixel;
const footprintBounds = ringBounds(baseFootprint);
return !!footprintBounds && boundsNear(expandedBounds(footprintBounds, radius),
return !!baseFootprintBounds && boundsNear(expandedBounds(baseFootprintBounds, radius),
wallBounds, gapUnits);
})
: input.wallSilhouettes;
: wallRows;
/**
* Дешёвая половина кандидата: где он окажется и с кем столкнётся.
@@ -1147,8 +1229,16 @@ export function resolveIsoOverlayCollisions(
* съедала 8.5 из 9.6 секунд группового прохода. Подавляющее большинство
* этих точек лежит ВНЕ комнаты — узнать это можно сравнением четырёх чисел,
* а не обходом колец полигона и силуэтов стен.
*/
const ownerBox = ownerRoom ? ringBounds(ownerRoom.outer as readonly ScenePoint[]) : null;
*/
const ownerBox = ownerRoom ? roomBounds.get(ownerRoom.id) || null : null;
const ownerAxisBox = ownerRoom ? axisAlignedRoomBoxes.get(ownerRoom.id) || null : null;
const currentStrictlyInOwner = !!ownerRoom
&& (ownerAxisBox
? currentPlan[0] > ownerAxisBox[0] + EPS
&& currentPlan[0] < ownerAxisBox[2] - EPS
&& currentPlan[1] > ownerAxisBox[1] + EPS
&& currentPlan[1] < ownerAxisBox[3] - EPS
: pointStrictlyInValidatedRoom(currentPlan, ownerRoom));
/**
* Широкая фаза по стенам — то, чего требовал §6.4 ТЗ и чего не было.
@@ -1159,14 +1249,14 @@ export function resolveIsoOverlayCollisions(
* Стены раскладываются по тем же ячейкам, что и принятые оверлеи, и каждый
* кандидат смотрит только свои ячейки.
*/
const wallCells = new Map<string, number[]>();
const wallCells = new Map<number | string, number[]>();
for (let index = 0; index < wallCandidates.length; index++) {
const wallBounds = silhouetteBounds(wallCandidates[index], true);
const wallBounds = wallCandidates[index].bounds;
if (!wallBounds) continue;
const [minX, minY, maxX, maxY] = cellRange(expandedBounds(wallBounds, gapUnits));
for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) {
const key = `${x}:${y}`;
const key = boundaryCandidateKey(x, y);
const list = wallCells.get(key) || [];
list.push(index);
wallCells.set(key, list);
@@ -1177,52 +1267,79 @@ export function resolveIsoOverlayCollisions(
// стоит дороже самой проверки.
const wallSeen = new Int32Array(wallCandidates.length);
let wallSeenGeneration = 0;
const wallsNear = (bounds: Bounds): number[] => {
const [minX, minY, maxX, maxY] = cellRange(expandedBounds(bounds, gapUnits));
const result: number[] = [];
const translatedFootprint = baseFootprint.map(() => [0, 0] as [number, number]);
const footprintAt = (offset: ScenePoint): readonly ScenePoint[] => {
for (let index = 0; index < baseFootprint.length; index++) {
translatedFootprint[index][0] = baseFootprint[index][0] + offset[0];
translatedFootprint[index][1] = baseFootprint[index][1] + offset[1];
}
return translatedFootprint;
};
const firstWallNear = (
bounds: Bounds, footprint: () => readonly ScenePoint[],
): number | undefined => {
const minX = Math.floor((bounds[0] - gapUnits) / cellUnits);
const minY = Math.floor((bounds[1] - gapUnits) / cellUnits);
const maxX = Math.floor((bounds[2] + gapUnits) / cellUnits);
const maxY = Math.floor((bounds[3] + gapUnits) / cellUnits);
wallSeenGeneration += 1;
for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) {
for (const index of wallCells.get(`${x}:${y}`) || []) {
for (const index of wallCells.get(boundaryCandidateKey(x, y)) || []) {
if (wallSeen[index] === wallSeenGeneration) continue;
wallSeen[index] = wallSeenGeneration;
result.push(index);
if (footprintNearSilhouette(
footprint(), bounds, wallCandidates[index].wall, gapUnits, true,
)) return index;
}
}
}
return result;
return undefined;
};
const INSPECTION_ALLOWED = -2;
const INSPECTION_ROOM = -1;
const inspectCandidate = (shape: {
offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint;
}): { allowed: boolean; walls: readonly number[]; room: boolean } => {
if (shape.sameAsBase) return { allowed: true, walls: [], room: false };
if (!wallsValid || !ownerRoom) return { allowed: false, walls: [], room: true };
const plan = raisedSceneToPlan(shape.visualScene, visualOffset, camera);
if (ownerBox && (plan[0] < ownerBox[0] || plan[0] > ownerBox[2]
|| plan[1] < ownerBox[1] || plan[1] > ownerBox[3]))
return { allowed: false, walls: [], room: true };
if (!pointStrictlyInRoom(plan, ownerRoom))
return { allowed: false, walls: [], room: true };
if (pointStrictlyInRoom(currentPlan, ownerRoom)
&& !segmentStrictlyInRoom(currentPlan, plan, ownerRoom))
return { allowed: false, walls: [], room: true };
const footprint = baseFootprint.map((point) => [
point[0] + shape.offsetScene[0], point[1] + shape.offsetScene[1],
] as ScenePoint);
const footprintBounds = ringBounds(footprint);
if (!footprintBounds) return { allowed: false, walls: [], room: true };
const wall = wallsNear(footprintBounds).find((index) =>
footprintNearSilhouette(
footprint, footprintBounds, wallCandidates[index], gapUnits, true,
));
return wall === undefined
? { allowed: true, walls: [], room: false }
: { allowed: false, walls: [wall], room: false };
}): number => {
if (shape.sameAsBase) return INSPECTION_ALLOWED;
if (!wallsValid || !ownerRoom) return INSPECTION_ROOM;
const sceneDx = shape.visualScene[0] - base.visualScene[0];
const sceneDy = shape.visualScene[1] - base.visualScene[1];
const rx = sceneDx * inverseX, ry = sceneDy * inverseY;
const planX = currentPlan[0] + rx * cosRot + ry * sinRot;
const planY = currentPlan[1] - rx * sinRot + ry * cosRot;
if (ownerBox && (planX < ownerBox[0] || planX > ownerBox[2]
|| planY < ownerBox[1] || planY > ownerBox[3]))
return INSPECTION_ROOM;
if (ownerAxisBox) {
if (!(planX > ownerAxisBox[0] + EPS && planX < ownerAxisBox[2] - EPS
&& planY > ownerAxisBox[1] + EPS && planY < ownerAxisBox[3] - EPS))
return INSPECTION_ROOM;
} else {
const plan: PlanPoint = [planX, planY];
if (!pointStrictlyInValidatedRoom(plan, ownerRoom))
return INSPECTION_ROOM;
if (currentStrictlyInOwner
&& !segmentBetweenStrictRoomPoints(currentPlan, plan, ownerRoom))
return INSPECTION_ROOM;
}
if (!baseFootprintBounds) return INSPECTION_ROOM;
const footprintBounds: Bounds = [
baseFootprintBounds[0] + shape.offsetScene[0],
baseFootprintBounds[1] + shape.offsetScene[1],
baseFootprintBounds[2] + shape.offsetScene[0],
baseFootprintBounds[3] + shape.offsetScene[1],
];
let footprint: readonly ScenePoint[] | null = null;
const wall = firstWallNear(
footprintBounds, () => footprint ||= footprintAt(shape.offsetScene),
);
return wall === undefined ? INSPECTION_ALLOWED : wall;
};
const candidateAllowed = (shape: {
offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint;
}): boolean => inspectCandidate(shape).allowed;
}): boolean => inspectCandidate(shape) === INSPECTION_ALLOWED;
const candidate = (offsetCss: ScenePoint): {
placement: IsoOverlayPlacement;
@@ -1238,8 +1355,13 @@ export function resolveIsoOverlayCollisions(
};
};
let best = candidate(baseOffsetCss);
const baseCandidate = candidate(baseOffsetCss);
let best = baseCandidate;
if (!best || best.conflicts.length) {
const hinted = item.nudgeHintCss ? candidate(item.nudgeHintCss) : null;
if (hinted && !hinted.conflicts.length) best = hinted;
}
if (!baseCandidate || baseCandidate.conflicts.length) {
/**
* A nearest free point must touch the boundary of the forbidden union.
* Enumerate those one-dimensional boundaries instead of the 7238 points
@@ -1247,12 +1369,12 @@ export function resolveIsoOverlayCollisions(
* preserve the old integer result even when a legal slit is narrower
* than the former 4 px coarse grid.
*/
const boundaryCandidates: BoundaryCandidateMap = new Map();
const boundaryCandidates = createBoundaryCandidates();
const overlayBoundaryRectangles: Bounds[] = [];
const boundaryRectangles: Bounds[] = [];
const boundarySegments: BoundarySegment[] = [];
const expandedOverlayBoundaries = new Set<number>();
const encounteredOverlayBoundaries = new Set<number>(best?.conflicts || []);
const encounteredOverlayBoundaries = new Set<number>(baseCandidate?.conflicts || []);
const addOverlayBoundary = (index: number): void => {
if (expandedOverlayBoundaries.has(index)) return;
expandedOverlayBoundaries.add(index);
@@ -1271,15 +1393,13 @@ export function resolveIsoOverlayCollisions(
boundaryRectangles.push(rectangle);
};
const footprintBounds = ringBounds(baseFootprint);
const footprintBounds = baseFootprintBounds;
const expandedWalls = new Set<number>();
const pendingWalls = new Set<number>();
const evaluated = new Set<string>();
const addWallBoundary = (index: number): void => {
if (expandedWalls.has(index) || !footprintBounds) return;
expandedWalls.add(index);
const wall = wallCandidates[index];
const wallBounds = silhouetteBounds(wall, true);
const { wall, bounds: wallBounds } = wallCandidates[index];
if (wallBounds) {
const expandedWallBounds: Bounds = [
(wallBounds[0] - gapUnits - footprintBounds[2]) / unitsPerPixel,
@@ -1333,24 +1453,26 @@ export function resolveIsoOverlayCollisions(
boundaryCandidates, [boundaryRectangles[index]], maxNudge,
);
for (let previous = 0; previous < index; previous++)
addBoundaryRectangleEvents(boundaryCandidates, [
boundaryRectangles[previous], boundaryRectangles[index],
], maxNudge);
addBoundaryRectangleIntersections(
boundaryCandidates, boundaryRectangles[previous],
boundaryRectangles[index], maxNudge,
);
}
// Concave silhouettes and the safety-gap rounding meet where finite
// boundary segments cross. Exact polygons still make the final call.
for (let index = processedSegments; index < boundarySegments.length; index++) {
for (let previous = 0; previous < index; previous++)
addBoundaryLineIntersections(boundaryCandidates, [
boundarySegments[previous], boundarySegments[index],
], maxNudge);
addBoundaryLineIntersection(
boundaryCandidates, boundarySegments[previous],
boundarySegments[index], maxNudge,
);
}
for (let index = processedOverlayRectangles;
index < overlayBoundaryRectangles.length; index++) {
for (let segment = 0; segment < processedSegments; segment++)
addBoundarySegmentRectangleIntersections(
addBoundarySegmentRectangleIntersection(
boundaryCandidates, boundarySegments[segment],
[overlayBoundaryRectangles[index]], maxNudge,
overlayBoundaryRectangles[index], maxNudge,
);
}
for (let index = processedSegments; index < boundarySegments.length; index++)
@@ -1364,9 +1486,8 @@ export function resolveIsoOverlayCollisions(
};
const evaluateNewCandidates = (): void => {
const entries = [...boundaryCandidates.entries()]
.filter(([key]) => !evaluated.has(key))
.map(([, offset]) => ({
const entries = boundaryCandidates.pending.splice(0)
.map((offset) => ({
offset, distance: Math.hypot(offset[0], offset[1]),
}))
.sort((a, b) => a.distance - b.distance
@@ -1379,9 +1500,6 @@ export function resolveIsoOverlayCollisions(
? best.placement.nudgeDistanceCss : Infinity;
if (entry.distance > maxNudge + EPS || entry.distance > bestFreeDistance + EPS) break;
const offset = entry.offset;
const key = boundaryCandidateKey(offset[0], offset[1]);
if (evaluated.has(key)) continue;
evaluated.add(key);
if (Math.abs(offset[0] - baseOffsetCss[0]) <= EPS
&& Math.abs(offset[1] - baseOffsetCss[1]) <= EPS) continue;
const shape = candidateShape(offset);
@@ -1394,8 +1512,9 @@ export function resolveIsoOverlayCollisions(
|| best.conflicts.length && shape.penalty < best.penalty - EPS;
if (!canWin) continue;
const inspection = inspectCandidate(shape);
if (!inspection.allowed) {
for (const wallIndex of inspection.walls) {
if (inspection !== INSPECTION_ALLOWED) {
if (inspection >= 0) {
const wallIndex = inspection;
if (expandedWalls.has(wallIndex)) continue;
const witness = {
index: wallIndex,
@@ -1461,18 +1580,6 @@ export function resolveIsoOverlayCollisions(
refreshBoundaryEvents();
evaluateNewCandidates();
}
if (best && !best.conflicts.length) {
const around = best.placement.nudgeCss;
for (const entry of localRefinementOffsets(around, maxNudge)) {
if (entry.distance >= best.placement.nudgeDistanceCss - EPS) break;
const shape = candidateShape(entry.offset);
if (!shape || shape.conflicts.length || !candidateAllowed(shape)) continue;
best = {
placement: placementAtGroupOffset(base, entry.offset, unitsPerPixel, false),
bounds: shape.bounds, conflicts: shape.conflicts, penalty: shape.penalty,
};
}
}
}
if (!best) {
const placement = placementAtGroupOffset(base, baseOffsetCss, unitsPerPixel, true);
+24 -6
View File
@@ -974,13 +974,31 @@ export function buildIsoOverlayRenderScene(input: IsoOverlaySceneInput): IsoOver
if (previous?.collisionSignature === collisionSignature
&& samePlacementMap(previous.rooms, roomPlacements)) return previous;
const previousEntries = new Map(previous?.entries.map((entry) => [
`${entry.kind}\u0000${entry.id}`, entry,
]) || []);
const collision = mode === 'live' ? resolveIsoOverlayCollisions({
items: entries.flatMap((entry) => entry.kind === 'room-label' ? [] : [{
id: entry.id,
kind: entry.kind,
placement: entry.placement,
screenHalfSize: entry.screenHalfSize,
}]),
items: entries.flatMap((entry) => {
if (entry.kind === 'room-label') return [];
const before = previousEntries.get(`${entry.kind}\u0000${entry.id}`);
const sameShape = !!before
&& before.screenHalfSize[0] === entry.screenHalfSize[0]
&& before.screenHalfSize[1] === entry.screenHalfSize[1]
&& before.placement.floorAnchor[0] === entry.placement.floorAnchor[0]
&& before.placement.floorAnchor[1] === entry.placement.floorAnchor[1]
&& (before.placement.owner?.id || '') === (entry.placement.owner?.id || '');
return [{
id: entry.id,
kind: entry.kind,
placement: entry.placement,
screenHalfSize: entry.screenHalfSize,
...(sameShape ? { nudgeHintCss: [
before!.placement.nudgeScene[0] / unitsPerPixel,
before!.placement.nudgeScene[1] / unitsPerPixel,
] as ScenePoint } : {}),
}];
}),
rooms,
wallSilhouettes: input.wallSilhouettes,
sceneUnitsPerCssPixel: unitsPerPixel,
+8
View File
@@ -97,6 +97,14 @@ test('group collision separates a solvable dense set independently of input orde
}
assert.deepEqual(normal.placements.get(keys[0]).visualScene, [100, 100],
'the stable first item stays at its zero-deviation anchor');
const hintedItems = [make('a'), make('b'), make('lock')].map((item) => ({
...item,
nudgeHintCss: normal.placements.get(isoOverlayCollisionKey(item.kind, item.id)).nudgeCss,
}));
const hinted = solve(hintedItems);
for (const key of keys) assert.deepEqual(hinted.placements.get(key), normal.placements.get(key),
'a previous exact placement is only an upper bound and cannot change the nearest result');
});
test('group collision finds a legal one-pixel slit between the coarse nodes', () => {