Fixes issue with xy panel (#935)

* update deps

* fixes #930

* update workflow

* Update TopPanel.js

* fix side effects

* Update utilities-performance.cy.js
master
JFH 2023-12-09 17:17:10 +01:00 committed by GitHub
parent 94068b80b7
commit ec3e0522df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1296 additions and 1172 deletions

View File

@ -9,7 +9,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 20.x
- run: | - run: |
npm ci npm ci
npm run build --workspace=packages/svgcanvas npm run build --workspace=packages/svgcanvas
@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16 node-version: 20
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- run: | - run: |
npm ci npm ci

View File

@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 20.x
- run: | - run: |
npm ci npm ci
npm run build --workspace=packages/svgcanvas npm run build --workspace=packages/svgcanvas
@ -26,7 +26,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16 node-version: 20
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- run: npm publish - run: npm publish
env: env:

View File

@ -12,7 +12,7 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 20.x
- name: npm install, test and lint - name: npm install, test and lint
run: | run: |
npm ci npm ci

View File

@ -12,7 +12,7 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 20.x
- name: npm install, test and lint - name: npm install, test and lint
run: | run: |
npm ci npm ci

View File

@ -1,69 +1,71 @@
{"total": {"lines":{"total":6260,"covered":3796,"skipped":0,"pct":60.64},"statements":{"total":6574,"covered":3913,"skipped":0,"pct":59.52},"functions":{"total":949,"covered":495,"skipped":0,"pct":52.16},"branches":{"total":3223,"covered":1398,"skipped":0,"pct":43.38}} {"total": {"lines":{"total":6564,"covered":3798,"skipped":0,"pct":57.86},"statements":{"total":6874,"covered":3901,"skipped":0,"pct":56.75},"functions":{"total":976,"covered":490,"skipped":0,"pct":50.2},"branches":{"total":3361,"covered":1358,"skipped":0,"pct":40.4}}
,"/Users/jfhenon/Work/svgedit/packages/svgcanvas/common/browser.js": {"lines":{"total":25,"covered":24,"skipped":0,"pct":96},"functions":{"total":6,"covered":2,"skipped":0,"pct":33.33},"statements":{"total":30,"covered":25,"skipped":0,"pct":83.33},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/packages/svgcanvas/common/browser.js": {"lines":{"total":25,"covered":24,"skipped":0,"pct":96},"functions":{"total":6,"covered":2,"skipped":0,"pct":33.33},"statements":{"total":30,"covered":25,"skipped":0,"pct":83.33},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/packages/svgcanvas/common/util.js": {"lines":{"total":90,"covered":8,"skipped":0,"pct":8.89},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.86},"statements":{"total":92,"covered":10,"skipped":0,"pct":10.87},"branches":{"total":98,"covered":10,"skipped":0,"pct":10.2}} ,"/Users/jean-francoishenon/Work/svgedit/packages/svgcanvas/common/util.js": {"lines":{"total":90,"covered":8,"skipped":0,"pct":8.89},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.86},"statements":{"total":92,"covered":10,"skipped":0,"pct":10.87},"branches":{"total":98,"covered":10,"skipped":0,"pct":10.2}}
,"/Users/jfhenon/Work/svgedit/src/editor/ConfigObj.js": {"lines":{"total":101,"covered":46,"skipped":0,"pct":45.54},"functions":{"total":14,"covered":11,"skipped":0,"pct":78.57},"statements":{"total":102,"covered":46,"skipped":0,"pct":45.1},"branches":{"total":96,"covered":30,"skipped":0,"pct":31.25}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/ConfigObj.js": {"lines":{"total":101,"covered":49,"skipped":0,"pct":48.51},"functions":{"total":14,"covered":11,"skipped":0,"pct":78.57},"statements":{"total":102,"covered":49,"skipped":0,"pct":48.04},"branches":{"total":96,"covered":33,"skipped":0,"pct":34.38}}
,"/Users/jfhenon/Work/svgedit/src/editor/Editor.js": {"lines":{"total":410,"covered":200,"skipped":0,"pct":48.78},"functions":{"total":102,"covered":34,"skipped":0,"pct":33.33},"statements":{"total":417,"covered":201,"skipped":0,"pct":48.2},"branches":{"total":213,"covered":78,"skipped":0,"pct":36.62}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/Editor.js": {"lines":{"total":410,"covered":184,"skipped":0,"pct":44.88},"functions":{"total":102,"covered":32,"skipped":0,"pct":31.37},"statements":{"total":417,"covered":185,"skipped":0,"pct":44.36},"branches":{"total":213,"covered":68,"skipped":0,"pct":31.92}}
,"/Users/jfhenon/Work/svgedit/src/editor/EditorStartup.js": {"lines":{"total":346,"covered":216,"skipped":0,"pct":62.43},"functions":{"total":51,"covered":27,"skipped":0,"pct":52.94},"statements":{"total":357,"covered":224,"skipped":0,"pct":62.75},"branches":{"total":122,"covered":41,"skipped":0,"pct":33.61}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/EditorStartup.js": {"lines":{"total":346,"covered":211,"skipped":0,"pct":60.98},"functions":{"total":51,"covered":26,"skipped":0,"pct":50.98},"statements":{"total":357,"covered":219,"skipped":0,"pct":61.34},"branches":{"total":122,"covered":38,"skipped":0,"pct":31.15}}
,"/Users/jfhenon/Work/svgedit/src/editor/MainMenu.js": {"lines":{"total":111,"covered":44,"skipped":0,"pct":39.64},"functions":{"total":14,"covered":7,"skipped":0,"pct":50},"statements":{"total":111,"covered":44,"skipped":0,"pct":39.64},"branches":{"total":48,"covered":7,"skipped":0,"pct":14.58}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/MainMenu.js": {"lines":{"total":111,"covered":44,"skipped":0,"pct":39.64},"functions":{"total":14,"covered":7,"skipped":0,"pct":50},"statements":{"total":111,"covered":44,"skipped":0,"pct":39.64},"branches":{"total":48,"covered":7,"skipped":0,"pct":14.58}}
,"/Users/jfhenon/Work/svgedit/src/editor/Rulers.js": {"lines":{"total":119,"covered":93,"skipped":0,"pct":78.15},"functions":{"total":6,"covered":5,"skipped":0,"pct":83.33},"statements":{"total":124,"covered":98,"skipped":0,"pct":79.03},"branches":{"total":43,"covered":32,"skipped":0,"pct":74.42}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/Rulers.js": {"lines":{"total":119,"covered":91,"skipped":0,"pct":76.47},"functions":{"total":6,"covered":4,"skipped":0,"pct":66.67},"statements":{"total":124,"covered":94,"skipped":0,"pct":75.81},"branches":{"total":43,"covered":30,"skipped":0,"pct":69.77}}
,"/Users/jfhenon/Work/svgedit/src/editor/browser-not-supported.js": {"lines":{"total":4,"covered":3,"skipped":0,"pct":75},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":3,"skipped":0,"pct":75},"branches":{"total":4,"covered":3,"skipped":0,"pct":75}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/browser-not-supported.js": {"lines":{"total":4,"covered":3,"skipped":0,"pct":75},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":3,"skipped":0,"pct":75},"branches":{"total":4,"covered":3,"skipped":0,"pct":75}}
,"/Users/jfhenon/Work/svgedit/src/editor/contextmenu.js": {"lines":{"total":22,"covered":9,"skipped":0,"pct":40.91},"functions":{"total":8,"covered":1,"skipped":0,"pct":12.5},"statements":{"total":23,"covered":9,"skipped":0,"pct":39.13},"branches":{"total":13,"covered":0,"skipped":0,"pct":0}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/contextmenu.js": {"lines":{"total":22,"covered":9,"skipped":0,"pct":40.91},"functions":{"total":8,"covered":1,"skipped":0,"pct":12.5},"statements":{"total":23,"covered":9,"skipped":0,"pct":39.13},"branches":{"total":13,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfhenon/Work/svgedit/src/editor/locale.js": {"lines":{"total":14,"covered":9,"skipped":0,"pct":64.29},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":14,"covered":9,"skipped":0,"pct":64.29},"branches":{"total":10,"covered":3,"skipped":0,"pct":30}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/locale.js": {"lines":{"total":14,"covered":9,"skipped":0,"pct":64.29},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":14,"covered":9,"skipped":0,"pct":64.29},"branches":{"total":10,"covered":3,"skipped":0,"pct":30}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/PaintBox.js": {"lines":{"total":64,"covered":51,"skipped":0,"pct":79.69},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":67,"covered":53,"skipped":0,"pct":79.1},"branches":{"total":33,"covered":21,"skipped":0,"pct":63.64}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/PaintBox.js": {"lines":{"total":64,"covered":35,"skipped":0,"pct":54.69},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":67,"covered":35,"skipped":0,"pct":52.24},"branches":{"total":33,"covered":12,"skipped":0,"pct":36.36}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/index.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/index.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seButton.js": {"lines":{"total":57,"covered":40,"skipped":0,"pct":70.18},"functions":{"total":15,"covered":7,"skipped":0,"pct":46.67},"statements":{"total":60,"covered":42,"skipped":0,"pct":70},"branches":{"total":33,"covered":23,"skipped":0,"pct":69.7}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seButton.js": {"lines":{"total":57,"covered":40,"skipped":0,"pct":70.18},"functions":{"total":15,"covered":7,"skipped":0,"pct":46.67},"statements":{"total":60,"covered":42,"skipped":0,"pct":70},"branches":{"total":33,"covered":23,"skipped":0,"pct":69.7}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seColorPicker.js": {"lines":{"total":50,"covered":41,"skipped":0,"pct":82},"functions":{"total":16,"covered":11,"skipped":0,"pct":68.75},"statements":{"total":51,"covered":41,"skipped":0,"pct":80.39},"branches":{"total":11,"covered":8,"skipped":0,"pct":72.73}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seColorPicker.js": {"lines":{"total":50,"covered":41,"skipped":0,"pct":82},"functions":{"total":16,"covered":11,"skipped":0,"pct":68.75},"statements":{"total":51,"covered":41,"skipped":0,"pct":80.39},"branches":{"total":11,"covered":8,"skipped":0,"pct":72.73}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seExplorerButton.js": {"lines":{"total":95,"covered":72,"skipped":0,"pct":75.79},"functions":{"total":17,"covered":10,"skipped":0,"pct":58.82},"statements":{"total":98,"covered":72,"skipped":0,"pct":73.47},"branches":{"total":30,"covered":17,"skipped":0,"pct":56.67}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seExplorerButton.js": {"lines":{"total":95,"covered":72,"skipped":0,"pct":75.79},"functions":{"total":17,"covered":10,"skipped":0,"pct":58.82},"statements":{"total":98,"covered":72,"skipped":0,"pct":73.47},"branches":{"total":30,"covered":17,"skipped":0,"pct":56.67}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seFlyingButton.js": {"lines":{"total":74,"covered":47,"skipped":0,"pct":63.51},"functions":{"total":14,"covered":9,"skipped":0,"pct":64.29},"statements":{"total":75,"covered":48,"skipped":0,"pct":64},"branches":{"total":29,"covered":12,"skipped":0,"pct":41.38}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seFlyingButton.js": {"lines":{"total":74,"covered":47,"skipped":0,"pct":63.51},"functions":{"total":14,"covered":9,"skipped":0,"pct":64.29},"statements":{"total":75,"covered":48,"skipped":0,"pct":64},"branches":{"total":29,"covered":12,"skipped":0,"pct":41.38}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seInput.js": {"lines":{"total":46,"covered":31,"skipped":0,"pct":67.39},"functions":{"total":16,"covered":8,"skipped":0,"pct":50},"statements":{"total":47,"covered":31,"skipped":0,"pct":65.96},"branches":{"total":8,"covered":4,"skipped":0,"pct":50}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seInput.js": {"lines":{"total":46,"covered":31,"skipped":0,"pct":67.39},"functions":{"total":16,"covered":8,"skipped":0,"pct":50},"statements":{"total":47,"covered":31,"skipped":0,"pct":65.96},"branches":{"total":8,"covered":4,"skipped":0,"pct":50}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seList.js": {"lines":{"total":87,"covered":59,"skipped":0,"pct":67.82},"functions":{"total":21,"covered":10,"skipped":0,"pct":47.62},"statements":{"total":89,"covered":61,"skipped":0,"pct":68.54},"branches":{"total":22,"covered":12,"skipped":0,"pct":54.55}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seList.js": {"lines":{"total":87,"covered":59,"skipped":0,"pct":67.82},"functions":{"total":21,"covered":10,"skipped":0,"pct":47.62},"statements":{"total":89,"covered":61,"skipped":0,"pct":68.54},"branches":{"total":22,"covered":12,"skipped":0,"pct":54.55}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seListItem.js": {"lines":{"total":39,"covered":26,"skipped":0,"pct":66.67},"functions":{"total":12,"covered":4,"skipped":0,"pct":33.33},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":10,"covered":8,"skipped":0,"pct":80}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seListItem.js": {"lines":{"total":39,"covered":26,"skipped":0,"pct":66.67},"functions":{"total":12,"covered":4,"skipped":0,"pct":33.33},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":10,"covered":8,"skipped":0,"pct":80}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seMenu.js": {"lines":{"total":26,"covered":20,"skipped":0,"pct":76.92},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.86},"statements":{"total":27,"covered":20,"skipped":0,"pct":74.07},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seMenu.js": {"lines":{"total":26,"covered":20,"skipped":0,"pct":76.92},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.86},"statements":{"total":27,"covered":20,"skipped":0,"pct":74.07},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seMenuItem.js": {"lines":{"total":37,"covered":26,"skipped":0,"pct":70.27},"functions":{"total":9,"covered":5,"skipped":0,"pct":55.56},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":19,"covered":8,"skipped":0,"pct":42.11}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seMenuItem.js": {"lines":{"total":37,"covered":26,"skipped":0,"pct":70.27},"functions":{"total":9,"covered":5,"skipped":0,"pct":55.56},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":19,"covered":8,"skipped":0,"pct":42.11}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/sePalette.js": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.97},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.97},"branches":{"total":13,"covered":10,"skipped":0,"pct":76.92}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/sePalette.js": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.97},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.97},"branches":{"total":13,"covered":10,"skipped":0,"pct":76.92}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/sePlainBorderButton.js": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/sePlainBorderButton.js": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/sePlainMenuButton.js": {"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/sePlainMenuButton.js": {"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seSelect.js": {"lines":{"total":56,"covered":45,"skipped":0,"pct":80.36},"functions":{"total":17,"covered":9,"skipped":0,"pct":52.94},"statements":{"total":59,"covered":47,"skipped":0,"pct":79.66},"branches":{"total":16,"covered":14,"skipped":0,"pct":87.5}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seSelect.js": {"lines":{"total":56,"covered":45,"skipped":0,"pct":80.36},"functions":{"total":17,"covered":9,"skipped":0,"pct":52.94},"statements":{"total":59,"covered":47,"skipped":0,"pct":79.66},"branches":{"total":16,"covered":14,"skipped":0,"pct":87.5}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seSpinInput.js": {"lines":{"total":65,"covered":55,"skipped":0,"pct":84.62},"functions":{"total":18,"covered":10,"skipped":0,"pct":55.56},"statements":{"total":66,"covered":55,"skipped":0,"pct":83.33},"branches":{"total":17,"covered":13,"skipped":0,"pct":76.47}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seSpinInput.js": {"lines":{"total":65,"covered":55,"skipped":0,"pct":84.62},"functions":{"total":18,"covered":10,"skipped":0,"pct":55.56},"statements":{"total":66,"covered":55,"skipped":0,"pct":83.33},"branches":{"total":17,"covered":13,"skipped":0,"pct":76.47}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seText.js": {"lines":{"total":28,"covered":18,"skipped":0,"pct":64.29},"functions":{"total":10,"covered":4,"skipped":0,"pct":40},"statements":{"total":29,"covered":18,"skipped":0,"pct":62.07},"branches":{"total":8,"covered":5,"skipped":0,"pct":62.5}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seText.js": {"lines":{"total":28,"covered":18,"skipped":0,"pct":64.29},"functions":{"total":10,"covered":4,"skipped":0,"pct":40},"statements":{"total":29,"covered":18,"skipped":0,"pct":62.07},"branches":{"total":8,"covered":5,"skipped":0,"pct":62.5}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/seZoom.js": {"lines":{"total":99,"covered":93,"skipped":0,"pct":93.94},"functions":{"total":28,"covered":24,"skipped":0,"pct":85.71},"statements":{"total":107,"covered":100,"skipped":0,"pct":93.46},"branches":{"total":36,"covered":21,"skipped":0,"pct":58.33}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seZoom.js": {"lines":{"total":102,"covered":65,"skipped":0,"pct":63.73},"functions":{"total":28,"covered":9,"skipped":0,"pct":32.14},"statements":{"total":107,"covered":66,"skipped":0,"pct":61.68},"branches":{"total":36,"covered":7,"skipped":0,"pct":19.44}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/jgraduate/ColorValuePicker.js": {"lines":{"total":231,"covered":54,"skipped":0,"pct":23.38},"functions":{"total":9,"covered":3,"skipped":0,"pct":33.33},"statements":{"total":249,"covered":63,"skipped":0,"pct":25.3},"branches":{"total":157,"covered":34,"skipped":0,"pct":21.66}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/jgraduate/ColorValuePicker.js": {"lines":{"total":231,"covered":54,"skipped":0,"pct":23.38},"functions":{"total":9,"covered":3,"skipped":0,"pct":33.33},"statements":{"total":249,"covered":63,"skipped":0,"pct":25.3},"branches":{"total":157,"covered":34,"skipped":0,"pct":21.66}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/jgraduate/Slider.js": {"lines":{"total":156,"covered":91,"skipped":0,"pct":58.33},"functions":{"total":17,"covered":9,"skipped":0,"pct":52.94},"statements":{"total":176,"covered":96,"skipped":0,"pct":54.55},"branches":{"total":186,"covered":97,"skipped":0,"pct":52.15}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/jgraduate/Slider.js": {"lines":{"total":156,"covered":91,"skipped":0,"pct":58.33},"functions":{"total":17,"covered":9,"skipped":0,"pct":52.94},"statements":{"total":176,"covered":96,"skipped":0,"pct":54.55},"branches":{"total":186,"covered":97,"skipped":0,"pct":52.15}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/jgraduate/jQuery.jGraduate.js": {"lines":{"total":580,"covered":275,"skipped":0,"pct":47.41},"functions":{"total":44,"covered":14,"skipped":0,"pct":31.82},"statements":{"total":602,"covered":282,"skipped":0,"pct":46.84},"branches":{"total":278,"covered":100,"skipped":0,"pct":35.97}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/jgraduate/jQuery.jGraduate.js": {"lines":{"total":580,"covered":275,"skipped":0,"pct":47.41},"functions":{"total":44,"covered":14,"skipped":0,"pct":31.82},"statements":{"total":602,"covered":282,"skipped":0,"pct":46.84},"branches":{"total":278,"covered":100,"skipped":0,"pct":35.97}}
,"/Users/jfhenon/Work/svgedit/src/editor/components/jgraduate/jQuery.jPicker.js": {"lines":{"total":840,"covered":449,"skipped":0,"pct":53.45},"functions":{"total":60,"covered":39,"skipped":0,"pct":65},"statements":{"total":926,"covered":475,"skipped":0,"pct":51.3},"branches":{"total":777,"covered":327,"skipped":0,"pct":42.08}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/jgraduate/jQuery.jPicker.js": {"lines":{"total":840,"covered":449,"skipped":0,"pct":53.45},"functions":{"total":60,"covered":39,"skipped":0,"pct":65},"statements":{"total":926,"covered":475,"skipped":0,"pct":51.3},"branches":{"total":777,"covered":327,"skipped":0,"pct":42.08}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/SePlainAlertDialog.js": {"lines":{"total":7,"covered":1,"skipped":0,"pct":14.29},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":7,"covered":1,"skipped":0,"pct":14.29},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/SePlainAlertDialog.js": {"lines":{"total":7,"covered":1,"skipped":0,"pct":14.29},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":7,"covered":1,"skipped":0,"pct":14.29},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/cmenuDialog.js": {"lines":{"total":120,"covered":112,"skipped":0,"pct":93.33},"functions":{"total":28,"covered":16,"skipped":0,"pct":57.14},"statements":{"total":131,"covered":117,"skipped":0,"pct":89.31},"branches":{"total":23,"covered":19,"skipped":0,"pct":82.61}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/cmenuDialog.js": {"lines":{"total":120,"covered":112,"skipped":0,"pct":93.33},"functions":{"total":28,"covered":15,"skipped":0,"pct":53.57},"statements":{"total":131,"covered":116,"skipped":0,"pct":88.55},"branches":{"total":23,"covered":19,"skipped":0,"pct":82.61}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/cmenuLayersDialog.js": {"lines":{"total":61,"covered":49,"skipped":0,"pct":80.33},"functions":{"total":16,"covered":6,"skipped":0,"pct":37.5},"statements":{"total":66,"covered":49,"skipped":0,"pct":74.24},"branches":{"total":18,"covered":13,"skipped":0,"pct":72.22}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/cmenuLayersDialog.js": {"lines":{"total":61,"covered":49,"skipped":0,"pct":80.33},"functions":{"total":16,"covered":6,"skipped":0,"pct":37.5},"statements":{"total":66,"covered":49,"skipped":0,"pct":74.24},"branches":{"total":18,"covered":13,"skipped":0,"pct":72.22}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/editorPreferencesDialog.js": {"lines":{"total":157,"covered":125,"skipped":0,"pct":79.62},"functions":{"total":30,"covered":9,"skipped":0,"pct":30},"statements":{"total":159,"covered":126,"skipped":0,"pct":79.25},"branches":{"total":46,"covered":35,"skipped":0,"pct":76.09}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/editorPreferencesDialog.js": {"lines":{"total":157,"covered":124,"skipped":0,"pct":78.98},"functions":{"total":30,"covered":9,"skipped":0,"pct":30},"statements":{"total":159,"covered":125,"skipped":0,"pct":78.62},"branches":{"total":46,"covered":34,"skipped":0,"pct":73.91}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/exportDialog.js": {"lines":{"total":55,"covered":39,"skipped":0,"pct":70.91},"functions":{"total":14,"covered":5,"skipped":0,"pct":35.71},"statements":{"total":58,"covered":39,"skipped":0,"pct":67.24},"branches":{"total":12,"covered":6,"skipped":0,"pct":50}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/exportDialog.js": {"lines":{"total":55,"covered":39,"skipped":0,"pct":70.91},"functions":{"total":14,"covered":5,"skipped":0,"pct":35.71},"statements":{"total":58,"covered":39,"skipped":0,"pct":67.24},"branches":{"total":12,"covered":6,"skipped":0,"pct":50}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/imagePropertiesDialog.js": {"lines":{"total":161,"covered":90,"skipped":0,"pct":55.9},"functions":{"total":20,"covered":5,"skipped":0,"pct":25},"statements":{"total":162,"covered":90,"skipped":0,"pct":55.56},"branches":{"total":53,"covered":23,"skipped":0,"pct":43.4}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/imagePropertiesDialog.js": {"lines":{"total":161,"covered":90,"skipped":0,"pct":55.9},"functions":{"total":20,"covered":5,"skipped":0,"pct":25},"statements":{"total":162,"covered":90,"skipped":0,"pct":55.56},"branches":{"total":53,"covered":23,"skipped":0,"pct":43.4}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/index.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/index.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/seAlertDialog.js": {"lines":{"total":6,"covered":2,"skipped":0,"pct":33.33},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":6,"covered":2,"skipped":0,"pct":33.33},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/seAlertDialog.js": {"lines":{"total":6,"covered":2,"skipped":0,"pct":33.33},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":6,"covered":2,"skipped":0,"pct":33.33},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/seConfirmDialog.js": {"lines":{"total":8,"covered":2,"skipped":0,"pct":25},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":8,"covered":2,"skipped":0,"pct":25},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/seConfirmDialog.js": {"lines":{"total":8,"covered":2,"skipped":0,"pct":25},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":8,"covered":2,"skipped":0,"pct":25},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/sePromptDialog.js": {"lines":{"total":24,"covered":5,"skipped":0,"pct":20.83},"functions":{"total":7,"covered":2,"skipped":0,"pct":28.57},"statements":{"total":24,"covered":5,"skipped":0,"pct":20.83},"branches":{"total":9,"covered":0,"skipped":0,"pct":0}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/sePromptDialog.js": {"lines":{"total":24,"covered":5,"skipped":0,"pct":20.83},"functions":{"total":7,"covered":2,"skipped":0,"pct":28.57},"statements":{"total":24,"covered":5,"skipped":0,"pct":20.83},"branches":{"total":9,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/seSelectDialog.js": {"lines":{"total":8,"covered":2,"skipped":0,"pct":25},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":8,"covered":2,"skipped":0,"pct":25},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/seSelectDialog.js": {"lines":{"total":8,"covered":2,"skipped":0,"pct":25},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":8,"covered":2,"skipped":0,"pct":25},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/svgSourceDialog.js": {"lines":{"total":74,"covered":56,"skipped":0,"pct":75.68},"functions":{"total":17,"covered":6,"skipped":0,"pct":35.29},"statements":{"total":75,"covered":57,"skipped":0,"pct":76},"branches":{"total":17,"covered":14,"skipped":0,"pct":82.35}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/svgSourceDialog.js": {"lines":{"total":74,"covered":56,"skipped":0,"pct":75.68},"functions":{"total":17,"covered":6,"skipped":0,"pct":35.29},"statements":{"total":75,"covered":56,"skipped":0,"pct":74.67},"branches":{"total":17,"covered":13,"skipped":0,"pct":76.47}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/se-elix/define/NumberSpinBox.js": {"lines":{"total":1,"covered":1,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":1,"covered":1,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/se-elix/define/NumberSpinBox.js": {"lines":{"total":1,"covered":1,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":1,"covered":1,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/se-elix/src/base/NumberSpinBox.js": {"lines":{"total":54,"covered":52,"skipped":0,"pct":96.3},"functions":{"total":13,"covered":11,"skipped":0,"pct":84.62},"statements":{"total":54,"covered":52,"skipped":0,"pct":96.3},"branches":{"total":53,"covered":47,"skipped":0,"pct":88.68}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/se-elix/src/base/NumberSpinBox.js": {"lines":{"total":54,"covered":52,"skipped":0,"pct":96.3},"functions":{"total":13,"covered":11,"skipped":0,"pct":84.62},"statements":{"total":54,"covered":52,"skipped":0,"pct":96.3},"branches":{"total":53,"covered":47,"skipped":0,"pct":88.68}}
,"/Users/jfhenon/Work/svgedit/src/editor/dialogs/se-elix/src/plain/PlainNumberSpinBox.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/se-elix/src/plain/PlainNumberSpinBox.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-eyedropper/ext-eyedropper.js": {"lines":{"total":60,"covered":39,"skipped":0,"pct":65},"functions":{"total":8,"covered":5,"skipped":0,"pct":62.5},"statements":{"total":71,"covered":39,"skipped":0,"pct":54.93},"branches":{"total":39,"covered":15,"skipped":0,"pct":38.46}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-connector/ext-connector.js": {"lines":{"total":287,"covered":83,"skipped":0,"pct":28.92},"functions":{"total":26,"covered":16,"skipped":0,"pct":61.54},"statements":{"total":295,"covered":86,"skipped":0,"pct":29.15},"branches":{"total":140,"covered":19,"skipped":0,"pct":13.57}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-eyedropper/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-connector/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-grid/ext-grid.js": {"lines":{"total":88,"covered":43,"skipped":0,"pct":48.86},"functions":{"total":8,"covered":4,"skipped":0,"pct":50},"statements":{"total":90,"covered":43,"skipped":0,"pct":47.78},"branches":{"total":10,"covered":4,"skipped":0,"pct":40}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-eyedropper/ext-eyedropper.js": {"lines":{"total":60,"covered":39,"skipped":0,"pct":65},"functions":{"total":8,"covered":5,"skipped":0,"pct":62.5},"statements":{"total":71,"covered":39,"skipped":0,"pct":54.93},"branches":{"total":39,"covered":14,"skipped":0,"pct":35.9}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-grid/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-eyedropper/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-markers/ext-markers.js": {"lines":{"total":149,"covered":46,"skipped":0,"pct":30.87},"functions":{"total":21,"covered":12,"skipped":0,"pct":57.14},"statements":{"total":164,"covered":48,"skipped":0,"pct":29.27},"branches":{"total":80,"covered":22,"skipped":0,"pct":27.5}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-grid/ext-grid.js": {"lines":{"total":88,"covered":43,"skipped":0,"pct":48.86},"functions":{"total":8,"covered":4,"skipped":0,"pct":50},"statements":{"total":90,"covered":43,"skipped":0,"pct":47.78},"branches":{"total":10,"covered":4,"skipped":0,"pct":40}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-opensave/ext-opensave.js": {"lines":{"total":136,"covered":36,"skipped":0,"pct":26.47},"functions":{"total":13,"covered":3,"skipped":0,"pct":23.08},"statements":{"total":141,"covered":36,"skipped":0,"pct":25.53},"branches":{"total":32,"covered":0,"skipped":0,"pct":0}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-grid/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-opensave/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-markers/ext-markers.js": {"lines":{"total":149,"covered":46,"skipped":0,"pct":30.87},"functions":{"total":21,"covered":12,"skipped":0,"pct":57.14},"statements":{"total":164,"covered":48,"skipped":0,"pct":29.27},"branches":{"total":80,"covered":22,"skipped":0,"pct":27.5}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-panning/ext-panning.js": {"lines":{"total":30,"covered":22,"skipped":0,"pct":73.33},"functions":{"total":7,"covered":6,"skipped":0,"pct":85.71},"statements":{"total":30,"covered":22,"skipped":0,"pct":73.33},"branches":{"total":6,"covered":2,"skipped":0,"pct":33.33}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-opensave/ext-opensave.js": {"lines":{"total":136,"covered":36,"skipped":0,"pct":26.47},"functions":{"total":13,"covered":3,"skipped":0,"pct":23.08},"statements":{"total":141,"covered":36,"skipped":0,"pct":25.53},"branches":{"total":32,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-panning/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-opensave/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-polystar/ext-polystar.js": {"lines":{"total":247,"covered":232,"skipped":0,"pct":93.93},"functions":{"total":18,"covered":16,"skipped":0,"pct":88.89},"statements":{"total":256,"covered":241,"skipped":0,"pct":94.14},"branches":{"total":62,"covered":39,"skipped":0,"pct":62.9}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-panning/ext-panning.js": {"lines":{"total":30,"covered":22,"skipped":0,"pct":73.33},"functions":{"total":7,"covered":6,"skipped":0,"pct":85.71},"statements":{"total":30,"covered":22,"skipped":0,"pct":73.33},"branches":{"total":6,"covered":2,"skipped":0,"pct":33.33}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-polystar/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-panning/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-shapes/ext-shapes.js": {"lines":{"total":76,"covered":74,"skipped":0,"pct":97.37},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":80,"covered":78,"skipped":0,"pct":97.5},"branches":{"total":26,"covered":17,"skipped":0,"pct":65.38}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-polystar/ext-polystar.js": {"lines":{"total":247,"covered":232,"skipped":0,"pct":93.93},"functions":{"total":18,"covered":16,"skipped":0,"pct":88.89},"statements":{"total":256,"covered":241,"skipped":0,"pct":94.14},"branches":{"total":62,"covered":39,"skipped":0,"pct":62.9}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-shapes/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-polystar/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-storage/ext-storage.js": {"lines":{"total":91,"covered":59,"skipped":0,"pct":64.84},"functions":{"total":12,"covered":7,"skipped":0,"pct":58.33},"statements":{"total":91,"covered":59,"skipped":0,"pct":64.84},"branches":{"total":68,"covered":27,"skipped":0,"pct":39.71}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-shapes/ext-shapes.js": {"lines":{"total":76,"covered":74,"skipped":0,"pct":97.37},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":80,"covered":78,"skipped":0,"pct":97.5},"branches":{"total":26,"covered":17,"skipped":0,"pct":65.38}}
,"/Users/jfhenon/Work/svgedit/src/editor/extensions/ext-storage/storageDialog.js": {"lines":{"total":60,"covered":56,"skipped":0,"pct":93.33},"functions":{"total":10,"covered":7,"skipped":0,"pct":70},"statements":{"total":62,"covered":57,"skipped":0,"pct":91.94},"branches":{"total":15,"covered":13,"skipped":0,"pct":86.67}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-shapes/locale/en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/locale/lang.en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-storage/ext-storage.js": {"lines":{"total":91,"covered":59,"skipped":0,"pct":64.84},"functions":{"total":12,"covered":7,"skipped":0,"pct":58.33},"statements":{"total":91,"covered":59,"skipped":0,"pct":64.84},"branches":{"total":68,"covered":26,"skipped":0,"pct":38.24}}
,"/Users/jfhenon/Work/svgedit/src/editor/panels/BottomPanel.js": {"lines":{"total":71,"covered":58,"skipped":0,"pct":81.69},"functions":{"total":22,"covered":14,"skipped":0,"pct":63.64},"statements":{"total":77,"covered":61,"skipped":0,"pct":79.22},"branches":{"total":30,"covered":16,"skipped":0,"pct":53.33}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-storage/storageDialog.js": {"lines":{"total":60,"covered":56,"skipped":0,"pct":93.33},"functions":{"total":10,"covered":7,"skipped":0,"pct":70},"statements":{"total":62,"covered":57,"skipped":0,"pct":91.94},"branches":{"total":15,"covered":13,"skipped":0,"pct":86.67}}
,"/Users/jfhenon/Work/svgedit/src/editor/panels/LayersPanel.js": {"lines":{"total":157,"covered":70,"skipped":0,"pct":44.59},"functions":{"total":27,"covered":6,"skipped":0,"pct":22.22},"statements":{"total":163,"covered":71,"skipped":0,"pct":43.56},"branches":{"total":46,"covered":6,"skipped":0,"pct":13.04}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/locale/lang.en.js": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfhenon/Work/svgedit/src/editor/panels/LeftPanel.js": {"lines":{"total":58,"covered":47,"skipped":0,"pct":81.03},"functions":{"total":20,"covered":15,"skipped":0,"pct":75},"statements":{"total":59,"covered":47,"skipped":0,"pct":79.66},"branches":{"total":32,"covered":12,"skipped":0,"pct":37.5}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/BottomPanel.js": {"lines":{"total":71,"covered":56,"skipped":0,"pct":78.87},"functions":{"total":22,"covered":14,"skipped":0,"pct":63.64},"statements":{"total":77,"covered":59,"skipped":0,"pct":76.62},"branches":{"total":30,"covered":12,"skipped":0,"pct":40}}
,"/Users/jfhenon/Work/svgedit/src/editor/panels/TopPanel.js": {"lines":{"total":391,"covered":296,"skipped":0,"pct":75.7},"functions":{"total":73,"covered":48,"skipped":0,"pct":65.75},"statements":{"total":411,"covered":304,"skipped":0,"pct":73.97},"branches":{"total":207,"covered":127,"skipped":0,"pct":61.35}} ,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/LayersPanel.js": {"lines":{"total":157,"covered":70,"skipped":0,"pct":44.59},"functions":{"total":27,"covered":6,"skipped":0,"pct":22.22},"statements":{"total":163,"covered":71,"skipped":0,"pct":43.56},"branches":{"total":46,"covered":6,"skipped":0,"pct":13.04}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/LeftPanel.js": {"lines":{"total":58,"covered":47,"skipped":0,"pct":81.03},"functions":{"total":20,"covered":15,"skipped":0,"pct":75},"statements":{"total":59,"covered":47,"skipped":0,"pct":79.66},"branches":{"total":32,"covered":12,"skipped":0,"pct":37.5}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/TopPanel.js": {"lines":{"total":405,"covered":282,"skipped":0,"pct":69.63},"functions":{"total":74,"covered":47,"skipped":0,"pct":63.51},"statements":{"total":416,"covered":285,"skipped":0,"pct":68.51},"branches":{"total":205,"covered":111,"skipped":0,"pct":54.15}}
} }

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="330" cy="250" edge="63.75" fill="#FF0000" id="svg_1" orient="x" points="637.5,250 600.0264282226562,301.5779724121094 539.3928833007812,281.8769226074219 539.3928833007812,218.12306213378906 600.0264282226562,198.4220428466797 637.5,250 " shape="regularPoly" sides="5" stroke="#000000" stroke-width="5"/> <polygon cx="330" cy="250" edge="63.75" fill="#FF0000" id="svg_1" orient="x" points="637.4922637939453,250 600.0186920166016,301.5779724121094 539.3851470947266,281.8769226074219 539.3851470947266,218.12306213378906 600.0186920166016,198.4220428466797 637.4922637939453,250 " shape="regularPoly" sides="5" stroke="#000000" stroke-width="5"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 482 B

After

Width:  |  Height:  |  Size: 506 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="330" cy="250" edge="63.75" fill="#bf0000" id="svg_1" orient="x" points="665.1679905202699,250 633.291057027713,305.21246839860237 569.5371900425995,305.21246839860237 537.6602565500426,250 569.5371900425994,194.78753160139763 633.291057027713,194.78753160139763 665.1679905202699,249.99999999999997 " shape="regularPoly" sides="6" stroke="#0000bf" stroke-width="15"/> <polygon cx="330" cy="250" edge="63.75" fill="#bf0000" id="svg_1" orient="x" points="665.1602390554261,250 633.2833055628693,305.21246839860237 569.5294385777557,305.21246839860237 537.6525050851989,250 569.5294385777556,194.78753160139763 633.2833055628693,194.78753160139763 665.1602390554261,249.99999999999997 " shape="regularPoly" sides="6" stroke="#0000bf" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 547 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="330" cy="250" edge="63.75" fill="#bf0000" id="svg_1" orient="x" points="637.5,250 600.0264282226562,301.5779724121094 539.3928833007812,281.8769226074219 539.3928833007812,218.12306213378906 600.0264282226562,198.4220428466797 637.5,250 " shape="regularPoly" sides="5" stroke="#0000bf" stroke-width="15"/> <polygon cx="330" cy="250" edge="63.75" fill="#bf0000" id="svg_1" orient="x" points="637.4922637939453,250 600.0186920166016,301.5779724121094 539.3851470947266,281.8769226074219 539.3851470947266,218.12306213378906 600.0186920166016,198.4220428466797 637.4922637939453,250 " shape="regularPoly" sides="5" stroke="#0000bf" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 507 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="330" cy="250" edge="63.75" fill="#FF0000" id="svg_1" orient="x" points="637.5,250 600.0264282226562,301.5779724121094 539.3928833007812,281.8769226074219 539.3928833007812,218.12306213378906 600.0264282226562,198.4220428466797 637.5,250 " shape="regularPoly" sides="5" stroke="#000000" stroke-width="15"/> <polygon cx="330" cy="250" edge="63.75" fill="#FF0000" id="svg_1" orient="x" points="637.4922637939453,250 600.0186920166016,301.5779724121094 539.3851470947266,281.8769226074219 539.3851470947266,218.12306213378906 600.0186920166016,198.4220428466797 637.4922637939453,250 " shape="regularPoly" sides="5" stroke="#000000" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 507 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="300" cy="150" fill="#FF0000" id="svg_1" orient="point" point="5" points="573.7792053222656,83 586.9064025878906,131.9319610595703 637.5,129.29586791992188 595.0194702148438,156.90138244628906 613.1608276367188,204.20413208007812 573.7792053222656,172.3333282470703 534.3975830078125,204.20413208007812 552.5389404296875,156.90138244628906 510.0584259033203,129.29586791992188 560.6520080566406,131.9319610595703 573.7792053222656,83 586.9064025878906,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#000000" stroke-width="5"/> <polygon cx="300" cy="150" fill="#FF0000" id="svg_1" orient="point" point="5" points="573.7799987792969,83 586.9071960449219,131.9319610595703 637.5007934570312,129.29586791992188 595.020263671875,156.90138244628906 613.16162109375,204.20413208007812 573.7799987792969,172.3333282470703 534.3983764648438,204.20413208007812 552.5397338867188,156.90138244628906 510.05921936035156,129.29586791992188 560.6528015136719,131.9319610595703 573.7799987792969,83 586.9071960449219,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#000000" stroke-width="5"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 766 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="300" cy="150" fill="#bf0000" id="svg_1" orient="point" point="6" points="575.6707502092634,69.74376460484095 586.83741687593,117.40253058698849 633.6944522628207,103.24376460484095 598.0040835425967,136.74376460484095 633.6944522628207,170.24376460484092 586.83741687593,156.0849986226934 575.6707502092634,203.74376460484095 564.5040835425967,156.0849986226934 517.647048155706,170.24376460484098 553.33741687593,136.74376460484095 517.647048155706,103.24376460484095 564.5040835425967,117.40253058698849 575.6707502092634,69.74376460484095 586.83741687593,117.40253058698849 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#0000bf" stroke-width="15"/> <polygon cx="300" cy="150" fill="#bf0000" id="svg_1" orient="point" point="6" points="575.6715567452567,69.74376460484095 586.8382234119233,117.40253058698849 633.695258798814,103.24376460484095 598.00489007859,136.74376460484095 633.695258798814,170.24376460484092 586.8382234119233,156.0849986226934 575.6715567452567,203.74376460484095 564.50489007859,156.0849986226934 517.6478546916993,170.24376460484098 553.3382234119233,136.74376460484095 517.6478546916993,103.24376460484095 564.50489007859,117.40253058698849 575.6715567452567,69.74376460484095 586.8382234119233,117.40253058698849 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#0000bf" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 865 B

After

Width:  |  Height:  |  Size: 867 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="300" cy="150" fill="#bf0000" id="svg_1" orient="point" point="5" points="573.7792053222656,83 586.9064025878906,131.9319610595703 637.5,129.29586791992188 595.0194702148438,156.90138244628906 613.1608276367188,204.20413208007812 573.7792053222656,172.3333282470703 534.3975830078125,204.20413208007812 552.5389404296875,156.90138244628906 510.0584259033203,129.29586791992188 560.6520080566406,131.9319610595703 573.7792053222656,83 586.9064025878906,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#0000bf" stroke-width="15"/> <polygon cx="300" cy="150" fill="#bf0000" id="svg_1" orient="point" point="5" points="573.7799987792969,83 586.9071960449219,131.9319610595703 637.5007934570312,129.29586791992188 595.020263671875,156.90138244628906 613.16162109375,204.20413208007812 573.7799987792969,172.3333282470703 534.3983764648438,204.20413208007812 552.5397338867188,156.90138244628906 510.05921936035156,129.29586791992188 560.6528015136719,131.9319610595703 573.7799987792969,83 586.9071960449219,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#0000bf" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 757 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -1,7 +1,7 @@
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g class="layer"> <g class="layer">
<title>Layer 1</title> <title>Layer 1</title>
<polygon cx="300" cy="150" fill="#FF0000" id="svg_1" orient="point" point="5" points="573.7792053222656,83 586.9064025878906,131.9319610595703 637.5,129.29586791992188 595.0194702148438,156.90138244628906 613.1608276367188,204.20413208007812 573.7792053222656,172.3333282470703 534.3975830078125,204.20413208007812 552.5389404296875,156.90138244628906 510.0584259033203,129.29586791992188 560.6520080566406,131.9319610595703 573.7792053222656,83 586.9064025878906,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#000000" stroke-width="15"/> <polygon cx="300" cy="150" fill="#FF0000" id="svg_1" orient="point" point="5" points="573.7799987792969,83 586.9071960449219,131.9319610595703 637.5007934570312,129.29586791992188 595.020263671875,156.90138244628906 613.16162109375,204.20413208007812 573.7799987792969,172.3333282470703 534.3983764648438,204.20413208007812 552.5397338867188,156.90138244628906 510.05921936035156,129.29586791992188 560.6528015136719,131.9319610595703 573.7799987792969,83 586.9071960449219,131.9319610595703 " r="67" r2="22.33" radialshift="0" shape="star" starRadiusMultiplier="3" stroke="#000000" stroke-width="15"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 757 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -5,6 +5,7 @@ import * as utilities from '../../../packages/svgcanvas/core/utilities.js'
import * as math from '../../../packages/svgcanvas/core/math.js' import * as math from '../../../packages/svgcanvas/core/math.js'
import * as path from '../../../packages/svgcanvas/core/path.js' import * as path from '../../../packages/svgcanvas/core/path.js'
import setAssertionMethods from '../../support/assert-close.js' import setAssertionMethods from '../../support/assert-close.js'
import * as units from '../../../packages/svgcanvas/core/units.js'
// eslint-disable-next-line // eslint-disable-next-line
chai.use(setAssertionMethods) chai.use(setAssertionMethods)
@ -94,6 +95,7 @@ describe('utilities bbox', function () {
} }
path.init(mockSvgCanvas) path.init(mockSvgCanvas)
units.init({ getRoundDigits: () => 2 }) // mock getRoundDigits
mockaddSVGElementsFromJsonCallCount = 0 mockaddSVGElementsFromJsonCallCount = 0
}) })

View File

@ -4,9 +4,11 @@ import 'pathseg'
import { NS } from '../../../packages/svgcanvas/core/namespaces.js' import { NS } from '../../../packages/svgcanvas/core/namespaces.js'
import * as utilities from '../../../packages/svgcanvas/core/utilities.js' import * as utilities from '../../../packages/svgcanvas/core/utilities.js'
import * as math from '../../../packages/svgcanvas/core/math.js' import * as math from '../../../packages/svgcanvas/core/math.js'
import * as units from '../../../packages/svgcanvas/core/units.js'
describe('utilities performance', function () { describe('utilities performance', function () {
let currentLayer; let groupWithMatrixTransform; let textWithMatrixTransform let currentLayer; let groupWithMatrixTransform; let textWithMatrixTransform
units.init({ getRoundDigits: () => 2 }) // mock getRoundDigits
beforeEach(() => { beforeEach(() => {
document.body.textContent = '' document.body.textContent = ''
const style = document.createElement('style') const style = document.createElement('style')

1367
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -85,37 +85,37 @@
"dependencies": { "dependencies": {
"@svgedit/svgcanvas": "7.2.1", "@svgedit/svgcanvas": "7.2.1",
"browser-fs-access": "0.35.0", "browser-fs-access": "0.35.0",
"core-js": "3.33.0", "core-js": "3.34.0",
"elix": "15.0.1", "elix": "15.0.1",
"html2canvas": "1.4.1", "html2canvas": "1.4.1",
"i18next": "23.5.1", "i18next": "23.7.8",
"jspdf": "2.5.1", "jspdf": "2.5.1",
"pathseg": "1.2.1", "pathseg": "1.2.1",
"regenerator-runtime": "0.14.0", "regenerator-runtime": "0.14.0",
"replace-in-file": "^7.0.1", "replace-in-file": "^7.0.2",
"svg2pdf.js": "2.2.2" "svg2pdf.js": "2.2.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.23.2", "@babel/core": "7.23.5",
"@babel/preset-env": "7.23.2", "@babel/preset-env": "7.23.5",
"@babel/register": "7.22.15", "@babel/register": "7.22.15",
"@babel/runtime-corejs3": "7.23.2", "@babel/runtime-corejs3": "7.23.5",
"@cypress/code-coverage": "3.12.3", "@cypress/code-coverage": "3.12.13",
"@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "25.0.5", "@rollup/plugin-commonjs": "25.0.7",
"@rollup/plugin-dynamic-import-vars": "2.0.6", "@rollup/plugin-dynamic-import-vars": "2.1.2",
"@rollup/plugin-node-resolve": "15.2.3", "@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "5.0.3", "@rollup/plugin-replace": "5.0.5",
"@rollup/plugin-url": "8.0.2", "@rollup/plugin-url": "8.0.2",
"@web/dev-server": "0.3.3", "@web/dev-server": "0.4.1",
"@web/dev-server-esbuild": "^0.4.1", "@web/dev-server-esbuild": "^1.0.1",
"@web/dev-server-rollup": "0.5.2", "@web/dev-server-rollup": "0.6.1",
"babel-plugin-istanbul": "^6.1.1", "babel-plugin-istanbul": "^6.1.1",
"babel-plugin-transform-object-rest-spread": "7.0.0-beta.3", "babel-plugin-transform-object-rest-spread": "7.0.0-beta.3",
"core-js-bundle": "3.33.0", "core-js-bundle": "3.34.0",
"cp-cli": "2.0.0", "cp-cli": "2.0.0",
"cypress": "13.3.1", "cypress": "13.6.1",
"cypress-multi-reporters": "1.6.3", "cypress-multi-reporters": "1.6.4",
"jamilih": "0.58.2", "jamilih": "0.58.2",
"jsdoc": "4.0.2", "jsdoc": "4.0.2",
"node-static": "0.7.11", "node-static": "0.7.11",
@ -128,13 +128,13 @@
"remark-cli": "12.0.0", "remark-cli": "12.0.0",
"remark-lint-ordered-list-marker-value": "3.1.2", "remark-lint-ordered-list-marker-value": "3.1.2",
"rimraf": "5.0.5", "rimraf": "5.0.5",
"rollup": "4.0.2", "rollup": "4.7.0",
"rollup-plugin-copy": "3.5.0", "rollup-plugin-copy": "3.5.0",
"rollup-plugin-filesize": "10.0.0", "rollup-plugin-filesize": "10.0.0",
"rollup-plugin-html": "0.2.1", "rollup-plugin-html": "0.2.1",
"rollup-plugin-progress": "1.1.2", "rollup-plugin-progress": "1.1.2",
"rollup-plugin-re": "1.0.7", "rollup-plugin-re": "1.0.7",
"standard": "17.1.0", "standard": "17.1.0",
"start-server-and-test": "2.0.1" "start-server-and-test": "2.0.3"
} }
} }

View File

@ -35,6 +35,6 @@
"react-dom": "^18.2.0" "react-dom": "^18.2.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-react": "^7.22.15" "@babel/preset-react": "^7.23.3"
} }
} }

View File

@ -167,8 +167,8 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
// Set x,y vals on elements that don't have them // Set x,y vals on elements that don't have them
if ((attr === 'x' || attr === 'y') && noXYElems.includes(elem.tagName)) { if ((attr === 'x' || attr === 'y') && noXYElems.includes(elem.tagName)) {
const bbox = getStrokedBBoxDefaultVisible([elem]) const bbox = getStrokedBBoxDefaultVisible([elem])
const diffX = attr === 'x' ? newValue - bbox.x : 0 const diffX = attr === 'x' ? parseFloat(newValue) - bbox.x : 0
const diffY = attr === 'y' ? newValue - bbox.y : 0 const diffY = attr === 'y' ? parseFloat(newValue) - bbox.y : 0
svgCanvas.moveSelectedElements(diffX * zoom, diffY * zoom, true) svgCanvas.moveSelectedElements(diffX * zoom, diffY * zoom, true)
continue continue
} }
@ -189,7 +189,7 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
} else if (attr === '#href') { } else if (attr === '#href') {
setHref(elem, newValue) setHref(elem, newValue)
} else if (newValue) { } else if (newValue) {
elem.setAttribute(attr, newValue) elem.setAttribute(attr, isNaN(parseFloat(newValue)) ? newValue : parseFloat(newValue))
} else if (typeof newValue === 'number') { } else if (typeof newValue === 'number') {
elem.setAttribute(attr, newValue) elem.setAttribute(attr, newValue)
} else { } else {

View File

@ -7,14 +7,18 @@
*/ */
import { NS } from './namespaces.js' import { NS } from './namespaces.js'
import { setUnitAttr, getTypeMap } from './units.js' import { setUnitAttr, getTypeMap, shortFloat } from './units.js'
import { import {
hasMatrixTransform, transformListToTransform, transformBox, getTransformList hasMatrixTransform,
transformListToTransform,
transformBox,
getTransformList
} from './math.js' } from './math.js'
import { getClosest, mergeDeep } from '../common/util.js' import { getClosest, mergeDeep } from '../common/util.js'
// Much faster than running getBBox() every time // Much faster than running getBBox() every time
const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath' const visElems =
'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath'
const visElemsArr = visElems.split(',') const visElemsArr = visElems.split(',')
// const hidElems = 'defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; // const hidElems = 'defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath';
@ -80,7 +84,7 @@ let svgroot_ = null
* @param {module:utilities.EditorContext} canvas * @param {module:utilities.EditorContext} canvas
* @returns {void} * @returns {void}
*/ */
export const init = (canvas) => { export const init = canvas => {
svgCanvas = canvas svgCanvas = canvas
svgroot_ = canvas.getSvgRoot() svgroot_ = canvas.getSvgRoot()
} }
@ -92,7 +96,7 @@ export const init = (canvas) => {
* @returns {string} The string with entity declarations in the internal subset removed * @returns {string} The string with entity declarations in the internal subset removed
* @todo This might be needed in other places `parseFromString` is used even without LGTM flagging * @todo This might be needed in other places `parseFromString` is used even without LGTM flagging
*/ */
export const dropXMLInternalSubset = (str) => { export const dropXMLInternalSubset = str => {
return str.replace(/(<!DOCTYPE\s+\w*\s*\[).*(\?]>)/, '$1$2') return str.replace(/(<!DOCTYPE\s+\w*\s*\[).*(\?]>)/, '$1$2')
// return str.replace(/(?<doctypeOpen><!DOCTYPE\s+\w*\s*\[).*(?<doctypeClose>\?\]>)/, '$<doctypeOpen>$<doctypeClose>'); // return str.replace(/(?<doctypeOpen><!DOCTYPE\s+\w*\s*\[).*(?<doctypeClose>\?\]>)/, '$<doctypeOpen>$<doctypeClose>');
} }
@ -104,7 +108,7 @@ export const dropXMLInternalSubset = (str) => {
* @param {string} str - The string to be converted * @param {string} str - The string to be converted
* @returns {string} The converted string * @returns {string} The converted string
*/ */
export const toXml = (str) => { export const toXml = str => {
// &apos; is ok in XML, but not HTML // &apos; is ok in XML, but not HTML
// &gt; does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]") // &gt; does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]")
return str return str
@ -155,7 +159,7 @@ export function hashCode (word) {
if (word.length === 0) return hash if (word.length === 0) return hash
for (let i = 0; i < word.length; i++) { for (let i = 0; i < word.length; i++) {
chr = word.charCodeAt(i) chr = word.charCodeAt(i)
hash = ((hash << 5) - hash) + chr hash = (hash << 5) - hash + chr
hash |= 0 // Convert to 32bit integer hash |= 0 // Convert to 32bit integer
} }
return hash return hash
@ -176,7 +180,7 @@ export function decodeUTF8 (argString) {
* @param {string} argString * @param {string} argString
* @returns {string} * @returns {string}
*/ */
export const encodeUTF8 = (argString) => { export const encodeUTF8 = argString => {
return unescape(encodeURIComponent(argString)) return unescape(encodeURIComponent(argString))
} }
@ -186,8 +190,13 @@ export const encodeUTF8 = (argString) => {
* @param {string} dataurl * @param {string} dataurl
* @returns {string} object URL or empty string * @returns {string} object URL or empty string
*/ */
export const dataURLToObjectURL = (dataurl) => { export const dataURLToObjectURL = dataurl => {
if (typeof Uint8Array === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) { if (
typeof Uint8Array === 'undefined' ||
typeof Blob === 'undefined' ||
typeof URL === 'undefined' ||
!URL.createObjectURL
) {
return '' return ''
} }
const arr = dataurl.split(',') const arr = dataurl.split(',')
@ -213,7 +222,7 @@ export const dataURLToObjectURL = (dataurl) => {
* @param {Blob} blob A Blob object or File object * @param {Blob} blob A Blob object or File object
* @returns {string} object URL or empty string * @returns {string} object URL or empty string
*/ */
export const createObjectURL = (blob) => { export const createObjectURL = blob => {
if (!blob || typeof URL === 'undefined' || !URL.createObjectURL) { if (!blob || typeof URL === 'undefined' || !URL.createObjectURL) {
return '' return ''
} }
@ -227,7 +236,10 @@ export const blankPageObjectURL = (() => {
if (typeof Blob === 'undefined') { if (typeof Blob === 'undefined') {
return '' return ''
} }
const blob = new Blob(['<html><head><title>SVG-edit</title></head><body>&nbsp;</body></html>'], { type: 'text/html' }) const blob = new Blob(
['<html><head><title>SVG-edit</title></head><body>&nbsp;</body></html>'],
{ type: 'text/html' }
)
return createObjectURL(blob) return createObjectURL(blob)
})() })()
@ -237,11 +249,11 @@ export const blankPageObjectURL = (() => {
* @param {string} input * @param {string} input
* @returns {string} Decimal numeric character references * @returns {string} Decimal numeric character references
*/ */
export const convertToXMLReferences = (input) => { export const convertToXMLReferences = input => {
let output = ''; let output = ''
[...input].forEach((ch) => { ;[...input].forEach(ch => {
const c = ch.charCodeAt() const c = ch.charCodeAt()
output += (c <= 127) ? ch : `&#${c};` output += c <= 127 ? ch : `&#${c};`
}) })
return output return output
} }
@ -254,12 +266,13 @@ export const convertToXMLReferences = (input) => {
* @throws {Error} * @throws {Error}
* @returns {XMLDocument} * @returns {XMLDocument}
*/ */
export const text2xml = (sXML) => { export const text2xml = sXML => {
if (sXML.includes('<svg:svg')) { if (sXML.includes('<svg:svg')) {
sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns') sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns')
} }
let out; let dXML let out
let dXML
try { try {
dXML = new DOMParser() dXML = new DOMParser()
dXML.async = false dXML.async = false
@ -268,7 +281,9 @@ export const text2xml = (sXML) => {
} }
try { try {
out = dXML.parseFromString(sXML, 'text/xml') out = dXML.parseFromString(sXML, 'text/xml')
} catch (e2) { throw new Error('Error parsing XML string') } } catch (e2) {
throw new Error('Error parsing XML string')
}
return out return out
} }
@ -419,17 +434,23 @@ export const getPathBBox = function (path) {
const getCalc = function (j, P1, P2, P3) { const getCalc = function (j, P1, P2, P3) {
return function (t) { return function (t) {
return 1 - t ** 3 * P0[j] + return (
3 * 1 - t ** 2 * t * P1[j] + 1 -
t ** 3 * P0[j] +
3 * 1 -
t ** 2 * t * P1[j] +
3 * (1 - t) * t ** 2 * P2[j] + 3 * (1 - t) * t ** 2 * P2[j] +
t ** 3 * P3[j] t ** 3 * P3[j]
)
} }
} }
for (let i = 0; i < tot; i++) { for (let i = 0; i < tot; i++) {
const seg = seglist.getItem(i) const seg = seglist.getItem(i)
if (seg.x === undefined) { continue } if (seg.x === undefined) {
continue
}
// Add actual points to limits // Add actual points to limits
bounds[0].push(P0[0]) bounds[0].push(P0[0])
@ -448,7 +469,9 @@ export const getPathBBox = function (path) {
const c = 3 * P1[j] - 3 * P0[j] const c = 3 * P1[j] - 3 * P0[j]
if (a === 0) { if (a === 0) {
if (b === 0) { continue } if (b === 0) {
continue
}
const t = -c / b const t = -c / b
if (t > 0 && t < 1) { if (t > 0 && t < 1) {
bounds[j].push(calc(t)) bounds[j].push(calc(t))
@ -456,11 +479,17 @@ export const getPathBBox = function (path) {
continue continue
} }
const b2ac = b ** 2 - 4 * c * a const b2ac = b ** 2 - 4 * c * a
if (b2ac < 0) { continue } if (b2ac < 0) {
continue
}
const t1 = (-b + Math.sqrt(b2ac)) / (2 * a) const t1 = (-b + Math.sqrt(b2ac)) / (2 * a)
if (t1 > 0 && t1 < 1) { bounds[j].push(calc(t1)) } if (t1 > 0 && t1 < 1) {
bounds[j].push(calc(t1))
}
const t2 = (-b - Math.sqrt(b2ac)) / (2 * a) const t2 = (-b - Math.sqrt(b2ac)) / (2 * a)
if (t2 > 0 && t2 < 1) { bounds[j].push(calc(t2)) } if (t2 > 0 && t2 < 1) {
bounds[j].push(calc(t2))
}
} }
P0 = P3 P0 = P3
} else { } else {
@ -490,7 +519,9 @@ export const getPathBBox = function (path) {
*/ */
export const getBBox = function (elem) { export const getBBox = function (elem) {
const selected = elem || svgCanvas.getSelectedElements()[0] const selected = elem || svgCanvas.getSelectedElements()[0]
if (elem.nodeType !== 1) { return null } if (elem.nodeType !== 1) {
return null
}
const elname = selected.nodeName const elname = selected.nodeName
let ret = null let ret = null
@ -512,7 +543,6 @@ export const getBBox = function (elem) {
} }
break break
default: default:
if (elname === 'use') { if (elname === 'use') {
ret = selected.getBBox() // , true); ret = selected.getBBox() // , true);
} else if (visElemsArr.includes(elname)) { } else if (visElemsArr.includes(elname)) {
@ -568,7 +598,7 @@ export const getPathDFromSegments = function (pathSegments) {
pathSegments.forEach(function ([singleChar, pts], _j) { pathSegments.forEach(function ([singleChar, pts], _j) {
d += singleChar d += singleChar
for (let i = 0; i < pts.length; i += 2) { for (let i = 0; i < pts.length; i += 2) {
d += (pts[i] + ',' + pts[i + 1]) + ' ' d += pts[i] + ',' + pts[i + 1] + ' '
} }
}) })
@ -584,7 +614,9 @@ export const getPathDFromSegments = function (pathSegments) {
export const getPathDFromElement = function (elem) { export const getPathDFromElement = function (elem) {
// Possibly the cubed root of 6, but 1.81 works best // Possibly the cubed root of 6, but 1.81 works best
let num = 1.81 let num = 1.81
let d; let rx; let ry let d
let rx
let ry
switch (elem.tagName) { switch (elem.tagName) {
case 'ellipse': case 'ellipse':
case 'circle': { case 'circle': {
@ -597,18 +629,20 @@ export const getPathDFromElement = function (elem) {
rx = ry rx = ry
} }
d = getPathDFromSegments([ d = getPathDFromSegments([
['M', [(cx - rx), (cy)]], ['M', [cx - rx, cy]],
['C', [(cx - rx), (cy - ry / num), (cx - rx / num), (cy - ry), (cx), (cy - ry)]], ['C', [cx - rx, cy - ry / num, cx - rx / num, cy - ry, cx, cy - ry]],
['C', [(cx + rx / num), (cy - ry), (cx + rx), (cy - ry / num), (cx + rx), (cy)]], ['C', [cx + rx / num, cy - ry, cx + rx, cy - ry / num, cx + rx, cy]],
['C', [(cx + rx), (cy + ry / num), (cx + rx / num), (cy + ry), (cx), (cy + ry)]], ['C', [cx + rx, cy + ry / num, cx + rx / num, cy + ry, cx, cy + ry]],
['C', [(cx - rx / num), (cy + ry), (cx - rx), (cy + ry / num), (cx - rx), (cy)]], ['C', [cx - rx / num, cy + ry, cx - rx, cy + ry / num, cx - rx, cy]],
['Z', []] ['Z', []]
]) ])
break break
} case 'path': }
case 'path':
d = elem.getAttribute('d') d = elem.getAttribute('d')
break break
case 'line': { case 'line':
{
const x1 = elem.getAttribute('x1') const x1 = elem.getAttribute('x1')
const y1 = elem.getAttribute('y1') const y1 = elem.getAttribute('y1')
const x2 = elem.getAttribute('x2') const x2 = elem.getAttribute('x2')
@ -647,14 +681,25 @@ export const getPathDFromElement = function (elem) {
['L', [x + w - rx, y]], ['L', [x + w - rx, y]],
['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]], ['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]],
['L', [x + w, y + h - ry]], ['L', [x + w, y + h - ry]],
['C', [x + w, y + h - ry / num, x + w - rx / num, y + h, x + w - rx, y + h]], [
'C',
[
x + w,
y + h - ry / num,
x + w - rx / num,
y + h,
x + w - rx,
y + h
]
],
['L', [x + rx, y + h]], ['L', [x + rx, y + h]],
['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]], ['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]],
['L', [x, y + ry]], ['L', [x, y + ry]],
['Z', []] ['Z', []]
]) ])
break break
} default: }
default:
break break
} }
@ -668,15 +713,17 @@ export const getPathDFromElement = function (elem) {
* @returns {PlainObject<"marker-start"|"marker-end"|"marker-mid"|"filter"|"clip-path", string>} An object with attributes. * @returns {PlainObject<"marker-start"|"marker-end"|"marker-mid"|"filter"|"clip-path", string>} An object with attributes.
*/ */
export const getExtraAttributesForConvertToPath = function (elem) { export const getExtraAttributesForConvertToPath = function (elem) {
const attrs = {}; const attrs = {}
// TODO: make this list global so that we can properly maintain it // TODO: make this list global so that we can properly maintain it
// TODO: what about @transform, @clip-rule, @fill-rule, etc? // TODO: what about @transform, @clip-rule, @fill-rule, etc?
['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'].forEach(function (item) { ;['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'].forEach(
function (item) {
const a = elem.getAttribute(item) const a = elem.getAttribute(item)
if (a) { if (a) {
attrs[item] = a attrs[item] = a
} }
}) }
)
return attrs return attrs
} }
@ -688,7 +735,11 @@ export const getExtraAttributesForConvertToPath = function (elem) {
* @param {module:path.pathActions} pathActions - If a transform exists, `pathActions.resetOrientation()` is used. See: canvas.pathActions. * @param {module:path.pathActions} pathActions - If a transform exists, `pathActions.resetOrientation()` is used. See: canvas.pathActions.
* @returns {DOMRect|false} The resulting path's bounding box object. * @returns {DOMRect|false} The resulting path's bounding box object.
*/ */
export const getBBoxOfElementAsPath = function (elem, addSVGElementsFromJson, pathActions) { export const getBBoxOfElementAsPath = function (
elem,
addSVGElementsFromJson,
pathActions
) {
const path = addSVGElementsFromJson({ const path = addSVGElementsFromJson({
element: 'path', element: 'path',
attr: getExtraAttributesForConvertToPath(elem) attr: getExtraAttributesForConvertToPath(elem)
@ -777,7 +828,13 @@ export const convertToPath = (elem, attrs, svgCanvas) => {
} }
const { nextSibling } = elem const { nextSibling } = elem
batchCmd.addSubCommand(new svgCanvas.history.RemoveElementCommand(elem, nextSibling, elem.parentNode)) batchCmd.addSubCommand(
new svgCanvas.history.RemoveElementCommand(
elem,
nextSibling,
elem.parentNode
)
)
svgCanvas.clearSelection() svgCanvas.clearSelection()
elem.remove() // We need to remove this element otherwise the nextSibling of 'path' won't be null and an exception will be thrown after subsequent undo and redos. elem.remove() // We need to remove this element otherwise the nextSibling of 'path' won't be null and an exception will be thrown after subsequent undo and redos.
@ -830,7 +887,11 @@ function bBoxCanBeOptimizedOverNativeGetBBox (angle, hasAMatrixTransform) {
* @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions.
* @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object
*/ */
export const getBBoxWithTransform = function (elem, addSVGElementsFromJson, pathActions) { export const getBBoxWithTransform = function (
elem,
addSVGElementsFromJson,
pathActions
) {
// TODO: Fix issue with rotated groups. Currently they work // TODO: Fix issue with rotated groups. Currently they work
// fine in FF, but not in other browsers (same problem mentioned // fine in FF, but not in other browsers (same problem mentioned
// in Issue 339 comment #2). // in Issue 339 comment #2).
@ -852,14 +913,22 @@ export const getBBoxWithTransform = function (elem, addSVGElementsFromJson, path
// TODO: why ellipse and not circle // TODO: why ellipse and not circle
const elemNames = ['ellipse', 'path', 'line', 'polyline', 'polygon'] const elemNames = ['ellipse', 'path', 'line', 'polyline', 'polygon']
if (elemNames.includes(elem.tagName)) { if (elemNames.includes(elem.tagName)) {
goodBb = getBBoxOfElementAsPath(elem, addSVGElementsFromJson, pathActions) goodBb = getBBoxOfElementAsPath(
elem,
addSVGElementsFromJson,
pathActions
)
bb = goodBb bb = goodBb
} else if (elem.tagName === 'rect') { } else if (elem.tagName === 'rect') {
// Look for radius // Look for radius
const rx = Number(elem.getAttribute('rx')) const rx = Number(elem.getAttribute('rx'))
const ry = Number(elem.getAttribute('ry')) const ry = Number(elem.getAttribute('ry'))
if (rx || ry) { if (rx || ry) {
goodBb = getBBoxOfElementAsPath(elem, addSVGElementsFromJson, pathActions) goodBb = getBBoxOfElementAsPath(
elem,
addSVGElementsFromJson,
pathActions
)
bb = goodBb bb = goodBb
} }
} }
@ -879,9 +948,9 @@ export const getBBoxWithTransform = function (elem, addSVGElementsFromJson, path
* @todo This is problematic with large stroke-width and, for example, a single * @todo This is problematic with large stroke-width and, for example, a single
* horizontal line. The calculated BBox extends way beyond left and right sides. * horizontal line. The calculated BBox extends way beyond left and right sides.
*/ */
const getStrokeOffsetForBBox = (elem) => { const getStrokeOffsetForBBox = elem => {
const sw = elem.getAttribute('stroke-width') const sw = elem.getAttribute('stroke-width')
return (!isNaN(sw) && elem.getAttribute('stroke') !== 'none') ? sw / 2 : 0 return !isNaN(sw) && elem.getAttribute('stroke') !== 'none' ? sw / 2 : 0
} }
/** /**
@ -901,17 +970,25 @@ const getStrokeOffsetForBBox = (elem) => {
* @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object
*/ */
export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => { export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => {
if (!elems || !elems.length) { return false } if (!elems || !elems.length) {
return false
}
let fullBb let fullBb
elems.forEach((elem) => { elems.forEach(elem => {
if (fullBb) { return } if (fullBb) {
if (!elem.parentNode) { return } return
}
if (!elem.parentNode) {
return
}
fullBb = getBBoxWithTransform(elem, addSVGElementsFromJson, pathActions) fullBb = getBBoxWithTransform(elem, addSVGElementsFromJson, pathActions)
}) })
// This shouldn't ever happen... // This shouldn't ever happen...
if (!fullBb) { return null } if (!fullBb) {
return null
}
// fullBb doesn't include the stoke, so this does no good! // fullBb doesn't include the stoke, so this does no good!
// if (elems.length == 1) return fullBb; // if (elems.length == 1) return fullBb;
@ -929,8 +1006,12 @@ export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => {
maxX += offset maxX += offset
maxY += offset maxY += offset
} else { } else {
elems.forEach((elem) => { elems.forEach(elem => {
const curBb = getBBoxWithTransform(elem, addSVGElementsFromJson, pathActions) const curBb = getBBoxWithTransform(
elem,
addSVGElementsFromJson,
pathActions
)
if (curBb) { if (curBb) {
const offset = getStrokeOffsetForBBox(elem) const offset = getStrokeOffsetForBBox(elem)
minX = Math.min(minX, curBb.x - offset) minX = Math.min(minX, curBb.x - offset)
@ -944,10 +1025,10 @@ export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => {
}) })
} }
fullBb.x = minX fullBb.x = shortFloat(minX)
fullBb.y = minY fullBb.y = shortFloat(minY)
fullBb.width = maxX - minX fullBb.width = shortFloat(maxX - minX)
fullBb.height = maxY - minY fullBb.height = shortFloat(maxY - minY)
return fullBb return fullBb
} }
@ -959,13 +1040,18 @@ export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => {
* @param {Element} parentElement - The parent DOM element to search within * @param {Element} parentElement - The parent DOM element to search within
* @returns {Element[]} All "visible" elements. * @returns {Element[]} All "visible" elements.
*/ */
export const getVisibleElements = (parentElement) => { export const getVisibleElements = parentElement => {
if (!parentElement) { if (!parentElement) {
const svgContent = svgCanvas.getSvgContent() const svgContent = svgCanvas.getSvgContent()
for (let i = 0; i < svgContent.children.length; i++) { for (let i = 0; i < svgContent.children.length; i++) {
if (svgContent.children[i].getBBox) { if (svgContent.children[i].getBBox) {
const bbox = svgContent.children[i].getBBox() const bbox = svgContent.children[i].getBBox()
if (bbox.width !== 0 && bbox.height !== 0 && bbox.width !== 0 && bbox.height !== 0) { if (
bbox.width !== 0 &&
bbox.height !== 0 &&
bbox.width !== 0 &&
bbox.height !== 0
) {
parentElement = svgContent.children[i] parentElement = svgContent.children[i]
break break
} }
@ -977,7 +1063,7 @@ export const getVisibleElements = (parentElement) => {
if (parentElement) { if (parentElement) {
const children = parentElement.children const children = parentElement.children
// eslint-disable-next-line array-callback-return // eslint-disable-next-line array-callback-return
Array.from(children, (elem) => { Array.from(children, elem => {
if (elem.getBBox) { if (elem.getBBox) {
contentElems.push(elem) contentElems.push(elem)
} }
@ -992,8 +1078,10 @@ export const getVisibleElements = (parentElement) => {
* @param {Element[]} elems - Array with DOM elements to check * @param {Element[]} elems - Array with DOM elements to check
* @returns {module:utilities.BBoxObject} A single bounding box object * @returns {module:utilities.BBoxObject} A single bounding box object
*/ */
export const getStrokedBBoxDefaultVisible = (elems) => { export const getStrokedBBoxDefaultVisible = elems => {
if (!elems) { elems = getVisibleElements() } if (!elems) {
elems = getVisibleElements()
}
return getStrokedBBox( return getStrokedBBox(
elems, elems,
svgCanvas.addSVGElementsFromJson, svgCanvas.addSVGElementsFromJson,
@ -1009,11 +1097,13 @@ export const getStrokedBBoxDefaultVisible = (elems) => {
* @returns {Float} The angle in degrees or radians * @returns {Float} The angle in degrees or radians
*/ */
export const getRotationAngleFromTransformList = (tlist, toRad) => { export const getRotationAngleFromTransformList = (tlist, toRad) => {
if (!tlist) { return 0 } // <svg> element have no tlist if (!tlist) {
return 0
} // <svg> element have no tlist
for (let i = 0; i < tlist.numberOfItems; ++i) { for (let i = 0; i < tlist.numberOfItems; ++i) {
const xform = tlist.getItem(i) const xform = tlist.getItem(i)
if (xform.type === 4) { if (xform.type === 4) {
return toRad ? xform.angle * Math.PI / 180.0 : xform.angle return toRad ? (xform.angle * Math.PI) / 180.0 : xform.angle
} }
} }
return 0.0 return 0.0
@ -1039,7 +1129,7 @@ export let getRotationAngle = (elem, toRad) => {
* @param {string} attrVal - The attribute value as a string * @param {string} attrVal - The attribute value as a string
* @returns {Element} Reference element * @returns {Element} Reference element
*/ */
export const getRefElem = (attrVal) => { export const getRefElem = attrVal => {
return getElement(getUrlFromAttr(attrVal).substr(1)) return getElement(getUrlFromAttr(attrVal).substr(1))
} }
/** /**
@ -1048,7 +1138,7 @@ export const getRefElem = (attrVal) => {
* @param {any} Element * @param {any} Element
* @returns {any} Reference element * @returns {any} Reference element
*/ */
export const getFeGaussianBlur = (ele) => { export const getFeGaussianBlur = ele => {
if (ele?.firstChild?.tagName === 'feGaussianBlur') { if (ele?.firstChild?.tagName === 'feGaussianBlur') {
return ele.firstChild return ele.firstChild
} else { } else {
@ -1069,7 +1159,7 @@ export const getFeGaussianBlur = (ele) => {
* @param {string} id - String with the element's new ID * @param {string} id - String with the element's new ID
* @returns {?Element} * @returns {?Element}
*/ */
export const getElement = (id) => { export const getElement = id => {
// querySelector lookup // querySelector lookup
return svgroot_.querySelector('#' + id) return svgroot_.querySelector('#' + id)
} }
@ -1085,9 +1175,12 @@ export const getElement = (id) => {
*/ */
export const assignAttributes = (elem, attrs, suspendLength, unitCheck) => { export const assignAttributes = (elem, attrs, suspendLength, unitCheck) => {
for (const [key, value] of Object.entries(attrs)) { for (const [key, value] of Object.entries(attrs)) {
const ns = (key.substr(0, 4) === 'xml:' const ns =
key.substr(0, 4) === 'xml:'
? NS.XML ? NS.XML
: key.substr(0, 6) === 'xlink:' ? NS.XLINK : null) : key.substr(0, 6) === 'xlink:'
? NS.XLINK
: null
if (value === undefined) { if (value === undefined) {
if (ns) { if (ns) {
elem.removeAttributeNS(ns, key) elem.removeAttributeNS(ns, key)
@ -1112,7 +1205,7 @@ export const assignAttributes = (elem, attrs, suspendLength, unitCheck) => {
* @param {Element} element - DOM element to clean up * @param {Element} element - DOM element to clean up
* @returns {void} * @returns {void}
*/ */
export const cleanupElement = (element) => { export const cleanupElement = element => {
const defaults = { const defaults = {
'fill-opacity': 1, 'fill-opacity': 1,
'stop-opacity': 1, 'stop-opacity': 1,
@ -1146,7 +1239,7 @@ export const cleanupElement = (element) => {
* @param {Float} value * @param {Float} value
* @returns {Integer} * @returns {Integer}
*/ */
export const snapToGrid = (value) => { export const snapToGrid = value => {
const unit = svgCanvas.getBaseUnit() const unit = svgCanvas.getBaseUnit()
let stepSize = svgCanvas.getSnappingStep() let stepSize = svgCanvas.getSnappingStep()
if (unit !== 'px') { if (unit !== 'px') {
@ -1162,8 +1255,8 @@ export const snapToGrid = (value) => {
* @param {Element} img - The DOM element to prevent the click on * @param {Element} img - The DOM element to prevent the click on
* @returns {void} * @returns {void}
*/ */
export const preventClickDefault = (img) => { export const preventClickDefault = img => {
$click(img, (e) => { $click(img, e => {
e.preventDefault() e.preventDefault()
}) })
} }
@ -1178,7 +1271,7 @@ export const preventClickDefault = (img) => {
* @param {any} val * @param {any} val
* @returns {boolean} * @returns {boolean}
*/ */
export const isNullish = (val) => { export const isNullish = val => {
return val === null || val === undefined return val === null || val === undefined
} }
@ -1192,14 +1285,16 @@ export const isNullish = (val) => {
* @returns {void} * @returns {void}
*/ */
export const mock = ({ export const mock = ({
getHref: getHrefUser, setHref: setHrefUser, getRotationAngle: getRotationAngleUser getHref: getHrefUser,
setHref: setHrefUser,
getRotationAngle: getRotationAngleUser
}) => { }) => {
getHref = getHrefUser getHref = getHrefUser
setHref = setHrefUser setHref = setHrefUser
getRotationAngle = getRotationAngleUser getRotationAngle = getRotationAngleUser
} }
export const stringToHTML = (str) => { export const stringToHTML = str => {
const parser = new DOMParser() const parser = new DOMParser()
const doc = parser.parseFromString(str, 'text/html') const doc = parser.parseFromString(str, 'text/html')
return doc.body.firstChild return doc.body.firstChild
@ -1215,9 +1310,9 @@ export const insertChildAtIndex = (parent, child, index = 0) => {
} }
// shortcuts to common DOM functions // shortcuts to common DOM functions
export const $id = (id) => document.getElementById(id) export const $id = id => document.getElementById(id)
export const $qq = (sel) => document.querySelector(sel) export const $qq = sel => document.querySelector(sel)
export const $qa = (sel) => [...document.querySelectorAll(sel)] export const $qa = sel => [...document.querySelectorAll(sel)]
export const $click = (element, handler) => { export const $click = (element, handler) => {
element.addEventListener('click', handler) element.addEventListener('click', handler)
element.addEventListener('touchend', handler) element.addEventListener('touchend', handler)

View File

@ -232,7 +232,7 @@ class TopPanel {
if (!isNode && currentMode !== 'pathedit') { if (!isNode && currentMode !== 'pathedit') {
this.displayTool('selected_panel') this.displayTool('selected_panel')
// Elements in this array already have coord fields // Elements in this array already have coord fields
if (['line', 'circle', 'ellipse'].includes(elname)) { if (['line', 'circle', 'ellipse', 'polygon'].includes(elname)) {
this.hideTool('xy_panel') this.hideTool('xy_panel')
} else { } else {
let x let x
@ -253,9 +253,23 @@ class TopPanel {
x = convertUnit(x) x = convertUnit(x)
y = convertUnit(y) y = convertUnit(y)
} }
/**
* Updates the value of an input field if needed
* @param {string} id - The ID of the input element to be updated.
* @param {number} newValue - The new numeric value to set in the input field.
*/
const updateValue = (id, newValue) => {
const currentValue = $id(id).value // Get current value from the field
// do nothing if nothing changed...
if (parseFloat(currentValue) === newValue) {
return
}
$id(id).value = newValue
}
updateValue('selected_x', x)
updateValue('selected_y', y)
$id('selected_x').value = x || 0
$id('selected_y').value = y || 0
this.displayTool('xy_panel') this.displayTool('xy_panel')
} }
@ -361,15 +375,12 @@ class TopPanel {
this.displayTool('text_panel') this.displayTool('text_panel')
$id('tool_italic').pressed = this.editor.svgCanvas.getItalic() $id('tool_italic').pressed = this.editor.svgCanvas.getItalic()
$id('tool_bold').pressed = this.editor.svgCanvas.getBold() $id('tool_bold').pressed = this.editor.svgCanvas.getBold()
$id( $id('tool_text_decoration_underline').pressed =
'tool_text_decoration_underline' this.editor.svgCanvas.hasTextDecoration('underline')
).pressed = this.editor.svgCanvas.hasTextDecoration('underline') $id('tool_text_decoration_linethrough').pressed =
$id( this.editor.svgCanvas.hasTextDecoration('line-through')
'tool_text_decoration_linethrough' $id('tool_text_decoration_overline').pressed =
).pressed = this.editor.svgCanvas.hasTextDecoration('line-through') this.editor.svgCanvas.hasTextDecoration('overline')
$id(
'tool_text_decoration_overline'
).pressed = this.editor.svgCanvas.hasTextDecoration('overline')
$id('tool_font_family').value = elem.getAttribute('font-family') $id('tool_font_family').value = elem.getAttribute('font-family')
$id('tool_text_anchor').setAttribute( $id('tool_text_anchor').setAttribute(
'value', 'value',
@ -420,7 +431,7 @@ class TopPanel {
} else if (this.multiselected) { } else if (this.multiselected) {
// Check if all selected elements are 'text' nodes, if yes enable text panel // Check if all selected elements are 'text' nodes, if yes enable text panel
const selElems = this.editor.svgCanvas.getSelectedElements() const selElems = this.editor.svgCanvas.getSelectedElements()
if (selElems.every((elem) => elem.tagName === 'text')) { if (selElems.every(elem => elem.tagName === 'text')) {
this.displayTool('text_panel') this.displayTool('text_panel')
} }
@ -939,15 +950,21 @@ class TopPanel {
$click($id('tool_make_link_multi'), this.makeHyperlink.bind(this)) $click($id('tool_make_link_multi'), this.makeHyperlink.bind(this))
$click($id('tool_reorient'), this.reorientPath.bind(this)) $click($id('tool_reorient'), this.reorientPath.bind(this))
$click($id('tool_group_elements'), this.clickGroup.bind(this)) $click($id('tool_group_elements'), this.clickGroup.bind(this))
$id('tool_position').addEventListener('change', (evt) => this.clickAlignEle.bind(this)(evt)) $id('tool_position').addEventListener('change', evt =>
this.clickAlignEle.bind(this)(evt)
)
$click($id('tool_align_left'), () => this.clickAlign.bind(this)('left')) $click($id('tool_align_left'), () => this.clickAlign.bind(this)('left'))
$click($id('tool_align_right'), () => this.clickAlign.bind(this)('right')) $click($id('tool_align_right'), () => this.clickAlign.bind(this)('right'))
$click($id('tool_align_center'), () => this.clickAlign.bind(this)('center')) $click($id('tool_align_center'), () => this.clickAlign.bind(this)('center'))
$click($id('tool_align_top'), () => this.clickAlign.bind(this)('top')) $click($id('tool_align_top'), () => this.clickAlign.bind(this)('top'))
$click($id('tool_align_bottom'), () => this.clickAlign.bind(this)('bottom')) $click($id('tool_align_bottom'), () => this.clickAlign.bind(this)('bottom'))
$click($id('tool_align_middle'), () => this.clickAlign.bind(this)('middle')) $click($id('tool_align_middle'), () => this.clickAlign.bind(this)('middle'))
$click($id('tool_align_distrib_horiz'), () => this.clickAlign.bind(this)('distrib_horiz')) $click($id('tool_align_distrib_horiz'), () =>
$click($id('tool_align_distrib_verti'), () => this.clickAlign.bind(this)('distrib_verti')) this.clickAlign.bind(this)('distrib_horiz')
)
$click($id('tool_align_distrib_verti'), () =>
this.clickAlign.bind(this)('distrib_verti')
)
$click($id('tool_node_clone'), this.clonePathNode.bind(this)) $click($id('tool_node_clone'), this.clonePathNode.bind(this))
$click($id('tool_node_delete'), this.deletePathNode.bind(this)) $click($id('tool_node_delete'), this.deletePathNode.bind(this))
$click($id('tool_openclose_path'), this.opencloseSubPath.bind(this)) $click($id('tool_openclose_path'), this.opencloseSubPath.bind(this))
@ -960,19 +977,40 @@ class TopPanel {
$click($id('tool_ungroup'), this.clickGroup.bind(this)) $click($id('tool_ungroup'), this.clickGroup.bind(this))
$click($id('tool_bold'), this.clickBold.bind(this)) $click($id('tool_bold'), this.clickBold.bind(this))
$click($id('tool_italic'), this.clickItalic.bind(this)) $click($id('tool_italic'), this.clickItalic.bind(this))
$click($id('tool_text_decoration_underline'), () => this.clickTextDecoration.bind(this)('underline')) $click($id('tool_text_decoration_underline'), () =>
$click($id('tool_text_decoration_linethrough'), () => this.clickTextDecoration.bind(this)('line-through')) this.clickTextDecoration.bind(this)('underline')
$click($id('tool_text_decoration_overline'), () => this.clickTextDecoration.bind(this)('overline')) )
$id('tool_text_anchor').addEventListener('change', (evt) => this.clickTextAnchor.bind(this)(evt)) $click($id('tool_text_decoration_linethrough'), () =>
$id('tool_letter_spacing').addEventListener('change', this.changeLetterSpacing.bind(this)) this.clickTextDecoration.bind(this)('line-through')
$id('tool_word_spacing').addEventListener('change', this.changeWordSpacing.bind(this)) )
$id('tool_text_length').addEventListener('change', this.changeTextLength.bind(this)) $click($id('tool_text_decoration_overline'), () =>
$id('tool_length_adjust').addEventListener('change', (evt) => this.changeLengthAdjust.bind(this)(evt)) this.clickTextDecoration.bind(this)('overline')
)
$id('tool_text_anchor').addEventListener('change', evt =>
this.clickTextAnchor.bind(this)(evt)
)
$id('tool_letter_spacing').addEventListener(
'change',
this.changeLetterSpacing.bind(this)
)
$id('tool_word_spacing').addEventListener(
'change',
this.changeWordSpacing.bind(this)
)
$id('tool_text_length').addEventListener(
'change',
this.changeTextLength.bind(this)
)
$id('tool_length_adjust').addEventListener('change', evt =>
this.changeLengthAdjust.bind(this)(evt)
)
$click($id('tool_unlink_use'), this.clickGroup.bind(this)) $click($id('tool_unlink_use'), this.clickGroup.bind(this))
$id('image_url').addEventListener('change', (evt) => { this.setImageURL(evt.currentTarget.value) }); $id('image_url').addEventListener('change', evt => {
this.setImageURL(evt.currentTarget.value)
})
// all top panel attributes // all top panel attributes
[ ;[
'elem_id', 'elem_id',
'elem_class', 'elem_class',
'circle_cx', 'circle_cx',