toposync-ext-images 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toposync_ext_images-0.1.0/.gitignore +39 -0
- toposync_ext_images-0.1.0/LICENSE +21 -0
- toposync_ext_images-0.1.0/PKG-INFO +19 -0
- toposync_ext_images-0.1.0/README.md +9 -0
- toposync_ext_images-0.1.0/pyproject.toml +19 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/__init__.py +2 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/extension.json +13 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/plugin.py +16 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/326.js +2 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/326.js.LICENSE.txt +9 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/387.js +1 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/703.js +2 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/703.js.LICENSE.txt +9 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/main.js +2 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/main.js.LICENSE.txt +9 -0
- toposync_ext_images-0.1.0/src/toposync_ext_images/static/remoteEntry.js +1 -0
- toposync_ext_images-0.1.0/ui/package.json +22 -0
- toposync_ext_images-0.1.0/ui/src/activate.tsx +14 -0
- toposync_ext_images-0.1.0/ui/src/api/filesApi.ts +24 -0
- toposync_ext_images-0.1.0/ui/src/constants.ts +13 -0
- toposync_ext_images-0.1.0/ui/src/debug.ts +14 -0
- toposync_ext_images-0.1.0/ui/src/dropHandlers/imageDropHandler.ts +65 -0
- toposync_ext_images-0.1.0/ui/src/elements/ImageEditorModal.tsx +242 -0
- toposync_ext_images-0.1.0/ui/src/elements/ImageElementType.tsx +240 -0
- toposync_ext_images-0.1.0/ui/src/elements/ImageScaleReference.tsx +387 -0
- toposync_ext_images-0.1.0/ui/src/entry.ts +4 -0
- toposync_ext_images-0.1.0/ui/src/imageUtils.ts +36 -0
- toposync_ext_images-0.1.0/ui/src/parsing.ts +35 -0
- toposync_ext_images-0.1.0/ui/src/tools/addImageTool.ts +225 -0
- toposync_ext_images-0.1.0/ui/src/translations.ts +90 -0
- toposync_ext_images-0.1.0/ui/src/types.ts +9 -0
- toposync_ext_images-0.1.0/ui/tsconfig.json +14 -0
- toposync_ext_images-0.1.0/ui/webpack.config.js +42 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
.env
|
|
3
|
+
.venv
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.pyc
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
|
|
9
|
+
node_modules/
|
|
10
|
+
yarn.lock
|
|
11
|
+
.pnp.cjs
|
|
12
|
+
.pnp.loader.mjs
|
|
13
|
+
.yarn/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
.parcel-cache/
|
|
17
|
+
|
|
18
|
+
.toposync-data/
|
|
19
|
+
.toposync-processor-data
|
|
20
|
+
toposync-data/
|
|
21
|
+
|
|
22
|
+
*.log
|
|
23
|
+
|
|
24
|
+
*.ignore.md
|
|
25
|
+
ignore/
|
|
26
|
+
|
|
27
|
+
# Playwright
|
|
28
|
+
test-results/
|
|
29
|
+
playwright-report/
|
|
30
|
+
yolo*.pt
|
|
31
|
+
|
|
32
|
+
# Streaming extension engines are downloaded at runtime.
|
|
33
|
+
extensions/streaming/src/toposync_ext_streaming/bin/mediamtx/**/mediamtx*
|
|
34
|
+
extensions/streaming/src/toposync_ext_streaming/bin/ffmpeg/**/ffmpeg*
|
|
35
|
+
|
|
36
|
+
# Vision model artifacts are provisioned locally and must not be committed.
|
|
37
|
+
extensions/vision/models/
|
|
38
|
+
|
|
39
|
+
*.temporary.*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mateus Calza
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: toposync-ext-images
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Toposync first-party extension: import images as overlays or tracing references.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: toposync-core>=0.3.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# Images extension
|
|
12
|
+
|
|
13
|
+
First-party Toposync extension to import images and place them on the floor as:
|
|
14
|
+
|
|
15
|
+
- **Overlay**: intended to be part of the 3D scene (e.g. labels, decals).
|
|
16
|
+
- **Tracing**: a reference layer to help drawing walls/areas on top of a floor plan.
|
|
17
|
+
|
|
18
|
+
The UI is shipped as a prebuilt Module Federation bundle under `static/`.
|
|
19
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Images extension
|
|
2
|
+
|
|
3
|
+
First-party Toposync extension to import images and place them on the floor as:
|
|
4
|
+
|
|
5
|
+
- **Overlay**: intended to be part of the 3D scene (e.g. labels, decals).
|
|
6
|
+
- **Tracing**: a reference layer to help drawing walls/areas on top of a floor plan.
|
|
7
|
+
|
|
8
|
+
The UI is shipped as a prebuilt Module Federation bundle under `static/`.
|
|
9
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "toposync-ext-images"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Toposync first-party extension: import images as overlays or tracing references."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
|
+
dependencies = ["toposync-core>=0.3.0"]
|
|
10
|
+
|
|
11
|
+
[project.entry-points."toposync.extensions"]
|
|
12
|
+
images = "toposync_ext_images.plugin:ImagesExtension"
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["hatchling>=1.25"]
|
|
16
|
+
build-backend = "hatchling.build"
|
|
17
|
+
|
|
18
|
+
[tool.hatch.build.targets.wheel]
|
|
19
|
+
packages = ["src/toposync_ext_images"]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
|
|
5
|
+
from toposync.extensions import BaseExtension
|
|
6
|
+
from toposync.runtime.event_bus import EventBus
|
|
7
|
+
from toposync.runtime.services import ServiceRegistry
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ImagesExtension(BaseExtension):
|
|
11
|
+
def __init__(self) -> None:
|
|
12
|
+
super().__init__(package="toposync_ext_images")
|
|
13
|
+
|
|
14
|
+
async def setup(self, app: FastAPI, *, bus: EventBus, services: ServiceRegistry) -> None: # noqa: ARG002
|
|
15
|
+
return None
|
|
16
|
+
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! For license information please see 326.js.LICENSE.txt */
|
|
2
|
+
"use strict";(self.webpackChunk_toposync_extension_images_ui=self.webpackChunk_toposync_extension_images_ui||[]).push([[326],{249(e,t){var r=Symbol.for("react.element"),n=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),u=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),a=Symbol.for("react.provider"),i=Symbol.for("react.context"),f=Symbol.for("react.forward_ref"),s=Symbol.for("react.suspense"),l=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),y=Symbol.iterator,d={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,h={};function m(e,t,r){this.props=e,this.context=t,this.refs=h,this.updater=r||d}function b(){}function v(e,t,r){this.props=e,this.context=t,this.refs=h,this.updater=r||d}m.prototype.isReactComponent={},m.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},m.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=m.prototype;var S=v.prototype=new b;S.constructor=v,_(S,m.prototype),S.isPureReactComponent=!0;var k=Array.isArray,w=Object.prototype.hasOwnProperty,E={current:null},$={key:!0,ref:!0,__self:!0,__source:!0};function R(e,t,n){var o,u={},c=null,a=null;if(null!=t)for(o in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(c=""+t.key),t)w.call(t,o)&&!$.hasOwnProperty(o)&&(u[o]=t[o]);var i=arguments.length-2;if(1===i)u.children=n;else if(1<i){for(var f=Array(i),s=0;s<i;s++)f[s]=arguments[s+2];u.children=f}if(e&&e.defaultProps)for(o in i=e.defaultProps)void 0===u[o]&&(u[o]=i[o]);return{$$typeof:r,type:e,key:c,ref:a,props:u,_owner:E.current}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===r}var g=/\/+/g;function j(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(e){return t[e]})}(""+e.key):t.toString(36)}function x(e,t,o,u,c){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var i=!1;if(null===e)i=!0;else switch(a){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case r:case n:i=!0}}if(i)return c=c(i=e),e=""===u?"."+j(i,0):u,k(c)?(o="",null!=e&&(o=e.replace(g,"$&/")+"/"),x(c,t,o,"",function(e){return e})):null!=c&&(C(c)&&(c=function(e,t){return{$$typeof:r,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(c,o+(!c.key||i&&i.key===c.key?"":(""+c.key).replace(g,"$&/")+"/")+e)),t.push(c)),1;if(i=0,u=""===u?".":u+":",k(e))for(var f=0;f<e.length;f++){var s=u+j(a=e[f],f);i+=x(a,t,o,s,c)}else if(s=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=y&&e[y]||e["@@iterator"])?e:null}(e),"function"==typeof s)for(e=s.call(e),f=0;!(a=e.next()).done;)i+=x(a=a.value,t,o,s=u+j(a,f++),c);else if("object"===a)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function O(e,t,r){if(null==e)return e;var n=[],o=0;return x(e,n,"","",function(e){return t.call(r,e,o++)}),n}function P(e){if(-1===e._status){var t=e._result;(t=t()).then(function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)},function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)}),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var I={current:null},T={transition:null},V={ReactCurrentDispatcher:I,ReactCurrentBatchConfig:T,ReactCurrentOwner:E};function A(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:O,forEach:function(e,t,r){O(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return O(e,function(){t++}),t},toArray:function(e){return O(e,function(e){return e})||[]},only:function(e){if(!C(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=m,t.Fragment=o,t.Profiler=c,t.PureComponent=v,t.StrictMode=u,t.Suspense=s,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=V,t.act=A,t.cloneElement=function(e,t,n){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var o=_({},e.props),u=e.key,c=e.ref,a=e._owner;if(null!=t){if(void 0!==t.ref&&(c=t.ref,a=E.current),void 0!==t.key&&(u=""+t.key),e.type&&e.type.defaultProps)var i=e.type.defaultProps;for(f in t)w.call(t,f)&&!$.hasOwnProperty(f)&&(o[f]=void 0===t[f]&&void 0!==i?i[f]:t[f])}var f=arguments.length-2;if(1===f)o.children=n;else if(1<f){i=Array(f);for(var s=0;s<f;s++)i[s]=arguments[s+2];o.children=i}return{$$typeof:r,type:e.type,key:u,ref:c,props:o,_owner:a}},t.createContext=function(e){return(e={$$typeof:i,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},t.createElement=R,t.createFactory=function(e){var t=R.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:f,render:e}},t.isValidElement=C,t.lazy=function(e){return{$$typeof:p,_payload:{_status:-1,_result:e},_init:P}},t.memo=function(e,t){return{$$typeof:l,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=T.transition;T.transition={};try{e()}finally{T.transition=t}},t.unstable_act=A,t.useCallback=function(e,t){return I.current.useCallback(e,t)},t.useContext=function(e){return I.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return I.current.useDeferredValue(e)},t.useEffect=function(e,t){return I.current.useEffect(e,t)},t.useId=function(){return I.current.useId()},t.useImperativeHandle=function(e,t,r){return I.current.useImperativeHandle(e,t,r)},t.useInsertionEffect=function(e,t){return I.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return I.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return I.current.useMemo(e,t)},t.useReducer=function(e,t,r){return I.current.useReducer(e,t,r)},t.useRef=function(e){return I.current.useRef(e)},t.useState=function(e){return I.current.useState(e)},t.useSyncExternalStore=function(e,t,r){return I.current.useSyncExternalStore(e,t,r)},t.useTransition=function(){return I.current.useTransition()},t.version="18.3.1"},326(e,t,r){e.exports=r(249)}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunk_toposync_extension_images_ui=self.webpackChunk_toposync_extension_images_ui||[]).push([[387],{387(t){function n(){return"undefined"==typeof window?"/":function(t){const n=String(t||"").trim();return n&&(n.startsWith("/")?n:`/${n}`).replace(/\/+$/,"")||"/"}(window.__TOPOSYNC_PUBLIC_BASE_PATH__)}function e(t){const e=n();return t.startsWith("/")?"/"===e||t===e||t.startsWith(`${e}/`)?t:`${e}${t}`:t}t.exports={getToposyncBasePath:n,resolveToposyncUrl:function(t){const n=String(t||"");if(!n)return n;if("undefined"==typeof window)return n;if(/^(data:|blob:|mailto:|tel:|#)/i.test(n))return n;if(n.startsWith("//"))return n;if(/^[a-z][a-z0-9+.-]*:/i.test(n))try{const t=new URL(n,window.location.href);return t.origin!==window.location.origin?n:e(`${t.pathname}${t.search}${t.hash}`)}catch{return n}return n.startsWith("/")?e(n):n}}}}]);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! For license information please see 703.js.LICENSE.txt */
|
|
2
|
+
"use strict";(self.webpackChunk_toposync_extension_images_ui=self.webpackChunk_toposync_extension_images_ui||[]).push([[703],{87(e,t,i){i.d(t,{Fk:()=>o,MG:()=>a,Y:()=>r,cR:()=>c,nJ:()=>s,pd:()=>d,s9:()=>n,w2:()=>l});const a="com.toposync.images.image",n="com.toposync.images.tool.addOverlay",l="com.toposync.images.tool.addTracing",s="toposync.images.debug",r=4,o=1,d=.55,c=.012},94(e,t,i){var a=i(496),n=Symbol.for("react.element"),l=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,r=a.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,o={key:!0,ref:!0,__self:!0,__source:!0};function d(e,t,i){var a,l={},d=null,c=null;for(a in void 0!==i&&(d=""+i),void 0!==t.key&&(d=""+t.key),void 0!==t.ref&&(c=t.ref),t)s.call(t,a)&&!o.hasOwnProperty(a)&&(l[a]=t[a]);if(e&&e.defaultProps)for(a in t=e.defaultProps)void 0===l[a]&&(l[a]=t[a]);return{$$typeof:n,type:e,key:d,ref:c,props:l,_owner:r.current}}t.Fragment=l,t.jsx=d,t.jsxs=d},171(e,t,i){i.d(t,{F:()=>s});var a=i(840),n=i(87),l=i(202);function s(e){const t=e.t;return{id:"com.toposync.images.dropHandler.image",canHandle:e=>e.files.some(e=>(0,l.u)(e)),handle:async(e,i)=>{const s=i.files.find(e=>(0,l.u)(e))??null;if(!s)return!1;const r=await(0,l.DQ)(s),o=await(0,a.B)(s,{filename:s.name}),d=e.elements.some(e=>e.type!==n.MG)?"overlay":"tracing",c=r&&r.height>0?r.width/r.height:null,m=n.Y,u=c?m/c:m,p="tracing"===d?n.pd:n.Fk,g="tracing"===d?"multiply":"normal",h=function(e){return e.viewport.screenToWorld({x:e.viewport.width/2,y:e.viewport.height/2})}(i),x=(0,l.jl)(s.name)||t("tracing"===d?"ext.images.editor.mode.tracing":"ext.images.editor.mode.overlay"),f=e.createElement(n.MG,{name:x,position:{x:h.x,y:0,z:h.z},props:{dir:o.dir,file:o.filename,width_m:m,depth_m:u,opacity:p,mode:d,blend:g,pixel_width:r?.width??null,pixel_height:r?.height??null}});return f&&e.openEditor(f),!0}}}},202(e,t,i){function a(e){const t=e.replace(/^.*[\\/]/,""),i=t.lastIndexOf(".");return i<=0?t:t.slice(0,i)}function n(e){if(e.type&&e.type.startsWith("image/"))return!0;const t=e.name.toLowerCase();return t.endsWith(".png")||t.endsWith(".jpg")||t.endsWith(".jpeg")||t.endsWith(".webp")||t.endsWith(".gif")||t.endsWith(".bmp")||t.endsWith(".svg")}async function l(e){const t=URL.createObjectURL(e);try{const e=new Image;return e.decoding="async",e.src=t,await e.decode(),{width:e.naturalWidth,height:e.naturalHeight}}catch{return null}finally{URL.revokeObjectURL(t)}}i.d(t,{DQ:()=>l,jl:()=>a,u:()=>n})},322(e,t,i){function a(e,t,i){return Number.isFinite(e)?Math.min(i,Math.max(t,e)):t}function n(e,t){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e){const t=Number(e);if(Number.isFinite(t))return t}return t}function l(e,t){return"string"==typeof e?e:t}function s(e,t){return"overlay"===e||"tracing"===e?e:t}function r(e,t){return"normal"===e||"multiply"===e?e:t}i.d(t,{E3:()=>l,Vl:()=>r,Zi:()=>s,kz:()=>n,qE:()=>a})},381(e,t,i){i.d(t,{c:()=>l});var a=i(87);const n=(()=>{try{return"1"===localStorage.getItem(a.nJ)}catch{return!1}})();function l(...e){n&&console.log(...e)}},416(e,t,i){i.d(t,{F:()=>a});const a={en:{"ext.images.element.name":"Image","ext.images.element.desc":"Imported image placed on the floor as an overlay or tracing reference.","ext.images.tool.add_overlay":"Overlay image","ext.images.tool.add_overlay_desc":"Click to upload and place an overlay image on the floor.","ext.images.tool.add_tracing":"Tracing image","ext.images.tool.add_tracing_desc":"Click to upload and place a tracing reference image on the floor.","ext.images.editor.title":"Image","ext.images.editor.mode":"Mode","ext.images.editor.mode.overlay":"Overlay","ext.images.editor.mode.tracing":"Tracing","ext.images.editor.opacity":"Opacity","ext.images.editor.size":"Size","ext.images.editor.width":"Width (m)","ext.images.editor.depth":"Depth (m)","ext.images.editor.rotation":"Rotation (°)","ext.images.editor.blend":"Blend","ext.images.editor.blend.normal":"Normal","ext.images.editor.blend.multiply":"Multiply","ext.images.editor.image":"Image","ext.images.editor.replace":"Replace image","ext.images.editor.uploading":"Uploading…","ext.images.editor.failed":"Failed to upload image","ext.images.scale.title":"Scale reference","ext.images.scale.hint":"Optional","ext.images.scale.desc":"Drag to draw a line on the image, then enter its real-world length to scale the entire image.","ext.images.scale.distance":"Reference length","ext.images.scale.distance_placeholder":"e.g. 2.4","ext.images.scale.unit":"Unit","ext.images.scale.pixel_distance":"Line length","ext.images.scale.clear":"Clear","ext.images.scale.apply":"Apply scale","ext.images.scale.result":"Result: {{w}} m × {{d}} m ({{mpp}} m/px)","ext.images.units.m":"m","ext.images.units.cm":"cm","ext.images.units.mm":"mm","ext.images.units.ft":"ft","ext.images.units.in":"in"},"pt-BR":{"ext.images.element.name":"Imagem","ext.images.element.desc":"Imagem importada no chão como sobreposição ou referência (decalque).","ext.images.tool.add_overlay":"Imagem (sobreposição)","ext.images.tool.add_overlay_desc":"Clique para enviar e posicionar uma imagem de sobreposição no chão.","ext.images.tool.add_tracing":"Imagem (decalque)","ext.images.tool.add_tracing_desc":"Clique para enviar e posicionar uma imagem de referência (decalque) no chão.","ext.images.editor.title":"Imagem","ext.images.editor.mode":"Modo","ext.images.editor.mode.overlay":"Sobreposição","ext.images.editor.mode.tracing":"Decalque","ext.images.editor.opacity":"Opacidade","ext.images.editor.size":"Tamanho","ext.images.editor.width":"Largura (m)","ext.images.editor.depth":"Profundidade (m)","ext.images.editor.rotation":"Rotação (°)","ext.images.editor.blend":"Mistura","ext.images.editor.blend.normal":"Normal","ext.images.editor.blend.multiply":"Multiplicar","ext.images.editor.image":"Imagem","ext.images.editor.replace":"Substituir imagem","ext.images.editor.uploading":"Enviando…","ext.images.editor.failed":"Falha ao enviar imagem","ext.images.scale.title":"Referência de escala","ext.images.scale.hint":"Opcional","ext.images.scale.desc":"Arraste para desenhar uma reta na imagem e informe o tamanho real dessa distância para escalar a imagem inteira.","ext.images.scale.distance":"Distância de referência","ext.images.scale.distance_placeholder":"ex.: 2,4","ext.images.scale.unit":"Unidade","ext.images.scale.pixel_distance":"Comprimento da reta","ext.images.scale.clear":"Limpar","ext.images.scale.apply":"Aplicar escala","ext.images.scale.result":"Resultado: {{w}} m × {{d}} m ({{mpp}} m/px)","ext.images.units.m":"m","ext.images.units.cm":"cm","ext.images.units.mm":"mm","ext.images.units.ft":"ft","ext.images.units.in":"in"}}},703(e,t,i){i.r(t),i.d(t,{activate:()=>r});var a=i(171),n=i(857),l=i(746),s=i(416);function r(e){e.i18n.registerTranslations(s.F),e.registerElementType((0,n._)(e.i18n)),e.registerEditorTool((0,l.$)(e.i18n)),e.registerEditorTool((0,l.l)(e.i18n)),e.registerFileDropHandler((0,a.F)(e.i18n))}},746(e,t,i){i.d(t,{$:()=>o,l:()=>d});var a=i(840),n=i(87),l=i(381),s=i(202);function r(e,t){return{id:"tracing"===t?n.w2:n.s9,name:{key:"tracing"===t?"ext.images.tool.add_tracing":"ext.images.tool.add_overlay",fallback:"tracing"===t?"Tracing image":"Overlay image"},description:{key:"tracing"===t?"ext.images.tool.add_tracing_desc":"ext.images.tool.add_overlay_desc"},icon:"tracing"===t?"layer-group":"image",createSession:({createElement:i,openEditor:r})=>{const o=document.createElement("input");o.type="file",o.multiple=!1,o.accept="image/*",o.style.position="fixed",o.style.left="-9999px",o.style.width="1px",o.style.height="1px",document.body.appendChild(o);let d=null,c=!1,m=null,u="idle",p=null,g=null;const h=e.t;function x(){g?.dispatchEvent(new Event("toposync:invalidate"))}return o.addEventListener("change",()=>{const e=o.files?.[0]??null;o.value="",e&&(async()=>{try{if(!d)throw new Error("No placement point selected");u="uploading",p=null,x();const l=await(0,s.DQ)(e),o=await(0,a.B)(e,{filename:e.name}),c=l&&l.height>0?l.width/l.height:null,m=n.Y,g=c?m/c:m,f="tracing"===t?n.pd:n.Fk,y="tracing"===t?"multiply":"normal",v=i(n.MG,{name:(0,s.jl)(e.name)||h("tracing"===t?"ext.images.editor.mode.tracing":"ext.images.editor.mode.overlay"),position:{x:d.x,y:0,z:d.z},props:{dir:o.dir,file:o.filename,width_m:m,depth_m:g,opacity:f,mode:t,blend:y,pixel_width:l?.width??null,pixel_height:l?.height??null}});v&&r(v),u="idle",d=null,x()}catch(e){u="error",p=e instanceof Error?e.message:String(e),console.error("[images:tool] import failed",e),x()}})()}),{onPointerEvent:e=>{if("cancel"===e.kind)return c=!1,m=null,void(d=null);if("down"===e.kind){if(0!==e.button)return;if("idle"!==u)return;return d={x:e.world.x,z:e.world.z},c=!0,m={x:e.screen.x,y:e.screen.y},void(0,l.c)("[images:tool] pointer down",{world:e.world,screen:e.screen})}if("move"===e.kind){if(!c||!m)return;const t=e.screen.x-m.x,i=e.screen.y-m.y;return void(t*t+i*i>16&&(c=!1,m=null))}if("up"===e.kind){if(!c)return;if(c=!1,m=null,0!==e.button)return;if("idle"!==u)return;if(!d)return;(0,l.c)("[images:tool] open picker",{pendingPlacementPoint:d}),o.click()}},onKeyDown:e=>{"Escape"===e.key&&(d=null,c=!1,m=null,u="idle",p=null,x())},renderOverlay2D:({ctx:e,viewport:t})=>{g=t.canvas;const i="uploading"===u?h("ext.images.editor.uploading"):"error"===u?`${h("ext.images.editor.failed")}${p?`: ${p}`:""}`:null;if(!i)return;e.save(),e.font="12px ui-sans-serif, system-ui",e.textBaseline="top";const a=t.width,n=e.measureText(i).width,l=Math.min(a-24,n+20),s=(a-l)/2;e.fillStyle="rgba(8,12,26,0.82)",e.strokeStyle="rgba(255,255,255,0.14)",e.lineWidth=1,function(e,t,i,a,n){const l=Math.max(0,Math.min(10,Math.min(a,n)/2));e.beginPath(),e.moveTo(t+l,i),e.lineTo(t+a-l,i),e.quadraticCurveTo(t+a,i,t+a,i+l),e.lineTo(t+a,42-l),e.quadraticCurveTo(t+a,42,t+a-l,42),e.lineTo(t+l,42),e.quadraticCurveTo(t,42,t,42-l),e.lineTo(t,i+l),e.quadraticCurveTo(t,i,t+l,i),e.closePath(),e.fill(),e.stroke()}(e,s,14,l,28),e.fillStyle="rgba(230,232,242,0.92)",e.fillText(i,s+10,22),e.restore()},getCursor:()=>"idle"===u?"copy":"wait",dispose:()=>{(0,l.c)("[images:tool] disposed"),o.remove()}}}}}function o(e){return r(e,"overlay")}function d(e){return r(e,"tracing")}},823(e,t,i){i.d(t,{O:()=>m});var a=i(870),n=i(496),l=i(912),s=i(840),r=i(87),o=i(322),d=i(202),c=i(900);function m({element:e,update:t,remove:i,close:m,i18n:u}){const{t:p,locale:g}=u.useI18n(),h=(0,n.useMemo)(()=>new Intl.NumberFormat(g,{maximumFractionDigits:2}),[g]),x=(0,n.useRef)(null),[f,y]=(0,n.useState)({status:"idle"}),v=e.props,b=(0,o.E3)(v.dir,""),w=(0,o.E3)(v.file,""),N=(0,o.Zi)(v.mode,"overlay"),_="tracing"===N?"multiply":"normal",j=(0,o.kz)(v.width_m,r.Y),k=(0,o.kz)(v.depth_m,r.Y),M=(0,o.qE)((0,o.kz)(v.opacity,"tracing"===N?.55:1),0,1),C=(0,o.Vl)(v.blend,_),E=(0,n.useMemo)(()=>180*e.rotation.y/Math.PI,[e.rotation.y]),F=b&&w?(0,l.resolveToposyncUrl)(`/files/${encodeURIComponent(b)}/${encodeURIComponent(w)}`):"",T=(0,o.kz)(v.pixel_width,NaN),R=(0,o.kz)(v.pixel_height,NaN),W=(0,n.useCallback)(()=>{x.current?.click()},[]);return(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"card",children:[(0,a.jsxs)("div",{className:"cardHeaderRow",children:[(0,a.jsx)("div",{className:"cardTitle",children:p("ext.images.editor.title")}),(0,a.jsxs)("div",{className:"cardMeta",children:["y=",h.format(r.cR),"m"]})]}),(0,a.jsx)("div",{className:"cardBody",children:p("ext.images.element.desc")})]}),(0,a.jsx)("div",{className:"sectionDivider"}),(0,a.jsxs)("div",{className:"field",children:[(0,a.jsx)("div",{className:"label",children:p("core.element_editor.name")}),(0,a.jsx)("input",{className:"input",value:e.name,onChange:e=>t({name:e.target.value})})]}),(0,a.jsxs)("div",{className:"rowWrap",children:[(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.mode")}),(0,a.jsxs)("select",{className:"input",value:N,onChange:e=>{const i=(0,o.Zi)(e.target.value,N);t({props:{mode:i,opacity:"tracing"===i?.55:1,blend:"tracing"===i?"multiply":"normal"}})},children:[(0,a.jsx)("option",{value:"overlay",children:p("ext.images.editor.mode.overlay")}),(0,a.jsx)("option",{value:"tracing",children:p("ext.images.editor.mode.tracing")})]})]}),(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.opacity")}),(0,a.jsx)("input",{className:"input",type:"range",min:0,max:100,step:1,value:Math.round(100*M),onChange:e=>t({props:{opacity:(0,o.qE)(Number(e.target.value)/100,0,1)}})}),(0,a.jsxs)("div",{className:"hint",children:[Math.round(100*M),"%"]})]})]}),(0,a.jsxs)("div",{className:"rowWrap",children:[(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.width")}),(0,a.jsx)("input",{className:"input",type:"number",inputMode:"decimal",min:.05,max:200,step:.05,value:Number.isFinite(j)?j:r.Y,onChange:e=>{const i=Number.parseFloat(e.target.value);Number.isFinite(i)&&t({props:{width_m:(0,o.qE)(i,.05,200)}})}})]}),(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.depth")}),(0,a.jsx)("input",{className:"input",type:"number",inputMode:"decimal",min:.05,max:200,step:.05,value:Number.isFinite(k)?k:r.Y,onChange:e=>{const i=Number.parseFloat(e.target.value);Number.isFinite(i)&&t({props:{depth_m:(0,o.qE)(i,.05,200)}})}})]})]}),(0,a.jsxs)("div",{className:"rowWrap",children:[(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.rotation")}),(0,a.jsx)("input",{className:"input",type:"number",inputMode:"decimal",step:1,value:Number.isFinite(E)?E:0,onChange:e=>{const i=Number.parseFloat(e.target.value);Number.isFinite(i)&&t({rotation:{y:i*Math.PI/180}})}})]}),(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:160},children:[(0,a.jsx)("div",{className:"label",children:p("ext.images.editor.blend")}),(0,a.jsxs)("select",{className:"input",value:C,onChange:e=>t({props:{blend:(0,o.Vl)(e.target.value,C)}}),children:[(0,a.jsx)("option",{value:"normal",children:p("ext.images.editor.blend.normal")}),(0,a.jsx)("option",{value:"multiply",children:p("ext.images.editor.blend.multiply")})]})]})]}),(0,a.jsx)("div",{className:"rowWrap",children:(0,a.jsx)("button",{className:"chipButton",type:"button",onClick:W,disabled:"uploading"===f.status,children:"uploading"===f.status?p("ext.images.editor.uploading"):p("ext.images.editor.replace")})}),F?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"sectionDivider"}),(0,a.jsx)(c.f,{t:p,locale:g,imageUrl:F,pixelWidth:Number.isFinite(T)?T:null,pixelHeight:Number.isFinite(R)?R:null,scaleRef:v.scale_ref,onApply:e=>t({props:e})})]}):null,"error"===f.status?(0,a.jsx)("div",{className:"card",style:{borderColor:"rgba(248,113,113,0.35)"},children:(0,a.jsxs)("div",{className:"cardBody",children:[p("ext.images.editor.failed"),f.message?`: ${f.message}`:""]})}):null,(0,a.jsx)("input",{ref:x,type:"file",accept:"image/*",style:{position:"fixed",left:"-9999px",width:1,height:1},onChange:i=>{const a=i.target.files?.[0]??null;a&&(i.target.value="",(async()=>{y({status:"uploading"});try{const i=await(0,d.DQ)(a),n=await(0,s.B)(a,{filename:a.name}),l=e.name||(0,d.jl)(a.name)||e.name,r={dir:n.dir,file:n.filename};if(i){r.pixel_width=i.width,r.pixel_height=i.height;const e=i.width>0?i.width/Math.max(1,i.height):null;e&&Number.isFinite(e)&&(r.depth_m=(0,o.qE)(j/e,.05,200))}t({name:l,props:r}),y({status:"idle"})}catch(e){y({status:"error",message:e instanceof Error?e.message:String(e)})}})())}}),(0,a.jsx)("div",{className:"sectionDivider"}),(0,a.jsxs)("div",{className:"rowWrap",children:[(0,a.jsx)("button",{className:"dangerButton",type:"button",onClick:i,children:p("core.actions.delete")}),(0,a.jsx)("button",{className:"chipButton",type:"button",onClick:m,children:p("core.actions.close")})]})]})}},840(e,t,i){i.d(t,{B:()=>l});var a=i(912),n=i(381);async function l(e,t){const i=new FormData;i.append("file",e,t.filename),t.dir&&i.append("dir",t.dir),i.append("filename",t.filename),(0,n.c)("[images] POST /api/files/upload",{dir:t.dir??null,filename:t.filename,size:e.size});const l=await fetch("/api/files/upload",{method:"POST",body:i});if((0,n.c)("[images] upload response",{status:l.status,ok:l.ok}),!l.ok)throw new Error(`Upload failed: ${l.status}`);const s=await l.json();return{...s,url:(0,a.resolveToposyncUrl)(s.url)}}},857(e,t,i){i.d(t,{_:()=>c});var a=i(870),n=(i(496),i(912)),l=i(87),s=i(322),r=i(823);function o(e){return(0,n.resolveToposyncUrl)(`/files/${encodeURIComponent(e.dir)}/${encodeURIComponent(e.file)}`)}function d(e){const t=(0,s.E3)(e.dir,""),i=(0,s.E3)(e.file,""),a=(0,s.Zi)(e.mode,"overlay"),n="tracing"===a?l.pd:l.Fk,r=(0,s.kz)(e.width_m,l.Y),o=(0,s.kz)(e.depth_m,l.Y),d=(0,s.qE)((0,s.kz)(e.opacity,n),0,1),c="tracing"===a?"multiply":"normal",m=(0,s.Vl)(e.blend,c),u=(0,s.kz)(e.pixel_width,NaN),p=(0,s.kz)(e.pixel_height,NaN);return{dir:t,file:i,width_m:(0,s.qE)(r,.05,200),depth_m:(0,s.qE)(o,.05,200),opacity:d,mode:a,blend:m,pixel_width:Number.isFinite(u)?u:void 0,pixel_height:Number.isFinite(p)?p:void 0}}function c(e){const t=new Map;return{type:l.MG,layerGroup:"background",placeable:!1,name:{key:"ext.images.element.name",fallback:"Image"},description:{key:"ext.images.element.desc"},defaultProps:{dir:"",file:"",width_m:l.Y,depth_m:l.Y,opacity:l.Fk,mode:"overlay",blend:"normal",pixel_width:null,pixel_height:null},create3D:({THREE:e},t)=>{const i=new e.Group,a=new e.PlaneGeometry(1,1,1,1);a.rotateX(-Math.PI/2);const n=new e.MeshBasicMaterial({color:16777215,transparent:!0,opacity:1,depthWrite:!1,polygonOffset:!0,polygonOffsetFactor:-1,polygonOffsetUnits:-1}),s=new e.Mesh(a,n);s.position.y=l.cR,s.raycast=()=>{},i.add(s);const r=new e.TextureLoader;let c=null,m="",u=!1,p=0;function g(t){const i=d(t.props);s.scale.set(i.width_m,1,i.depth_m);const a=Boolean(i.dir&&i.file),l=a&&"overlay"===i.mode;if(s.visible=l,!l)return m="",p++,c&&(c.dispose(),c=null),void(n.map&&(n.map=null,n.needsUpdate=!0));const g="tracing"===i.mode&&"multiply"===i.blend?e.MultiplyBlending:e.NormalBlending,h=i.opacity<.999,x=a||h||g!==e.NormalBlending,f=n.blending!==g||n.transparent!==x;n.blending=g,n.transparent=x,n.opacity=i.opacity,f&&(n.needsUpdate=!0);const y=o(i);y!==m&&(m=y,async function(t){const i=++p;try{const a=await r.loadAsync(t);if(u||i!==p)return void a.dispose();a.colorSpace=e.SRGBColorSpace,c&&c.dispose(),c=a,n.map=a,n.needsUpdate=!0}catch(e){console.warn("[images:create3D] texture load failed",e)}}(y))}return g(t),{object:i,update:g,dispose:()=>{u=!0,c&&c.dispose(),a.dispose(),n.dispose()}}},render2D:({ctx:e,element:i,viewport:a})=>{const n=d(i.props),l=a.worldToScreen({x:i.position.x,z:i.position.z}),r=Math.max(20,n.width_m*a.scale),c=Math.max(20,n.depth_m*a.scale),m=(0,s.kz)(i.rotation.y,0),u=n.dir&&n.file?o(n):"",p=u&&(()=>{const e=t.get(u)??null;if(e)return e;const i=new Image;return i.decoding="async",i.onload=()=>a.canvas.dispatchEvent(new Event("toposync:invalidate")),i.onerror=()=>a.canvas.dispatchEvent(new Event("toposync:invalidate")),i.src=u,t.set(u,i),i})();e.save(),e.translate(l.x,l.y),e.rotate(-m),"multiply"===n.blend&&(e.globalCompositeOperation="multiply"),e.globalAlpha=n.opacity,p&&p.complete&&p.naturalWidth>0?e.drawImage(p,-r/2,-c/2,r,c):(e.fillStyle="rgba(56,189,248,0.10)",e.fillRect(-r/2,-c/2,r,c)),e.globalCompositeOperation="source-over",e.globalAlpha=1,e.strokeStyle="rgba(230,232,242,0.22)",e.lineWidth=2,e.strokeRect(-r/2,-c/2,r,c),e.restore()},hitTest2D:({element:e,world:t})=>{const i=d(e.props),a=(0,s.kz)(e.rotation.y,0),n=t.x-e.position.x,l=t.z-e.position.z,r=Math.cos(a),o=Math.sin(a),c=n*r-l*o,m=n*o+l*r;return Math.abs(c)<=i.width_m/2&&Math.abs(m)<=i.depth_m/2},translate2D:({element:e,delta:t})=>({id:e.id,position:{x:e.position.x+t.x,z:e.position.z+t.z}}),renderEditorModal:({element:t,update:i,remove:n,close:l})=>(0,a.jsx)(r.O,{element:t,update:i,remove:n,close:l,i18n:e})}}},870(e,t,i){e.exports=i(94)},900(e,t,i){i.d(t,{f:()=>m});var a=i(870),n=i(496),l=i(322);const s={m:1,cm:.01,mm:.001,ft:.3048,in:.0254},r="toposync.images.scaleUnit";function o(e){return"number"==typeof e&&Number.isFinite(e)}function d(e,t){return"m"===e||"cm"===e||"mm"===e||"ft"===e||"in"===e?e:t}function c(e){return e.startsWith("en-US")?"ft":"m"}function m({t:e,locale:t,imageUrl:i,pixelWidth:m,pixelHeight:u,scaleRef:p,onApply:g}){const h=(0,n.useMemo)(()=>function(e){if(t=e,!Boolean(t)||"object"!=typeof t||Array.isArray(t))return{line:null,value:null,unit:null};var t;const i=e.ax,a=e.ay,n=e.bx,l=e.by,s=e.value,r=e.unit;return{line:o(i)&&o(a)&&o(n)&&o(l)&&i>=0&&i<=1&&a>=0&&a<=1&&n>=0&&n<=1&&l>=0&&l<=1?{a:{x:i,y:a},b:{x:n,y:l}}:null,value:o(s)?s:null,unit:d(r,"m")}}(p),[p]),[x,f]=(0,n.useState)(()=>h.unit??function(e){try{return d(localStorage.getItem(r),c(e))}catch{return c(e)}}(t)),[y,v]=(0,n.useState)(()=>h.value&&Number.isFinite(h.value)?String(h.value):""),[b,w]=(0,n.useState)(()=>h.line),[N,_]=(0,n.useState)(!1),[j,k]=(0,n.useState)(null),M=(0,n.useRef)(null),C=(0,n.useRef)(null),E=(0,n.useMemo)(()=>new Intl.NumberFormat(t,{minimumFractionDigits:2,maximumFractionDigits:2}),[t]),F=(0,n.useCallback)(()=>{const e=M.current,t=C.current;if(!e||!t)return;const i=e.getBoundingClientRect(),a=window.devicePixelRatio||1,n=Math.max(1,Math.floor(i.width*a)),l=Math.max(1,Math.floor(i.height*a));t.width===n&&t.height===l||(t.width=n,t.height=l);const s=t.getContext("2d");if(!s)return;if(s.setTransform(a,0,0,a,0,0),s.clearRect(0,0,i.width,i.height),!b)return;const r={x:b.a.x*i.width,y:b.a.y*i.height},o={x:b.b.x*i.width,y:b.b.y*i.height};s.lineWidth=2,s.strokeStyle="rgba(251,191,36,0.92)",s.shadowColor="rgba(251,191,36,0.25)",s.shadowBlur=10,s.beginPath(),s.moveTo(r.x,r.y),s.lineTo(o.x,o.y),s.stroke(),s.shadowBlur=0,s.fillStyle="rgba(251,191,36,0.92)",s.strokeStyle="rgba(0,0,0,0.55)",s.lineWidth=1.5;for(const e of[r,o])s.beginPath(),s.arc(e.x,e.y,6,0,2*Math.PI),s.fill(),s.stroke()},[b]);(0,n.useEffect)(()=>{const e=M.current;if(!e)return;const t=new ResizeObserver(()=>F());return t.observe(e),F(),()=>t.disconnect()},[F]),(0,n.useEffect)(()=>{F()},[F,b,N]),(0,n.useEffect)(()=>{j&&(Number.isFinite(m)&&Number.isFinite(u)||g({pixel_width:j.width,pixel_height:j.height}))},[j,g,u,m]);const T=(0,n.useMemo)(()=>{if(!b)return null;const e=j?.width??(Number.isFinite(m)?m:null),t=j?.height??(Number.isFinite(u)?u:null);if(!e||!t)return null;const i=b.a.x*e,a=b.a.y*t,n=b.b.x*e,l=b.b.y*t,s=Math.hypot(i-n,a-l);return s>=1?s:null},[b,j,u,m]),R=(0,n.useMemo)(()=>function(e){const t=e.trim();if(!t)return null;const i=t.replace(/\s+/g,"").replace(",","."),a=Number.parseFloat(i);return Number.isFinite(a)?a:null}(y),[y]),W=(0,n.useMemo)(()=>{const e=j?.width??(Number.isFinite(m)?m:null),t=j?.height??(Number.isFinite(u)?u:null);if(!e||!t)return null;if(!T||!R||R<=0)return null;const i=R*s[x],a=i/T;return{metersPerPixel:a,widthMeters:e*a,depthMeters:t*a,lengthMeters:i,pixelWidth:e,pixelHeight:t}},[R,j,T,u,m,x]),S=(0,n.useCallback)(()=>{b&&W&&g({width_m:(0,l.qE)(W.widthMeters,.05,200),depth_m:(0,l.qE)(W.depthMeters,.05,200),pixel_width:W.pixelWidth,pixel_height:W.pixelHeight,scale_ref:{ax:b.a.x,ay:b.a.y,bx:b.b.x,by:b.b.y,value:R,unit:x}})},[W,R,b,g,x]),I=(0,n.useCallback)(()=>{w(null),g({scale_ref:null})},[g]);return(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{className:"rowWrap",style:{alignItems:"baseline",justifyContent:"space-between"},children:[(0,a.jsx)("div",{className:"label",children:e("ext.images.scale.title")}),(0,a.jsx)("div",{className:"hint",children:e("ext.images.scale.hint")})]}),(0,a.jsx)("div",{className:"hint",style:{marginTop:6,marginBottom:10},children:e("ext.images.scale.desc")}),(0,a.jsxs)("div",{ref:M,style:{position:"relative",width:"100%",aspectRatio:j?`${j.width} / ${j.height}`:"16 / 10",borderRadius:12,overflow:"hidden",border:"1px solid rgba(255,255,255,0.10)",background:"rgba(255,255,255,0.04)"},children:[(0,a.jsx)("img",{src:i,alt:e("ext.images.editor.image"),style:{width:"100%",height:"100%",objectFit:"contain",display:"block"},onLoad:e=>{const t=e.currentTarget;t.naturalWidth&&t.naturalHeight&&k({width:t.naturalWidth,height:t.naturalHeight})}}),(0,a.jsx)("canvas",{ref:C,style:{position:"absolute",inset:0,width:"100%",height:"100%",touchAction:"none",cursor:"crosshair"},onPointerDown:e=>{const t=M.current;if(!t)return;const i=t.getBoundingClientRect(),a=(e.clientX-i.left)/i.width,n=(e.clientY-i.top)/i.height,s={x:(0,l.qE)(a,0,1),y:(0,l.qE)(n,0,1)};w({a:s,b:s}),_(!0),e.currentTarget.setPointerCapture(e.pointerId)},onPointerMove:e=>{if(!N)return;const t=M.current;if(!t)return;const i=t.getBoundingClientRect(),a=(e.clientX-i.left)/i.width,n=(e.clientY-i.top)/i.height;w(e=>e?{...e,b:{x:(0,l.qE)(a,0,1),y:(0,l.qE)(n,0,1)}}:e)},onPointerUp:e=>{_(!1);try{e.currentTarget.releasePointerCapture(e.pointerId)}catch{}},onPointerCancel:()=>_(!1)})]}),(0,a.jsxs)("div",{className:"rowWrap",style:{marginTop:10},children:[(0,a.jsxs)("div",{className:"field",style:{flex:1,minWidth:180},children:[(0,a.jsx)("div",{className:"label",children:e("ext.images.scale.distance")}),(0,a.jsx)("input",{className:"input",inputMode:"decimal",value:y,placeholder:e("ext.images.scale.distance_placeholder"),onChange:e=>v(e.target.value)})]}),(0,a.jsxs)("div",{className:"field",style:{width:120,minWidth:120},children:[(0,a.jsx)("div",{className:"label",children:e("ext.images.scale.unit")}),(0,a.jsxs)("select",{className:"input",value:x,onChange:e=>{const t=d(e.target.value,x);f(t),function(e){try{localStorage.setItem(r,e)}catch{}}(t)},children:[(0,a.jsx)("option",{value:"m",children:e("ext.images.units.m")}),(0,a.jsx)("option",{value:"cm",children:e("ext.images.units.cm")}),(0,a.jsx)("option",{value:"mm",children:e("ext.images.units.mm")}),(0,a.jsx)("option",{value:"ft",children:e("ext.images.units.ft")}),(0,a.jsx)("option",{value:"in",children:e("ext.images.units.in")})]})]})]}),(0,a.jsxs)("div",{className:"rowWrap",style:{alignItems:"baseline",justifyContent:"space-between"},children:[(0,a.jsx)("div",{className:"hint",children:T?`${e("ext.images.scale.pixel_distance")}: ${E.format(T)} px`:null}),(0,a.jsxs)("div",{className:"rowWrap",style:{justifyContent:"flex-end"},children:[(0,a.jsx)("button",{className:"chipButton",type:"button",onClick:I,disabled:!b,children:e("ext.images.scale.clear")}),(0,a.jsx)("button",{className:"primaryButton",type:"button",onClick:S,disabled:!W||!b,children:e("ext.images.scale.apply")})]})]}),W?(0,a.jsx)("div",{className:"card",style:{marginTop:10},children:(0,a.jsx)("div",{className:"cardBody",children:e("ext.images.scale.result",{w:E.format(W.widthMeters),d:E.format(W.depthMeters),mpp:E.format(W.metersPerPixel)})})}):null]})}}}]);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! For license information please see main.js.LICENSE.txt */
|
|
2
|
+
(()=>{"use strict";var e,r,t={65(e,r,t){t(912),(()=>{try{return"1"===localStorage.getItem("toposync.images.debug")}catch{return!1}})(),t(870),t(496)},94(e,r,t){var n=t(496);Symbol.for("react.element"),Symbol.for("react.fragment"),Object.prototype.hasOwnProperty,n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner},870(e,r,t){t(94)}},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={exports:{}};return t[e](a,a.exports,o),a.exports}o.m=t,o.c=n,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((r,t)=>(o.f[t](e,r),r),[])),o.u=e=>e+".js",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="@toposync/extension-images-ui:",o.l=(t,n,a,i)=>{if(e[t])e[t].push(n);else{var u,s;if(void 0!==a)for(var l=document.getElementsByTagName("script"),p=0;p<l.length;p++){var c=l[p];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==r+a){u=c;break}}u||(s=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",r+a),u.src=t),e[t]=[n];var f=(r,n)=>{u.onerror=u.onload=null,clearTimeout(h);var o=e[t];if(delete e[t],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),r)return r(n)},h=setTimeout(f.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=f.bind(null,u.onerror),u.onload=f.bind(null,u.onload),s&&document.head.appendChild(u)}},(()=>{o.S={};var e={},r={};o.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];o.o(o.S,t)||(o.S[t]={});var i=o.S[t],u="@toposync/extension-images-ui",s=(e,r,t,n)=>{var o=i[e]=i[e]||{},a=o[r];(!a||!a.loaded&&(!n!=!a.eager?n:u>a.from))&&(o[r]={get:t,from:u,eager:!!n})},l=[];return"default"===t&&(s("@toposync/plugin-api","0.3.0",()=>o.e(387).then(()=>()=>o(387))),s("react","18.3.1",()=>o.e(326).then(()=>()=>o(326)))),e[t]=l.length?Promise.all(l).then(()=>e[t]=1):1}}})(),(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var r=o.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},r=e=>{var t=e[0],n="";if(1===e.length)return"*";if(t+.5){n+=0==t?">=":-1==t?"<":1==t?"^":2==t?"~":t>0?"=":"!=";for(var o=1,a=1;a<e.length;a++)o--,n+="u"==(typeof(u=e[a]))[0]?"-":(o>0?".":"")+(o=2,u);return n}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+s()+")":1===u?"("+s()+" || "+s()+")":2===u?i.pop()+" "+i.pop():r(u))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},t=(r,n)=>{if(0 in r){n=e(n);var o=r[0],a=o<0;a&&(o=-o-1);for(var i=0,u=1,s=!0;;u++,i++){var l,p,c=u<r.length?(typeof r[u])[0]:"";if(i>=n.length||"o"==(p=(typeof(l=n[i]))[0]))return!s||("u"==c?u>o&&!a:""==c!=a);if("u"==p){if(!s||"u"!=c)return!1}else if(s)if(c==p)if(u<=o){if(l!=r[u])return!1}else{if(a?l>r[u]:l<r[u])return!1;l!=r[u]&&(s=!1)}else if("s"!=c&&"n"!=c){if(a||u<=o)return!1;s=!1,u--}else{if(u<=o||p<c!=a)return!1;s=!1}else"s"!=c&&"n"!=c&&(s=!1,u--)}}var f=[],h=f.pop.bind(f);for(i=1;i<r.length;i++){var d=r[i];f.push(1==d?h()|h():2==d?h()&h():d?t(d,n):!h())}return!!h()},n=(e,r)=>e&&o.o(e,r),a=e=>(e.loaded=1,e.get()),i=(r,t,n)=>{var o=n?(e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}))(r[t]):r[t];return Object.keys(o).reduce((r,t)=>!r||!o[r].loaded&&((r,t)=>{r=e(r),t=e(t);for(var n=0;;){if(n>=r.length)return n<t.length&&"u"!=(typeof t[n])[0];var o=r[n],a=(typeof o)[0];if(n>=t.length)return"u"==a;var i=t[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}})(r,t)?t:r,0)},u=e=>function(r,t,n,a,i){var u=o.I(r);return u&&u.then&&!n?u.then(e.bind(e,r,o.S[r],t,!1,a,i)):e(r,o.S[r],t,n,a,i)},s=(e,r,t)=>t?t():((e,r)=>(e=>{throw new Error(e)})("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),l=u((e,r,t,o,u)=>{if(!n(r,t))return s(e,t,u);var l=i(r,t,o);return a(r[t][l])}),p=u((e,o,u,l,p,c)=>{if(!n(o,u))return s(e,u,c);var f,h=i(o,u,l);return t(p,h)||(f=((e,t,n,o)=>"Unsatisfied version "+n+" from "+(n&&e[t][n].from)+" of shared singleton module "+t+" (required "+r(o)+")")(o,u,h,p),"undefined"!=typeof console&&console.warn&&console.warn(f)),a(o[u][h])}),c={},f={912:()=>p("default","@toposync/plugin-api",!1,[2,0,3,0],()=>o.e(387).then(()=>()=>o(387))),496:()=>l("default","react",!1,()=>o.e(326).then(()=>()=>o(326)))};[912,496].forEach(e=>{o.m[e]=r=>{c[e]=0,delete o.c[e];var t=f[e]();if("function"!=typeof t)throw new Error("Shared module is not available for eager consumption: "+e);r.exports=t()}});var h={792:[912,496]},d={};o.f.consumes=(e,r)=>{o.o(h,e)&&h[e].forEach(e=>{if(o.o(c,e))return r.push(c[e]);if(!d[e]){var t=r=>{c[e]=0,o.m[e]=t=>{delete o.c[e],t.exports=r()}};d[e]=!0;var n=r=>{delete c[e],o.m[e]=t=>{throw delete o.c[e],r}};try{var a=f[e]();a.then?r.push(c[e]=a.then(t).catch(n)):t(a)}catch(e){n(e)}}})}})(),(()=>{var e={792:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=a);var i=o.p+o.u(r),u=new Error;o.l(i,t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;u.message="Loading chunk "+r+" failed.\n("+a+": "+i+")",u.name="ChunkLoadError",u.type=a,u.request=i,n[1](u)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[i,u,s]=t,l=0;if(i.some(r=>0!==e[r])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);s&&s(o)}for(r&&r(t);l<i.length;l++)a=i[l],o.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunk_toposync_extension_images_ui=self.webpackChunk_toposync_extension_images_ui||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o(65)})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var images;(()=>{"use strict";var e,r,t,n,o,a,i,u,s,l,f,p,c,d,h,v,g,m,y,b,w,S={863(e,r,t){var n={"./activate":()=>t.e(703).then(()=>()=>t(703))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},k={};function x(e){var r=k[e];if(void 0!==r)return r.exports;var t=k[e]={exports:{}};return S[e](t,t.exports,x),t.exports}x.m=S,x.c=k,x.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return x.d(r,{a:r}),r},x.d=(e,r)=>{for(var t in r)x.o(r,t)&&!x.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},x.f={},x.e=e=>Promise.all(Object.keys(x.f).reduce((r,t)=>(x.f[t](e,r),r),[])),x.u=e=>e+".js",x.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),x.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="@toposync/extension-images-ui:",x.l=(t,n,o,a)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==o)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var f=s[l];if(f.getAttribute("src")==t||f.getAttribute("data-webpack")==r+o){i=f;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",x.nc&&i.setAttribute("nonce",x.nc),i.setAttribute("data-webpack",r+o),i.src=t),e[t]=[n];var p=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var o=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(e=>e(n)),r)return r(n)},c=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),u&&document.head.appendChild(i)}},x.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{x.S={};var e={},r={};x.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];x.o(x.S,t)||(x.S[t]={});var a=x.S[t],i="@toposync/extension-images-ui",u=(e,r,t,n)=>{var o=a[e]=a[e]||{},u=o[r];(!u||!u.loaded&&(!n!=!u.eager?n:i>u.from))&&(o[r]={get:t,from:i,eager:!!n})},s=[];return"default"===t&&(u("@toposync/plugin-api","0.3.0",()=>x.e(387).then(()=>()=>x(387))),u("react","18.3.1",()=>x.e(326).then(()=>()=>x(326)))),e[t]=s.length?Promise.all(s).then(()=>e[t]=1):1}}})(),(()=>{var e;x.g.importScripts&&(e=x.g.location+"");var r=x.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),x.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],a=(typeof o)[0];if(n>=r.length)return"u"==a;var i=r[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,a=1;a<e.length;a++)n--,t+="u"==(typeof(u=e[a]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+s()+")":1===u?"("+s()+" || "+s()+")":2===u?i.pop()+" "+i.pop():o(u))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var i=0,u=1,s=!0;;u++,i++){var l,f,p=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(f=(typeof(l=r[i]))[0]))return!s||("u"==p?u>n&&!o:""==p!=o);if("u"==f){if(!s||"u"!=p)return!1}else if(s)if(p==f)if(u<=n){if(l!=e[u])return!1}else{if(o?l>e[u]:l<e[u])return!1;l!=e[u]&&(s=!1)}else if("s"!=p&&"n"!=p){if(o||u<=n)return!1;s=!1,u--}else{if(u<=n||f<p!=o)return!1;s=!1}else"s"!=p&&"n"!=p&&(s=!1,u--)}}var c=[],d=c.pop.bind(c);for(i=1;i<e.length;i++){var h=e[i];c.push(1==h?d()|d():2==h?d()&d():h?a(h,r):!d())}return!!d()},i=(e,r)=>e&&x.o(e,r),u=e=>(e.loaded=1,e.get()),s=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),l=(e,r,t)=>{var o=t?s(e[r]):e[r];return Object.keys(o).reduce((e,r)=>!e||!o[e].loaded&&n(e,r)?r:e,0)},f=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+o(n)+")",p=e=>{throw new Error(e)},c=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},h=(e,r,t)=>t?t():((e,r)=>p("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(d=e=>function(r,t,n,o,a){var i=x.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,x.S[r],t,!1,o,a)):e(r,x.S[r],t,n,o,a)})((e,r,t,n,o)=>{if(!i(r,t))return h(e,t,o);var a=l(r,t,n);return u(r[t][a])}),g=d((e,r,t,n,o,s)=>{if(!i(r,t))return h(e,t,s);var p=l(r,t,n);return a(o,p)||c(f(r,t,p,o)),u(r[t][p])}),m={},y={912:()=>g("default","@toposync/plugin-api",!1,[2,0,3,0],()=>x.e(387).then(()=>()=>x(387))),496:()=>v("default","react",!1,()=>x.e(326).then(()=>()=>x(326)))},b={703:[912,496]},w={},x.f.consumes=(e,r)=>{x.o(b,e)&&b[e].forEach(e=>{if(x.o(m,e))return r.push(m[e]);if(!w[e]){var t=r=>{m[e]=0,x.m[e]=t=>{delete x.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete m[e],x.m[e]=t=>{throw delete x.c[e],r}};try{var o=y[e]();o.then?r.push(m[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})},(()=>{var e={129:0};x.f.j=(r,t)=>{var n=x.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=x.p+x.u(r),i=new Error;x.l(a,t=>{if(x.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,u]=t,s=0;if(a.some(r=>0!==e[r])){for(n in i)x.o(i,n)&&(x.m[n]=i[n]);u&&u(x)}for(r&&r(t);s<a.length;s++)o=a[s],x.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunk_toposync_extension_images_ui=self.webpackChunk_toposync_extension_images_ui||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var E=x(863);images=E})();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@toposync/extension-images-ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "webpack --mode production"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@toposync/plugin-api": "^0.3.0",
|
|
10
|
+
"react": "^18.3.1",
|
|
11
|
+
"react-dom": "^18.3.1",
|
|
12
|
+
"three": "^0.167.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "^18.3.12",
|
|
16
|
+
"@types/three": "^0.167.2",
|
|
17
|
+
"ts-loader": "^9.5.1",
|
|
18
|
+
"typescript": "^5.6.3",
|
|
19
|
+
"webpack": "^5.94.0",
|
|
20
|
+
"webpack-cli": "^5.1.4"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TopoSyncHost } from "@toposync/plugin-api";
|
|
2
|
+
|
|
3
|
+
import { createImageFileDropHandler } from "./dropHandlers/imageDropHandler";
|
|
4
|
+
import { createImageElementType } from "./elements/ImageElementType";
|
|
5
|
+
import { createAddOverlayImageTool, createAddTracingImageTool } from "./tools/addImageTool";
|
|
6
|
+
import { imagesTranslations } from "./translations";
|
|
7
|
+
|
|
8
|
+
export function activate(host: TopoSyncHost): void {
|
|
9
|
+
host.i18n.registerTranslations(imagesTranslations);
|
|
10
|
+
host.registerElementType(createImageElementType(host.i18n));
|
|
11
|
+
host.registerEditorTool(createAddOverlayImageTool(host.i18n));
|
|
12
|
+
host.registerEditorTool(createAddTracingImageTool(host.i18n));
|
|
13
|
+
host.registerFileDropHandler(createImageFileDropHandler(host.i18n));
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { resolveToposyncUrl } from "@toposync/plugin-api";
|
|
2
|
+
import { debugLog } from "../debug";
|
|
3
|
+
import type { UploadFileResponse } from "../types";
|
|
4
|
+
|
|
5
|
+
export async function uploadToFilesDir(
|
|
6
|
+
file: Blob,
|
|
7
|
+
options: { dir?: string; filename: string },
|
|
8
|
+
): Promise<UploadFileResponse> {
|
|
9
|
+
const form = new FormData();
|
|
10
|
+
form.append("file", file, options.filename);
|
|
11
|
+
if (options.dir) form.append("dir", options.dir);
|
|
12
|
+
form.append("filename", options.filename);
|
|
13
|
+
|
|
14
|
+
debugLog("[images] POST /api/files/upload", {
|
|
15
|
+
dir: options.dir ?? null,
|
|
16
|
+
filename: options.filename,
|
|
17
|
+
size: file.size,
|
|
18
|
+
});
|
|
19
|
+
const response = await fetch("/api/files/upload", { method: "POST", body: form });
|
|
20
|
+
debugLog("[images] upload response", { status: response.status, ok: response.ok });
|
|
21
|
+
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
|
|
22
|
+
const data = (await response.json()) as UploadFileResponse;
|
|
23
|
+
return { ...data, url: resolveToposyncUrl(data.url) };
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const IMAGES_EXTENSION_ID = "com.toposync.images";
|
|
2
|
+
export const IMAGE_ELEMENT_TYPE_ID = "com.toposync.images.image";
|
|
3
|
+
|
|
4
|
+
export const ADD_OVERLAY_IMAGE_TOOL_ID = "com.toposync.images.tool.addOverlay";
|
|
5
|
+
export const ADD_TRACING_IMAGE_TOOL_ID = "com.toposync.images.tool.addTracing";
|
|
6
|
+
|
|
7
|
+
export const IMAGES_DEBUG_STORAGE_KEY = "toposync.images.debug";
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_IMAGE_WIDTH_METERS = 4;
|
|
10
|
+
export const DEFAULT_IMAGE_OPACITY_OVERLAY = 1;
|
|
11
|
+
export const DEFAULT_IMAGE_OPACITY_TRACING = 0.55;
|
|
12
|
+
|
|
13
|
+
export const IMAGE_LAYER_Y = 0.012;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IMAGES_DEBUG_STORAGE_KEY } from "./constants";
|
|
2
|
+
|
|
3
|
+
export const imagesDebugEnabled = (() => {
|
|
4
|
+
try {
|
|
5
|
+
return localStorage.getItem(IMAGES_DEBUG_STORAGE_KEY) === "1";
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
})();
|
|
10
|
+
|
|
11
|
+
export function debugLog(...args: unknown[]): void {
|
|
12
|
+
if (imagesDebugEnabled) console.log(...args);
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { EditorFileDropEvent, FileDropHandler, FileDropHandlerContext, HostI18n, PlanePoint } from "@toposync/plugin-api";
|
|
2
|
+
|
|
3
|
+
import { uploadToFilesDir } from "../api/filesApi";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_IMAGE_OPACITY_OVERLAY,
|
|
6
|
+
DEFAULT_IMAGE_OPACITY_TRACING,
|
|
7
|
+
DEFAULT_IMAGE_WIDTH_METERS,
|
|
8
|
+
IMAGE_ELEMENT_TYPE_ID,
|
|
9
|
+
} from "../constants";
|
|
10
|
+
import { filenameStem, isImageFile, readImageDimensions } from "../imageUtils";
|
|
11
|
+
|
|
12
|
+
function viewportCenterWorld(event: EditorFileDropEvent): PlanePoint {
|
|
13
|
+
return event.viewport.screenToWorld({ x: event.viewport.width / 2, y: event.viewport.height / 2 });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createImageFileDropHandler(i18n: HostI18n): FileDropHandler {
|
|
17
|
+
const t = i18n.t;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
id: "com.toposync.images.dropHandler.image",
|
|
21
|
+
canHandle: (event) => event.files.some((file) => isImageFile(file)),
|
|
22
|
+
handle: async (ctx: FileDropHandlerContext, event: EditorFileDropEvent) => {
|
|
23
|
+
const file = event.files.find((f) => isImageFile(f)) ?? null;
|
|
24
|
+
if (!file) return false;
|
|
25
|
+
|
|
26
|
+
const dims = await readImageDimensions(file);
|
|
27
|
+
const upload = await uploadToFilesDir(file, { filename: file.name });
|
|
28
|
+
|
|
29
|
+
const hasNonImageElements = ctx.elements.some((el) => el.type !== IMAGE_ELEMENT_TYPE_ID);
|
|
30
|
+
const mode = hasNonImageElements ? "overlay" : "tracing";
|
|
31
|
+
|
|
32
|
+
const aspect = dims && dims.height > 0 ? dims.width / dims.height : null;
|
|
33
|
+
const widthM = DEFAULT_IMAGE_WIDTH_METERS;
|
|
34
|
+
const depthM = aspect ? widthM / aspect : widthM;
|
|
35
|
+
|
|
36
|
+
const opacity = mode === "tracing" ? DEFAULT_IMAGE_OPACITY_TRACING : DEFAULT_IMAGE_OPACITY_OVERLAY;
|
|
37
|
+
const blend = mode === "tracing" ? "multiply" : "normal";
|
|
38
|
+
|
|
39
|
+
const center = viewportCenterWorld(event);
|
|
40
|
+
const name =
|
|
41
|
+
filenameStem(file.name) ||
|
|
42
|
+
(mode === "tracing" ? t("ext.images.editor.mode.tracing") : t("ext.images.editor.mode.overlay"));
|
|
43
|
+
|
|
44
|
+
const createdElementId = ctx.createElement(IMAGE_ELEMENT_TYPE_ID, {
|
|
45
|
+
name,
|
|
46
|
+
position: { x: center.x, y: 0, z: center.z },
|
|
47
|
+
props: {
|
|
48
|
+
dir: upload.dir,
|
|
49
|
+
file: upload.filename,
|
|
50
|
+
width_m: widthM,
|
|
51
|
+
depth_m: depthM,
|
|
52
|
+
opacity,
|
|
53
|
+
mode,
|
|
54
|
+
blend,
|
|
55
|
+
pixel_width: dims?.width ?? null,
|
|
56
|
+
pixel_height: dims?.height ?? null,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (createdElementId) ctx.openEditor(createdElementId);
|
|
61
|
+
return true;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|