Fix text scale #1008 (#1010)

* update dependencies

* fix #1008 by adjusting font-size

(allowing to keep the text keep his proportions to the font)

* refactor math.js
This commit is contained in:
JFH
2024-12-27 21:37:05 +01:00
committed by GitHub
parent f0549e4629
commit 403237c182
18 changed files with 810 additions and 521 deletions

View File

@@ -1,71 +1,73 @@
{"total": {"lines":{"total":6677,"covered":3923,"skipped":0,"pct":58.75},"statements":{"total":6981,"covered":4034,"skipped":0,"pct":57.78},"functions":{"total":1001,"covered":524,"skipped":0,"pct":52.34},"branches":{"total":3421,"covered":1412,"skipped":0,"pct":41.27},"branchesTrue":{"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/jean-francoishenon/Work/svgedit/packages/svgcanvas/common/util.js": {"lines":{"total":90,"covered":8,"skipped":0,"pct":8.88},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.85},"statements":{"total":92,"covered":10,"skipped":0,"pct":10.86},"branches":{"total":98,"covered":10,"skipped":0,"pct":10.2}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/ConfigObj.js": {"lines":{"total":101,"covered":39,"skipped":0,"pct":38.61},"functions":{"total":14,"covered":9,"skipped":0,"pct":64.28},"statements":{"total":102,"covered":39,"skipped":0,"pct":38.23},"branches":{"total":96,"covered":25,"skipped":0,"pct":26.04}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/Editor.js": {"lines":{"total":414,"covered":192,"skipped":0,"pct":46.37},"functions":{"total":103,"covered":31,"skipped":0,"pct":30.09},"statements":{"total":420,"covered":193,"skipped":0,"pct":45.95},"branches":{"total":213,"covered":75,"skipped":0,"pct":35.21}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/EditorStartup.js": {"lines":{"total":383,"covered":237,"skipped":0,"pct":61.87},"functions":{"total":57,"covered":31,"skipped":0,"pct":54.38},"statements":{"total":395,"covered":246,"skipped":0,"pct":62.27},"branches":{"total":147,"covered":51,"skipped":0,"pct":34.69}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/MainMenu.js": {"lines":{"total":101,"covered":44,"skipped":0,"pct":43.56},"functions":{"total":14,"covered":7,"skipped":0,"pct":50},"statements":{"total":101,"covered":44,"skipped":0,"pct":43.56},"branches":{"total":44,"covered":7,"skipped":0,"pct":15.9}}
,"/Users/jean-francoishenon/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.41}}
,"/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/jean-francoishenon/Work/svgedit/src/editor/contextmenu.js": {"lines":{"total":22,"covered":9,"skipped":0,"pct":40.9},"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/locale.js": {"lines":{"total":14,"covered":9,"skipped":0,"pct":64.28},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":14,"covered":9,"skipped":0,"pct":64.28},"branches":{"total":10,"covered":3,"skipped":0,"pct":30}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/PaintBox.js": {"lines":{"total":64,"covered":51,"skipped":0,"pct":79.68},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":67,"covered":53,"skipped":0,"pct":79.1},"branches":{"total":33,"covered":20,"skipped":0,"pct":60.6}}
,"/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/jean-francoishenon/Work/svgedit/src/editor/components/seButton.js": {"lines":{"total":57,"covered":41,"skipped":0,"pct":71.92},"functions":{"total":15,"covered":8,"skipped":0,"pct":53.33},"statements":{"total":60,"covered":43,"skipped":0,"pct":71.66},"branches":{"total":33,"covered":23,"skipped":0,"pct":69.69}}
,"/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.72}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seExplorerButton.js": {"lines":{"total":99,"covered":76,"skipped":0,"pct":76.76},"functions":{"total":18,"covered":11,"skipped":0,"pct":61.11},"statements":{"total":102,"covered":76,"skipped":0,"pct":74.5},"branches":{"total":30,"covered":17,"skipped":0,"pct":56.66}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seFlyingButton.js": {"lines":{"total":77,"covered":50,"skipped":0,"pct":64.93},"functions":{"total":15,"covered":11,"skipped":0,"pct":73.33},"statements":{"total":78,"covered":51,"skipped":0,"pct":65.38},"branches":{"total":31,"covered":13,"skipped":0,"pct":41.93}}
,"/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.95},"branches":{"total":8,"covered":4,"skipped":0,"pct":50}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seList.js": {"lines":{"total":87,"covered":59,"skipped":0,"pct":67.81},"functions":{"total":21,"covered":10,"skipped":0,"pct":47.61},"statements":{"total":89,"covered":61,"skipped":0,"pct":68.53},"branches":{"total":22,"covered":12,"skipped":0,"pct":54.54}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seListItem.js": {"lines":{"total":39,"covered":26,"skipped":0,"pct":66.66},"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/seMenu.js": {"lines":{"total":26,"covered":20,"skipped":0,"pct":76.92},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.85},"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/seMenuItem.js": {"lines":{"total":37,"covered":26,"skipped":0,"pct":70.27},"functions":{"total":9,"covered":5,"skipped":0,"pct":55.55},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":21,"covered":8,"skipped":0,"pct":38.09}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/sePalette.js": {"lines":{"total":53,"covered":44,"skipped":0,"pct":83.01},"functions":{"total":11,"covered":9,"skipped":0,"pct":81.81},"statements":{"total":53,"covered":44,"skipped":0,"pct":83.01},"branches":{"total":15,"covered":10,"skipped":0,"pct":66.66}}
,"/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/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/jean-francoishenon/Work/svgedit/src/editor/components/seSelect.js": {"lines":{"total":56,"covered":45,"skipped":0,"pct":80.35},"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/seSpinInput.js": {"lines":{"total":65,"covered":55,"skipped":0,"pct":84.61},"functions":{"total":18,"covered":10,"skipped":0,"pct":55.55},"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/seText.js": {"lines":{"total":28,"covered":18,"skipped":0,"pct":64.28},"functions":{"total":10,"covered":4,"skipped":0,"pct":40},"statements":{"total":29,"covered":18,"skipped":0,"pct":62.06},"branches":{"total":8,"covered":5,"skipped":0,"pct":62.5}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/seZoom.js": {"lines":{"total":102,"covered":93,"skipped":0,"pct":91.17},"functions":{"total":28,"covered":24,"skipped":0,"pct":85.71},"statements":{"total":107,"covered":97,"skipped":0,"pct":90.65},"branches":{"total":36,"covered":21,"skipped":0,"pct":58.33}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/components/jgraduate/ColorValuePicker.js": {"lines":{"total":231,"covered":54,"skipped":0,"pct":23.37},"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.65}}
,"/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.54},"branches":{"total":186,"covered":97,"skipped":0,"pct":52.15}}
,"/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.81},"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.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.29},"branches":{"total":777,"covered":327,"skipped":0,"pct":42.08}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/SePlainAlertDialog.js": {"lines":{"total":12,"covered":2,"skipped":0,"pct":16.66},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":2,"skipped":0,"pct":16.66},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}}
,"/Users/jean-francoishenon/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.6}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/cmenuLayersDialog.js": {"lines":{"total":61,"covered":49,"skipped":0,"pct":80.32},"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/editorPreferencesDialog.js": {"lines":{"total":157,"covered":125,"skipped":0,"pct":79.61},"functions":{"total":30,"covered":9,"skipped":0,"pct":30},"statements":{"total":159,"covered":126,"skipped":0,"pct":79.24},"branches":{"total":46,"covered":35,"skipped":0,"pct":76.08}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/dialogs/exportDialog.js": {"lines":{"total":52,"covered":36,"skipped":0,"pct":69.23},"functions":{"total":14,"covered":5,"skipped":0,"pct":35.71},"statements":{"total":55,"covered":36,"skipped":0,"pct":65.45},"branches":{"total":11,"covered":5,"skipped":0,"pct":45.45}}
,"/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.55},"branches":{"total":53,"covered":23,"skipped":0,"pct":43.39}}
,"/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/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/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":4,"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/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/jean-francoishenon/Work/svgedit/src/editor/dialogs/svgSourceDialog.js": {"lines":{"total":74,"covered":56,"skipped":0,"pct":75.67},"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/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/src/base/NumberSpinBox.js": {"lines":{"total":54,"covered":51,"skipped":0,"pct":94.44},"functions":{"total":13,"covered":11,"skipped":0,"pct":84.61},"statements":{"total":54,"covered":51,"skipped":0,"pct":94.44},"branches":{"total":53,"covered":46,"skipped":0,"pct":86.79}}
,"/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/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-connector/ext-connector.js": {"lines":{"total":287,"covered":84,"skipped":0,"pct":29.26},"functions":{"total":26,"covered":16,"skipped":0,"pct":61.53},"statements":{"total":295,"covered":87,"skipped":0,"pct":29.49},"branches":{"total":140,"covered":21,"skipped":0,"pct":15}}
,"/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/jean-francoishenon/Work/svgedit/src/editor/extensions/ext-eyedropper/ext-eyedropper.js": {"lines":{"total":99,"covered":57,"skipped":0,"pct":57.57},"functions":{"total":16,"covered":11,"skipped":0,"pct":68.75},"statements":{"total":109,"covered":58,"skipped":0,"pct":53.21},"branches":{"total":65,"covered":19,"skipped":0,"pct":29.23}}
,"/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/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.77},"branches":{"total":10,"covered":4,"skipped":0,"pct":40}}
,"/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/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.26},"branches":{"total":80,"covered":22,"skipped":0,"pct":27.5}}
,"/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.07},"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-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-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-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-polystar/ext-polystar.js": {"lines":{"total":247,"covered":232,"skipped":0,"pct":93.92},"functions":{"total":18,"covered":16,"skipped":0,"pct":88.88},"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-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-shapes/ext-shapes.js": {"lines":{"total":76,"covered":74,"skipped":0,"pct":97.36},"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-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-storage/ext-storage.js": {"lines":{"total":91,"covered":37,"skipped":0,"pct":40.65},"functions":{"total":12,"covered":5,"skipped":0,"pct":41.66},"statements":{"total":91,"covered":37,"skipped":0,"pct":40.65},"branches":{"total":68,"covered":16,"skipped":0,"pct":23.52}}
,"/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.93},"branches":{"total":15,"covered":13,"skipped":0,"pct":86.66}}
,"/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/jean-francoishenon/Work/svgedit/src/editor/panels/BottomPanel.js": {"lines":{"total":77,"covered":61,"skipped":0,"pct":79.22},"functions":{"total":22,"covered":14,"skipped":0,"pct":63.63},"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/panels/LayersPanel.js": {"lines":{"total":162,"covered":75,"skipped":0,"pct":46.29},"functions":{"total":27,"covered":6,"skipped":0,"pct":22.22},"statements":{"total":168,"covered":76,"skipped":0,"pct":45.23},"branches":{"total":46,"covered":6,"skipped":0,"pct":13.04}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/LeftPanel.js": {"lines":{"total":57,"covered":46,"skipped":0,"pct":80.7},"functions":{"total":20,"covered":15,"skipped":0,"pct":75},"statements":{"total":58,"covered":46,"skipped":0,"pct":79.31},"branches":{"total":32,"covered":12,"skipped":0,"pct":37.5}}
,"/Users/jean-francoishenon/Work/svgedit/src/editor/panels/TopPanel.js": {"lines":{"total":409,"covered":313,"skipped":0,"pct":76.52},"functions":{"total":76,"covered":52,"skipped":0,"pct":68.42},"statements":{"total":421,"covered":316,"skipped":0,"pct":75.05},"branches":{"total":209,"covered":127,"skipped":0,"pct":60.76}}
{"total": {"lines":{"total":6724,"covered":3944,"skipped":0,"pct":58.65},"statements":{"total":7028,"covered":4055,"skipped":0,"pct":57.69},"functions":{"total":1009,"covered":529,"skipped":0,"pct":52.42},"branches":{"total":3434,"covered":1414,"skipped":0,"pct":41.17},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/packages/svgcanvas/common/util.js": {"lines":{"total":90,"covered":8,"skipped":0,"pct":8.88},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.85},"statements":{"total":92,"covered":10,"skipped":0,"pct":10.86},"branches":{"total":98,"covered":10,"skipped":0,"pct":10.2}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/ConfigObj.js": {"lines":{"total":101,"covered":39,"skipped":0,"pct":38.61},"functions":{"total":14,"covered":9,"skipped":0,"pct":64.28},"statements":{"total":102,"covered":39,"skipped":0,"pct":38.23},"branches":{"total":95,"covered":25,"skipped":0,"pct":26.31}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/Editor.js": {"lines":{"total":414,"covered":192,"skipped":0,"pct":46.37},"functions":{"total":103,"covered":31,"skipped":0,"pct":30.09},"statements":{"total":420,"covered":193,"skipped":0,"pct":45.95},"branches":{"total":213,"covered":75,"skipped":0,"pct":35.21}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/EditorStartup.js": {"lines":{"total":383,"covered":237,"skipped":0,"pct":61.87},"functions":{"total":57,"covered":31,"skipped":0,"pct":54.38},"statements":{"total":395,"covered":246,"skipped":0,"pct":62.27},"branches":{"total":147,"covered":51,"skipped":0,"pct":34.69}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/MainMenu.js": {"lines":{"total":101,"covered":44,"skipped":0,"pct":43.56},"functions":{"total":14,"covered":7,"skipped":0,"pct":50},"statements":{"total":101,"covered":44,"skipped":0,"pct":43.56},"branches":{"total":44,"covered":7,"skipped":0,"pct":15.9}}
,"/Users/jfh/Documents/GitHub/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.41}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/contextmenu.js": {"lines":{"total":22,"covered":9,"skipped":0,"pct":40.9},"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/jfh/Documents/GitHub/svgedit/src/editor/locale.js": {"lines":{"total":14,"covered":9,"skipped":0,"pct":64.28},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":14,"covered":9,"skipped":0,"pct":64.28},"branches":{"total":10,"covered":3,"skipped":0,"pct":30}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/PaintBox.js": {"lines":{"total":64,"covered":51,"skipped":0,"pct":79.68},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":67,"covered":53,"skipped":0,"pct":79.1},"branches":{"total":33,"covered":20,"skipped":0,"pct":60.6}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/components/seButton.js": {"lines":{"total":57,"covered":42,"skipped":0,"pct":73.68},"functions":{"total":15,"covered":9,"skipped":0,"pct":60},"statements":{"total":60,"covered":44,"skipped":0,"pct":73.33},"branches":{"total":33,"covered":23,"skipped":0,"pct":69.69}}
,"/Users/jfh/Documents/GitHub/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.72}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seExplorerButton.js": {"lines":{"total":99,"covered":76,"skipped":0,"pct":76.76},"functions":{"total":18,"covered":11,"skipped":0,"pct":61.11},"statements":{"total":102,"covered":76,"skipped":0,"pct":74.5},"branches":{"total":30,"covered":17,"skipped":0,"pct":56.66}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seFlyingButton.js": {"lines":{"total":77,"covered":50,"skipped":0,"pct":64.93},"functions":{"total":15,"covered":11,"skipped":0,"pct":73.33},"statements":{"total":78,"covered":51,"skipped":0,"pct":65.38},"branches":{"total":31,"covered":13,"skipped":0,"pct":41.93}}
,"/Users/jfh/Documents/GitHub/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.95},"branches":{"total":8,"covered":4,"skipped":0,"pct":50}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seList.js": {"lines":{"total":87,"covered":59,"skipped":0,"pct":67.81},"functions":{"total":21,"covered":10,"skipped":0,"pct":47.61},"statements":{"total":89,"covered":61,"skipped":0,"pct":68.53},"branches":{"total":22,"covered":12,"skipped":0,"pct":54.54}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seListItem.js": {"lines":{"total":39,"covered":26,"skipped":0,"pct":66.66},"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/jfh/Documents/GitHub/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.85},"statements":{"total":27,"covered":20,"skipped":0,"pct":74.07},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}}
,"/Users/jfh/Documents/GitHub/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.55},"statements":{"total":40,"covered":27,"skipped":0,"pct":67.5},"branches":{"total":21,"covered":8,"skipped":0,"pct":38.09}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/sePalette.js": {"lines":{"total":53,"covered":44,"skipped":0,"pct":83.01},"functions":{"total":11,"covered":9,"skipped":0,"pct":81.81},"statements":{"total":53,"covered":44,"skipped":0,"pct":83.01},"branches":{"total":15,"covered":10,"skipped":0,"pct":66.66}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/components/seSelect.js": {"lines":{"total":56,"covered":45,"skipped":0,"pct":80.35},"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/jfh/Documents/GitHub/svgedit/src/editor/components/seSpinInput.js": {"lines":{"total":65,"covered":55,"skipped":0,"pct":84.61},"functions":{"total":18,"covered":10,"skipped":0,"pct":55.55},"statements":{"total":66,"covered":55,"skipped":0,"pct":83.33},"branches":{"total":17,"covered":13,"skipped":0,"pct":76.47}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seText.js": {"lines":{"total":28,"covered":18,"skipped":0,"pct":64.28},"functions":{"total":10,"covered":4,"skipped":0,"pct":40},"statements":{"total":29,"covered":18,"skipped":0,"pct":62.06},"branches":{"total":8,"covered":5,"skipped":0,"pct":62.5}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/seZoom.js": {"lines":{"total":102,"covered":94,"skipped":0,"pct":92.15},"functions":{"total":28,"covered":25,"skipped":0,"pct":89.28},"statements":{"total":107,"covered":98,"skipped":0,"pct":91.58},"branches":{"total":36,"covered":22,"skipped":0,"pct":61.11}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/components/jgraduate/ColorValuePicker.js": {"lines":{"total":231,"covered":54,"skipped":0,"pct":23.37},"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.65}}
,"/Users/jfh/Documents/GitHub/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.54},"branches":{"total":186,"covered":97,"skipped":0,"pct":52.15}}
,"/Users/jfh/Documents/GitHub/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.81},"statements":{"total":602,"covered":282,"skipped":0,"pct":46.84},"branches":{"total":278,"covered":100,"skipped":0,"pct":35.97}}
,"/Users/jfh/Documents/GitHub/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.29},"branches":{"total":777,"covered":327,"skipped":0,"pct":42.08}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/dialogs/SePlainAlertDialog.js": {"lines":{"total":12,"covered":2,"skipped":0,"pct":16.66},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":12,"covered":2,"skipped":0,"pct":16.66},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfh/Documents/GitHub/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.6}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/dialogs/cmenuLayersDialog.js": {"lines":{"total":61,"covered":49,"skipped":0,"pct":80.32},"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/jfh/Documents/GitHub/svgedit/src/editor/dialogs/editorPreferencesDialog.js": {"lines":{"total":157,"covered":125,"skipped":0,"pct":79.61},"functions":{"total":30,"covered":9,"skipped":0,"pct":30},"statements":{"total":159,"covered":126,"skipped":0,"pct":79.24},"branches":{"total":46,"covered":35,"skipped":0,"pct":76.08}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/dialogs/exportDialog.js": {"lines":{"total":52,"covered":36,"skipped":0,"pct":69.23},"functions":{"total":14,"covered":5,"skipped":0,"pct":35.71},"statements":{"total":55,"covered":36,"skipped":0,"pct":65.45},"branches":{"total":11,"covered":5,"skipped":0,"pct":45.45}}
,"/Users/jfh/Documents/GitHub/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.55},"branches":{"total":53,"covered":23,"skipped":0,"pct":43.39}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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":4,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/dialogs/svgSourceDialog.js": {"lines":{"total":74,"covered":56,"skipped":0,"pct":75.67},"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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/dialogs/se-elix/src/base/NumberSpinBox.js": {"lines":{"total":54,"covered":51,"skipped":0,"pct":94.44},"functions":{"total":13,"covered":11,"skipped":0,"pct":84.61},"statements":{"total":54,"covered":51,"skipped":0,"pct":94.44},"branches":{"total":53,"covered":46,"skipped":0,"pct":86.79}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-connector/ext-connector.js": {"lines":{"total":287,"covered":84,"skipped":0,"pct":29.26},"functions":{"total":26,"covered":16,"skipped":0,"pct":61.53},"statements":{"total":295,"covered":87,"skipped":0,"pct":29.49},"branches":{"total":140,"covered":21,"skipped":0,"pct":15}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-eyedropper/ext-eyedropper.js": {"lines":{"total":99,"covered":57,"skipped":0,"pct":57.57},"functions":{"total":16,"covered":11,"skipped":0,"pct":68.75},"statements":{"total":109,"covered":58,"skipped":0,"pct":53.21},"branches":{"total":65,"covered":19,"skipped":0,"pct":29.23}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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.77},"branches":{"total":10,"covered":4,"skipped":0,"pct":40}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-layer_view/ext-layer_view.js": {"lines":{"total":43,"covered":21,"skipped":0,"pct":48.83},"functions":{"total":8,"covered":4,"skipped":0,"pct":50},"statements":{"total":43,"covered":21,"skipped":0,"pct":48.83},"branches":{"total":14,"covered":2,"skipped":0,"pct":14.28}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-layer_view/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/jfh/Documents/GitHub/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.26},"branches":{"total":80,"covered":22,"skipped":0,"pct":27.5}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-opensave/ext-opensave.js": {"lines":{"total":137,"covered":36,"skipped":0,"pct":26.27},"functions":{"total":13,"covered":3,"skipped":0,"pct":23.07},"statements":{"total":142,"covered":36,"skipped":0,"pct":25.35},"branches":{"total":32,"covered":0,"skipped":0,"pct":0}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-polystar/ext-polystar.js": {"lines":{"total":247,"covered":232,"skipped":0,"pct":93.92},"functions":{"total":18,"covered":16,"skipped":0,"pct":88.88},"statements":{"total":256,"covered":241,"skipped":0,"pct":94.14},"branches":{"total":62,"covered":39,"skipped":0,"pct":62.9}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-shapes/ext-shapes.js": {"lines":{"total":76,"covered":74,"skipped":0,"pct":97.36},"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/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/extensions/ext-storage/ext-storage.js": {"lines":{"total":91,"covered":37,"skipped":0,"pct":40.65},"functions":{"total":12,"covered":5,"skipped":0,"pct":41.66},"statements":{"total":91,"covered":37,"skipped":0,"pct":40.65},"branches":{"total":68,"covered":16,"skipped":0,"pct":23.52}}
,"/Users/jfh/Documents/GitHub/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.93},"branches":{"total":15,"covered":13,"skipped":0,"pct":86.66}}
,"/Users/jfh/Documents/GitHub/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/jfh/Documents/GitHub/svgedit/src/editor/panels/BottomPanel.js": {"lines":{"total":77,"covered":61,"skipped":0,"pct":79.22},"functions":{"total":22,"covered":14,"skipped":0,"pct":63.63},"statements":{"total":77,"covered":61,"skipped":0,"pct":79.22},"branches":{"total":30,"covered":16,"skipped":0,"pct":53.33}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/panels/LayersPanel.js": {"lines":{"total":165,"covered":76,"skipped":0,"pct":46.06},"functions":{"total":27,"covered":6,"skipped":0,"pct":22.22},"statements":{"total":171,"covered":77,"skipped":0,"pct":45.02},"branches":{"total":46,"covered":6,"skipped":0,"pct":13.04}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/panels/LeftPanel.js": {"lines":{"total":57,"covered":46,"skipped":0,"pct":80.7},"functions":{"total":20,"covered":15,"skipped":0,"pct":75},"statements":{"total":58,"covered":46,"skipped":0,"pct":79.31},"branches":{"total":32,"covered":12,"skipped":0,"pct":37.5}}
,"/Users/jfh/Documents/GitHub/svgedit/src/editor/panels/TopPanel.js": {"lines":{"total":409,"covered":310,"skipped":0,"pct":75.79},"functions":{"total":76,"covered":51,"skipped":0,"pct":67.1},"statements":{"total":421,"covered":313,"skipped":0,"pct":74.34},"branches":{"total":209,"covered":126,"skipped":0,"pct":60.28}}
}

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="24" font-style="italic" font-weight="bold" id="svg_1" stroke="#000000" stroke-width="0" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="220" xml:space="preserve" y="220">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="220" xml:space="preserve" y="220">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 574 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_1" stroke="#000000" stroke-width="0" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="220" xml:space="preserve" y="220">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="220" xml:space="preserve" y="220">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 503 B

After

Width:  |  Height:  |  Size: 503 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="24" font-style="italic" id="svg_1" stroke="#000000" stroke-width="0" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="220" xml:space="preserve" y="220">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="220" xml:space="preserve" y="220">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 555 B

After

Width:  |  Height:  |  Size: 555 B

View File

@@ -2,7 +2,7 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#bf0000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#0000bf" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="24" id="svg_2" opacity="0.5" stroke="#000000" stroke-width="0" text-anchor="middle" x="620" xml:space="preserve" y="250">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="20" id="svg_2" opacity="0.5" stroke="#000000" stroke-width="0" text-anchor="middle" x="630" xml:space="preserve" y="250">AB</text>
</g>
<defs>
<filter height="200%" id="svg_2_blur" width="200%" x="-50%" y="-50%">

Before

Width:  |  Height:  |  Size: 755 B

After

Width:  |  Height:  |  Size: 755 B

View File

@@ -2,7 +2,7 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#bf0000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#0000bf" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
</g>
<defs>
<filter height="200%" id="svg_2_blur" width="200%" x="-50%" y="-50%">

Before

Width:  |  Height:  |  Size: 741 B

After

Width:  |  Height:  |  Size: 741 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#000000" stroke-width="0" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 574 B

View File

@@ -2,7 +2,7 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#bf0000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#0000bf" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="24" id="svg_2" opacity="0.5" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" filter="url(#svg_2_blur)" font-family="Serif" font-size="20" id="svg_2" opacity="0.5" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
</g>
<defs>
<filter height="200%" id="svg_2_blur" width="200%" x="-50%" y="-50%">

Before

Width:  |  Height:  |  Size: 755 B

After

Width:  |  Height:  |  Size: 755 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#bf0000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#0000bf" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 557 B

After

Width:  |  Height:  |  Size: 557 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="34" font-style="italic" font-weight="bold" id="svg_1" stroke="#000000" text-anchor="middle" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="245" xml:space="preserve" y="245">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 557 B

After

Width:  |  Height:  |  Size: 557 B

View File

@@ -2,6 +2,6 @@
<g class="layer">
<title>Layer 1</title>
<text fill="#000000" font-family="Serif" font-size="24" font-style="italic" font-weight="bold" id="svg_1" stroke="#000000" stroke-width="0" text-anchor="middle" transform="matrix(1 0 0 1 0 0)" x="200" xml:space="preserve" y="200">AB</text>
<text fill="#000000" font-family="Serif" font-size="24" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
<text fill="#000000" font-family="Serif" font-size="20" id="svg_2" stroke="#000000" stroke-width="0" text-anchor="middle" x="245" xml:space="preserve" y="245">AB</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 574 B

View File

@@ -4,103 +4,317 @@ import * as math from '../../../packages/svgcanvas/core/math.js'
describe('math', function () {
const svg = document.createElementNS(NS.SVG, 'svg')
it('Test svgedit.math package', function () {
assert.ok(math)
assert.ok(math.transformPoint)
assert.ok(math.isIdentity)
assert.ok(math.matrixMultiply)
assert.equal(typeof math.transformPoint, typeof function () { /* empty fn */ })
assert.equal(typeof math.isIdentity, typeof function () { /* empty fn */ })
assert.equal(typeof math.matrixMultiply, typeof function () { /* empty fn */ })
before(() => {
// Ensure the SVG element is attached to the document for transform list tests
document.body.appendChild(svg)
})
after(() => {
// Cleanup
document.body.removeChild(svg)
})
it('Test svgedit.math package exports', function () {
assert.ok(math, 'math module should exist')
const expectedFunctions = [
'transformPoint',
'getTransformList',
'isIdentity',
'matrixMultiply',
'hasMatrixTransform',
'transformBox',
'transformListToTransform',
'getMatrix',
'snapToAngle',
'rectsIntersect'
]
expectedFunctions.forEach(fn => {
assert.ok(
typeof math[fn] === 'function',
`Expected "${fn}" to be a function`
)
})
})
it('Test svgedit.math.transformPoint() function', function () {
const { transformPoint } = math
const m = svg.createSVGMatrix()
m.a = 1; m.b = 0
m.c = 0; m.d = 1
m.e = 0; m.f = 0
m.a = 1
m.b = 0
m.c = 0
m.d = 1
m.e = 0
m.f = 0
let pt = transformPoint(100, 200, m)
assert.equal(pt.x, 100)
assert.equal(pt.y, 200)
assert.equal(pt.x, 100, 'X should be unchanged by identity matrix')
assert.equal(pt.y, 200, 'Y should be unchanged by identity matrix')
m.e = 300; m.f = 400
m.e = 300
m.f = 400
pt = transformPoint(100, 200, m)
assert.equal(pt.x, 400)
assert.equal(pt.y, 600)
assert.equal(pt.x, 400, 'X should be translated by 300')
assert.equal(pt.y, 600, 'Y should be translated by 400')
m.a = 0.5; m.b = 0.75
m.c = 1.25; m.d = 2
m.a = 0.5
m.b = 0.75
m.c = 1.25
m.d = 2
pt = transformPoint(100, 200, m)
assert.equal(pt.x, 100 * m.a + 200 * m.c + m.e)
assert.equal(pt.y, 100 * m.b + 200 * m.d + m.f)
assert.equal(
pt.x,
100 * m.a + 200 * m.c + m.e,
'X should match matrix multiplication'
)
assert.equal(
pt.y,
100 * m.b + 200 * m.d + m.f,
'Y should match matrix multiplication'
)
})
it('Test svgedit.math.isIdentity() function', function () {
assert.ok(math.isIdentity(svg.createSVGMatrix()))
const { isIdentity } = math
assert.ok(
isIdentity(svg.createSVGMatrix()),
'Default matrix should be identity'
)
const m = svg.createSVGMatrix()
m.a = 1; m.b = 0
m.c = 0; m.d = 1
m.e = 0; m.f = 0
assert.ok(math.isIdentity(m))
m.a = 1
m.b = 0
m.c = 0
m.d = 1
m.e = 0
m.f = 0
assert.ok(
isIdentity(m),
'Modified matrix matching identity values should be identity'
)
m.e = 10
assert.notOk(isIdentity(m), 'Matrix with translation is not identity')
})
it('Test svgedit.math.matrixMultiply() function', function () {
const mult = math.matrixMultiply
const { isIdentity } = math
const { matrixMultiply, isIdentity } = math
// translate there and back
// Test empty arguments
const iDefault = matrixMultiply()
assert.ok(
isIdentity(iDefault),
'No arguments should return identity matrix'
)
// Translate there and back
const tr1 = svg.createSVGMatrix().translate(100, 50)
const tr2 = svg.createSVGMatrix().translate(-90, 0)
const tr3 = svg.createSVGMatrix().translate(-10, -50)
let I = mult(tr1, tr2, tr3)
assert.ok(isIdentity(I), 'Expected identity matrix when translating there and back')
let I = matrixMultiply(tr1, tr2, tr3)
assert.ok(isIdentity(I), 'Translating there and back should yield identity')
// rotate there and back
// TODO: currently Mozilla fails this when rotating back at -50 and then -40 degrees
// (b and c are *almost* zero, but not zero)
// Rotate there and back
const rotThere = svg.createSVGMatrix().rotate(90)
const rotBack = svg.createSVGMatrix().rotate(-90) // TODO: set this to -50
const rotBackMore = svg.createSVGMatrix().rotate(0) // TODO: set this to -40
I = mult(rotThere, rotBack, rotBackMore)
assert.ok(isIdentity(I), 'Expected identity matrix when rotating there and back')
const rotBack = svg.createSVGMatrix().rotate(-90)
I = matrixMultiply(rotThere, rotBack)
assert.ok(isIdentity(I), 'Rotating and rotating back should yield identity')
// scale up and down
// Scale up and down
const scaleUp = svg.createSVGMatrix().scale(4)
const scaleDown = svg.createSVGMatrix().scaleNonUniform(0.25, 1)
const scaleDownMore = svg.createSVGMatrix().scaleNonUniform(1, 0.25)
I = mult(scaleUp, scaleDown, scaleDownMore)
assert.ok(isIdentity(I), 'Expected identity matrix when scaling up and down')
const scaleDownX = svg.createSVGMatrix().scaleNonUniform(0.25, 1)
const scaleDownY = svg.createSVGMatrix().scaleNonUniform(1, 0.25)
I = matrixMultiply(scaleUp, scaleDownX, scaleDownY)
assert.ok(
isIdentity(I),
'Scaling up and then scaling down back to original should yield identity'
)
// test multiplication with its inverse
I = mult(rotThere, rotThere.inverse())
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse')
I = mult(rotThere.inverse(), rotThere)
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse')
// Multiplying a matrix by its inverse
const someMatrix = svg
.createSVGMatrix()
.rotate(33)
.translate(100, 200)
.scale(2)
I = matrixMultiply(someMatrix, someMatrix.inverse())
cy.log(I)
cy.log('-----------------------------------------')
assert.ok(
isIdentity(I),
'Matrix multiplied by its inverse should be identity'
)
})
it('Test svgedit.math.transformBox() function', function () {
const { transformBox } = math
const m = svg.createSVGMatrix()
m.a = 1; m.b = 0
m.c = 0; m.d = 1
m.e = 0; m.f = 0
// Identity
const r = transformBox(10, 10, 200, 300, m)
assert.equal(r.tl.x, 10)
assert.equal(r.tl.y, 10)
assert.equal(r.tr.x, 210)
assert.equal(r.tr.y, 10)
assert.equal(r.bl.x, 10)
assert.equal(r.bl.y, 310)
assert.equal(r.br.x, 210)
assert.equal(r.br.y, 310)
assert.equal(r.aabox.x, 10)
assert.equal(r.aabox.y, 10)
assert.equal(r.aabox.width, 200)
assert.equal(r.aabox.height, 300)
assert.equal(r.tl.x, 10, 'Top-left X should be 10')
assert.equal(r.tl.y, 10, 'Top-left Y should be 10')
assert.equal(r.tr.x, 210, 'Top-right X should be 210')
assert.equal(r.tr.y, 10, 'Top-right Y should be 10')
assert.equal(r.bl.x, 10, 'Bottom-left X should be 10')
assert.equal(r.bl.y, 310, 'Bottom-left Y should be 310')
assert.equal(r.br.x, 210, 'Bottom-right X should be 210')
assert.equal(r.br.y, 310, 'Bottom-right Y should be 310')
assert.equal(r.aabox.x, 10, 'AABBox X should be 10')
assert.equal(r.aabox.y, 10, 'AABBox Y should be 10')
assert.equal(r.aabox.width, 200, 'AABBox width should be 200')
assert.equal(r.aabox.height, 300, 'AABBox height should be 300')
// Transformed box
m.e = 50
m.f = 50
const r2 = transformBox(0, 0, 100, 100, m)
assert.equal(r2.aabox.x, 50, 'AABBox x should be translated by 50')
assert.equal(r2.aabox.y, 50, 'AABBox y should be translated by 50')
})
it('Test svgedit.math.getTransformList() and hasMatrixTransform() functions', function () {
const { getTransformList, hasMatrixTransform } = math
// An element with no transform
const rect = document.createElementNS(NS.SVG, 'rect')
svg.appendChild(rect)
const tlist = getTransformList(rect)
assert.ok(tlist, 'Should get a transform list (empty)')
assert.equal(tlist.numberOfItems, 0, 'Transform list should be empty')
assert.notOk(
hasMatrixTransform(tlist),
'No matrix transform in an empty transform list'
)
// Add a non-identity matrix transform
const nonIdentityMatrix = svg.createSVGMatrix().translate(10, 20).scale(2)
const tf = svg.createSVGTransformFromMatrix(nonIdentityMatrix)
tlist.appendItem(tf)
assert.equal(tlist.numberOfItems, 1, 'Transform list should have one item')
assert.ok(
hasMatrixTransform(tlist),
'Non-identity matrix transform should be detected'
)
// Add an identity transform
const tfIdentity = svg.createSVGTransformFromMatrix(svg.createSVGMatrix()) // identity matrix
tlist.appendItem(tfIdentity)
assert.equal(
tlist.numberOfItems,
2,
'Transform list should have two items now'
)
// Still should have a non-identity matrix transform present
assert.ok(
hasMatrixTransform(tlist),
'Still have a non-identity matrix transform after adding an identity transform'
)
// Cleanup
svg.removeChild(rect)
})
it('Test svgedit.math.transformListToTransform() and getMatrix() functions', function () {
const { transformListToTransform, getMatrix } = math
const g = document.createElementNS(NS.SVG, 'g')
svg.appendChild(g)
const tlist = g.transform.baseVal
const m1 = svg.createSVGTransformFromMatrix(
svg.createSVGMatrix().translate(10, 20)
)
const m2 = svg.createSVGTransformFromMatrix(
svg.createSVGMatrix().rotate(45)
)
tlist.appendItem(m1)
tlist.appendItem(m2)
const consolidated = transformListToTransform(tlist)
const expected = m1.matrix.multiply(m2.matrix)
assert.equal(
consolidated.matrix.a,
expected.a,
'Consolidated matrix a should match expected'
)
assert.equal(
consolidated.matrix.d,
expected.d,
'Consolidated matrix d should match expected'
)
const elemMatrix = getMatrix(g)
assert.equal(
elemMatrix.a,
expected.a,
'Element matrix a should match expected'
)
assert.equal(
elemMatrix.d,
expected.d,
'Element matrix d should match expected'
)
svg.removeChild(g)
})
it('Test svgedit.math.snapToAngle() function', function () {
const { snapToAngle } = math
const result = snapToAngle(0, 0, 10, 0) // Expect snap to 0 degrees
assert.equal(
result.x,
10,
'Snapped x should remain 10 when angle is already at 0°'
)
assert.equal(
result.y,
0,
'Snapped y should remain 0 when angle is already at 0°'
)
// 45-degree snap from an angle close to 45° (e.g., 50°)
const angleDegrees = 50
const angleRadians = angleDegrees * (Math.PI / 180)
const dx = Math.cos(angleRadians) * 100
const dy = Math.sin(angleRadians) * 100
const snapped = snapToAngle(0, 0, dx, dy)
// Should snap to exactly 45°
const expectedAngle = Math.PI / 4
const dist = Math.hypot(dx, dy)
assert.closeTo(
snapped.x,
dist * Math.cos(expectedAngle),
0.00001,
'X should be close to 45° projection'
)
assert.closeTo(
snapped.y,
dist * Math.sin(expectedAngle),
0.00001,
'Y should be close to 45° projection'
)
})
it('Test svgedit.math.rectsIntersect() function', function () {
const { rectsIntersect } = math
const r1 = { x: 0, y: 0, width: 50, height: 50 }
const r2 = { x: 25, y: 25, width: 50, height: 50 }
const r3 = { x: 100, y: 100, width: 10, height: 10 }
assert.ok(rectsIntersect(r1, r2), 'Rectangles overlapping should intersect')
assert.notOk(
rectsIntersect(r1, r3),
'Non-overlapping rectangles should not intersect'
)
// Edge case: touching edges
const r4 = { x: 50, y: 0, width: 50, height: 50 }
// Note: Depending on interpretation, touching at the border might be considered intersecting or not.
// The given function checks strict overlapping (not just touching), so this should return false.
assert.notOk(
rectsIntersect(r1, r4),
'Rectangles touching at the edge should not be considered intersecting'
)
})
})

201
package-lock.json generated
View File

@@ -17,7 +17,7 @@
"browser-fs-access": "0.35.0",
"core-js": "3.39.0",
"elix": "15.0.1",
"i18next": "23.16.5",
"i18next": "24.0.5",
"jspdf": "2.5.2",
"pathseg": "1.2.1",
"regenerator-runtime": "0.14.1",
@@ -29,7 +29,7 @@
"@babel/preset-env": "7.26.0",
"@babel/register": "7.25.9",
"@babel/runtime-corejs3": "7.26.0",
"@cypress/code-coverage": "3.13.6",
"@cypress/code-coverage": "3.13.8",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "^28",
"@rollup/plugin-dynamic-import-vars": "2.1.5",
@@ -43,7 +43,7 @@
"babel-plugin-transform-object-rest-spread": "7.0.0-beta.3",
"core-js-bundle": "3.39.0",
"cp-cli": "2.0.0",
"cypress": "13.15.2",
"cypress": "13.16.1",
"cypress-multi-reporters": "2.0.4",
"jamilih": "0.60.0",
"jsdoc": "4.0.4",
@@ -57,7 +57,7 @@
"remark-cli": "12.0.1",
"remark-lint-ordered-list-marker-value": "4.0.0",
"rimraf": "6.0.1",
"rollup": "4.25.0",
"rollup": "4.28.1",
"rollup-plugin-copy": "3.5.0",
"rollup-plugin-filesize": "10.0.0",
"rollup-plugin-html": "0.2.1",
@@ -70,7 +70,7 @@
"node": ">=20"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.25.0"
"@rollup/rollup-linux-x64-gnu": "4.28.1"
}
},
"node_modules/@ampproject/remapping": {
@@ -1789,9 +1789,9 @@
}
},
"node_modules/@cypress/code-coverage": {
"version": "3.13.6",
"resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.13.6.tgz",
"integrity": "sha512-nNVDYDK6r9zPqDIv9k7FibPP9/dATGRR3us9Ued/ldcxPz5x8WbVthjV5OIjqotRKEmS7wxiXFHSDhKJqaZNuw==",
"version": "3.13.8",
"resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.13.8.tgz",
"integrity": "sha512-liUtYL42nbEUkMKtB8H2sudI7gREeKNSTO1VbvFRjiRxj+2hurEkxgbVB8fmjm10iQrDeiX6XGEIL2IefcdC0A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3359,9 +3359,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.25.0.tgz",
"integrity": "sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz",
"integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==",
"cpu": [
"arm"
],
@@ -3373,9 +3373,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.25.0.tgz",
"integrity": "sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz",
"integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==",
"cpu": [
"arm64"
],
@@ -3387,9 +3387,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.25.0.tgz",
"integrity": "sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz",
"integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==",
"cpu": [
"arm64"
],
@@ -3401,9 +3401,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.25.0.tgz",
"integrity": "sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz",
"integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==",
"cpu": [
"x64"
],
@@ -3415,9 +3415,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.25.0.tgz",
"integrity": "sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz",
"integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==",
"cpu": [
"arm64"
],
@@ -3429,9 +3429,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.25.0.tgz",
"integrity": "sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz",
"integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==",
"cpu": [
"x64"
],
@@ -3443,9 +3443,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.25.0.tgz",
"integrity": "sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz",
"integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==",
"cpu": [
"arm"
],
@@ -3457,9 +3457,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.25.0.tgz",
"integrity": "sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz",
"integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==",
"cpu": [
"arm"
],
@@ -3471,9 +3471,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.25.0.tgz",
"integrity": "sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz",
"integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==",
"cpu": [
"arm64"
],
@@ -3485,9 +3485,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.25.0.tgz",
"integrity": "sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz",
"integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==",
"cpu": [
"arm64"
],
@@ -3498,10 +3498,24 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz",
"integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.25.0.tgz",
"integrity": "sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz",
"integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==",
"cpu": [
"ppc64"
],
@@ -3513,9 +3527,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.25.0.tgz",
"integrity": "sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz",
"integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==",
"cpu": [
"riscv64"
],
@@ -3527,9 +3541,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.25.0.tgz",
"integrity": "sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz",
"integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==",
"cpu": [
"s390x"
],
@@ -3541,9 +3555,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.25.0.tgz",
"integrity": "sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz",
"integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==",
"cpu": [
"x64"
],
@@ -3554,9 +3568,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.25.0.tgz",
"integrity": "sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz",
"integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==",
"cpu": [
"x64"
],
@@ -3568,9 +3582,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.25.0.tgz",
"integrity": "sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz",
"integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==",
"cpu": [
"arm64"
],
@@ -3582,9 +3596,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.25.0.tgz",
"integrity": "sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz",
"integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==",
"cpu": [
"ia32"
],
@@ -3596,9 +3610,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.25.0.tgz",
"integrity": "sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz",
"integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==",
"cpu": [
"x64"
],
@@ -6484,9 +6498,9 @@
}
},
"node_modules/cypress": {
"version": "13.15.2",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.2.tgz",
"integrity": "sha512-ARbnUorjcCM3XiPwgHKuqsyr5W9Qn+pIIBPaoilnoBkLdSC2oLQjV1BUpnmc7KR+b7Avah3Ly2RMFnfxr96E/A==",
"version": "13.16.1",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.1.tgz",
"integrity": "sha512-17FtCaz0cx7ssWYKXzGB0Vub8xHwpVPr+iPt2fHhLMDhVAPVrplD+rTQsZUsfb19LVBn5iwkEUFjQ1yVVJXsLA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -9094,9 +9108,9 @@
}
},
"node_modules/i18next": {
"version": "23.16.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.5.tgz",
"integrity": "sha512-KTlhE3EP9x6pPTAW7dy0WKIhoCpfOGhRQlO+jttQLgzVaoOjWwBWramu7Pp0i+8wDNduuzXfe3kkVbzrKyrbTA==",
"version": "24.0.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.0.5.tgz",
"integrity": "sha512-1jSdEzgFPGLZRsQwydoMFCBBaV+PmrVEO5WhANllZPX4y2JSGTxUjJ+xVklHIsiS95uR8gYc/y0hYZWevucNjg==",
"funding": [
{
"type": "individual",
@@ -9114,6 +9128,14 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.2"
},
"peerDependencies": {
"typescript": "^5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/iconv-lite": {
@@ -14892,9 +14914,9 @@
}
},
"node_modules/rollup": {
"version": "4.25.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz",
"integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz",
"integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -14908,24 +14930,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.25.0",
"@rollup/rollup-android-arm64": "4.25.0",
"@rollup/rollup-darwin-arm64": "4.25.0",
"@rollup/rollup-darwin-x64": "4.25.0",
"@rollup/rollup-freebsd-arm64": "4.25.0",
"@rollup/rollup-freebsd-x64": "4.25.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.25.0",
"@rollup/rollup-linux-arm-musleabihf": "4.25.0",
"@rollup/rollup-linux-arm64-gnu": "4.25.0",
"@rollup/rollup-linux-arm64-musl": "4.25.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.25.0",
"@rollup/rollup-linux-riscv64-gnu": "4.25.0",
"@rollup/rollup-linux-s390x-gnu": "4.25.0",
"@rollup/rollup-linux-x64-gnu": "4.25.0",
"@rollup/rollup-linux-x64-musl": "4.25.0",
"@rollup/rollup-win32-arm64-msvc": "4.25.0",
"@rollup/rollup-win32-ia32-msvc": "4.25.0",
"@rollup/rollup-win32-x64-msvc": "4.25.0",
"@rollup/rollup-android-arm-eabi": "4.28.1",
"@rollup/rollup-android-arm64": "4.28.1",
"@rollup/rollup-darwin-arm64": "4.28.1",
"@rollup/rollup-darwin-x64": "4.28.1",
"@rollup/rollup-freebsd-arm64": "4.28.1",
"@rollup/rollup-freebsd-x64": "4.28.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.28.1",
"@rollup/rollup-linux-arm-musleabihf": "4.28.1",
"@rollup/rollup-linux-arm64-gnu": "4.28.1",
"@rollup/rollup-linux-arm64-musl": "4.28.1",
"@rollup/rollup-linux-loongarch64-gnu": "4.28.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.28.1",
"@rollup/rollup-linux-riscv64-gnu": "4.28.1",
"@rollup/rollup-linux-s390x-gnu": "4.28.1",
"@rollup/rollup-linux-x64-gnu": "4.28.1",
"@rollup/rollup-linux-x64-musl": "4.28.1",
"@rollup/rollup-win32-arm64-msvc": "4.28.1",
"@rollup/rollup-win32-ia32-msvc": "4.28.1",
"@rollup/rollup-win32-x64-msvc": "4.28.1",
"fsevents": "~2.3.2"
}
},

View File

@@ -89,7 +89,7 @@
"browser-fs-access": "0.35.0",
"core-js": "3.39.0",
"elix": "15.0.1",
"i18next": "23.16.5",
"i18next": "24.0.5",
"jspdf": "2.5.2",
"pathseg": "1.2.1",
"regenerator-runtime": "0.14.1",
@@ -101,7 +101,7 @@
"@babel/preset-env": "7.26.0",
"@babel/register": "7.25.9",
"@babel/runtime-corejs3": "7.26.0",
"@cypress/code-coverage": "3.13.6",
"@cypress/code-coverage": "3.13.8",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "^28",
"@rollup/plugin-dynamic-import-vars": "2.1.5",
@@ -115,7 +115,7 @@
"babel-plugin-transform-object-rest-spread": "7.0.0-beta.3",
"core-js-bundle": "3.39.0",
"cp-cli": "2.0.0",
"cypress": "13.15.2",
"cypress": "13.16.1",
"cypress-multi-reporters": "2.0.4",
"jamilih": "0.60.0",
"jsdoc": "4.0.4",
@@ -129,7 +129,7 @@
"remark-cli": "12.0.1",
"remark-lint-ordered-list-marker-value": "4.0.0",
"rimraf": "6.0.1",
"rollup": "4.25.0",
"rollup": "4.28.1",
"rollup-plugin-copy": "3.5.0",
"rollup-plugin-filesize": "10.0.0",
"rollup-plugin-html": "0.2.1",
@@ -139,6 +139,6 @@
"start-server-and-test": "2.0.8"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.25.0"
"@rollup/rollup-linux-x64-gnu": "4.28.1"
}
}

View File

@@ -124,7 +124,7 @@ export const remapElement = (selected, changes, m) => {
case 'image': {
// Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix
// Convert to matrix if flipped
const chlist = getTransformList(selected)
const mt = svgCanvas.getSvgRoot().createSVGTransform()
mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m))
@@ -177,6 +177,19 @@ export const remapElement = (selected, changes, m) => {
const pt = remap(changes.x, changes.y)
changes.x = pt.x
changes.y = pt.y
// Scale font-size
let fontSize = selected.getAttribute('font-size')
if (!fontSize) {
// If not directly set, try computed style
fontSize = window.getComputedStyle(selected).fontSize
}
const fontSizeNum = parseFloat(fontSize)
if (!isNaN(fontSizeNum)) {
// Assume uniform scaling and use m.a
changes['font-size'] = fontSizeNum * Math.abs(m.a)
}
finishUp()
// Handle child 'tspan' elements
@@ -197,7 +210,17 @@ export const remapElement = (selected, changes, m) => {
const childPtY = remap(changes.x, childY).y
childChanges.y = childPtY
}
if (hasX || hasY) {
let tspanFS = child.getAttribute('font-size')
if (!tspanFS) {
tspanFS = window.getComputedStyle(child).fontSize
}
const tspanFSNum = parseFloat(tspanFS)
if (!isNaN(tspanFSNum)) {
childChanges['font-size'] = tspanFSNum * Math.abs(m.a)
}
if (hasX || hasY || childChanges['font-size']) {
assignAttributes(child, childChanges, 1000, true)
}
}
@@ -208,6 +231,17 @@ export const remapElement = (selected, changes, m) => {
const pt = remap(changes.x, changes.y)
changes.x = pt.x
changes.y = pt.y
// Handle tspan font-size scaling
let tspanFS = selected.getAttribute('font-size')
if (!tspanFS) {
tspanFS = window.getComputedStyle(selected).fontSize
}
const tspanFSNum = parseFloat(tspanFS)
if (!isNaN(tspanFSNum)) {
changes['font-size'] = tspanFSNum * Math.abs(m.a)
}
finishUp()
break
}

View File

@@ -570,6 +570,7 @@ const mouseOutEvent = () => {
* @returns {void}
*/
const mouseUpEvent = (evt) => {
evt.preventDefault()
moveSelectionThresholdReached = false
if (evt.button === 2) { return }
if (!svgCanvas.getStarted()) { return }

View File

@@ -3,117 +3,111 @@
* @module math
* @license MIT
*
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
* ©2010 Alexis Deveria, ©2010 Jeff Schiller
*/
/**
* @typedef {PlainObject} module:math.AngleCoord45
* @property {Float} x - The angle-snapped x value
* @property {Float} y - The angle-snapped y value
* @property {Integer} a - The angle at which to snap
* @typedef {Object} AngleCoord45
* @property {number} x - The angle-snapped x value
* @property {number} y - The angle-snapped y value
* @property {number} a - The angle (in radians) at which to snap
*/
/**
* @typedef {PlainObject} module:math.XYObject
* @property {Float} x
* @property {Float} y
* @typedef {Object} XYObject
* @property {number} x
* @property {number} y
*/
import { NS } from './namespaces.js'
// Constants
const NEAR_ZERO = 1e-14
const NEAR_ZERO = 1e-10
// Throw away SVGSVGElement used for creating matrices/transforms.
// Create a throwaway SVG element for matrix operations
const svg = document.createElementNS(NS.SVG, 'svg')
/**
* A (hopefully) quicker function to transform a point by a matrix
* (this function avoids any DOM calls and just does the math).
* @function module:math.transformPoint
* @param {Float} x - Float representing the x coordinate
* @param {Float} y - Float representing the y coordinate
* @param {SVGMatrix} m - Matrix object to transform the point with
* @returns {module:math.XYObject} An x, y object representing the transformed point
* Transforms a point by a given matrix without DOM calls.
* @function transformPoint
* @param {number} x - The x coordinate
* @param {number} y - The y coordinate
* @param {SVGMatrix} m - The transformation matrix
* @returns {XYObject} The transformed point
*/
export const transformPoint = function (x, y, m) {
return { x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f }
}
export const transformPoint = (x, y, m) => ({
x: m.a * x + m.c * y + m.e,
y: m.b * x + m.d * y + m.f
})
export const getTransformList = (elem) => {
if (elem.transform) {
return elem.transform?.baseVal
/**
* Gets the transform list (baseVal) from an element if it exists.
* @function getTransformList
* @param {Element} elem - An SVG element or element with a transform list
* @returns {SVGTransformList|undefined} The transform list, if any
*/
export const getTransformList = elem => {
if (elem.transform?.baseVal) {
return elem.transform.baseVal
}
if (elem.gradientTransform) {
return elem.gradientTransform?.baseVal
if (elem.gradientTransform?.baseVal) {
return elem.gradientTransform.baseVal
}
if (elem.patternTransform) {
return elem.patternTransform?.baseVal
if (elem.patternTransform?.baseVal) {
return elem.patternTransform.baseVal
}
console.warn('no transform list found - check browser version', elem)
console.warn('No transform list found. Check browser compatibility.', elem)
}
/**
* Helper function to check if the matrix performs no actual transform
* (i.e. exists for identity purposes).
* @function module:math.isIdentity
* @param {SVGMatrix} m - The matrix object to check
* @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0
* Checks if a matrix is the identity matrix.
* @function isIdentity
* @param {SVGMatrix} m - The matrix to check
* @returns {boolean} True if it's an identity matrix (1,0,0,1,0,0)
*/
export const isIdentity = function (m) {
return (
m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0
)
}
export const isIdentity = m =>
m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0
/**
* This function tries to return a `SVGMatrix` that is the multiplication `m1 * m2`.
* We also round to zero when it's near zero.
* @function module:math.matrixMultiply
* @param {...SVGMatrix} args - Matrix objects to multiply
* @returns {SVGMatrix} The matrix object resulting from the calculation
* Multiplies multiple matrices together (m1 * m2 * ...).
* Near-zero values are rounded to zero.
* @function matrixMultiply
* @param {...SVGMatrix} args - The matrices to multiply
* @returns {SVGMatrix} The resulting matrix
*/
export const matrixMultiply = function (...args) {
const m = args.reduceRight((prev, m1) => {
return m1.multiply(prev)
})
export const matrixMultiply = (...args) => {
// If no matrices are given, return an identity matrix
if (args.length === 0) {
return svg.createSVGMatrix()
}
if (Math.abs(m.a) < NEAR_ZERO) {
m.a = 0
}
if (Math.abs(m.b) < NEAR_ZERO) {
m.b = 0
}
if (Math.abs(m.c) < NEAR_ZERO) {
m.c = 0
}
if (Math.abs(m.d) < NEAR_ZERO) {
m.d = 0
}
if (Math.abs(m.e) < NEAR_ZERO) {
m.e = 0
}
if (Math.abs(m.f) < NEAR_ZERO) {
m.f = 0
}
const m = args.reduceRight((prev, curr) => curr.multiply(prev))
// Round near-zero values to zero
if (Math.abs(m.a) < NEAR_ZERO) m.a = 0
if (Math.abs(m.b) < NEAR_ZERO) m.b = 0
if (Math.abs(m.c) < NEAR_ZERO) m.c = 0
if (Math.abs(m.d) < NEAR_ZERO) m.d = 0
if (Math.abs(m.e) < NEAR_ZERO) m.e = 0
if (Math.abs(m.f) < NEAR_ZERO) m.f = 0
return m
}
/**
* See if the given transformlist includes a non-indentity matrix transform.
* @function module:math.hasMatrixTransform
* @param {SVGTransformList} [tlist] - The transformlist to check
* @returns {boolean} Whether or not a matrix transform was found
* Checks if a transform list includes a non-identity matrix transform.
* @function hasMatrixTransform
* @param {SVGTransformList} [tlist] - The transform list to check
* @returns {boolean} True if a matrix transform is found
*/
export const hasMatrixTransform = function (tlist) {
if (!tlist) {
return false
}
let num = tlist.numberOfItems
while (num--) {
const xform = tlist.getItem(num)
if (xform.type === 1 && !isIdentity(xform.matrix)) {
export const hasMatrixTransform = tlist => {
if (!tlist) return false
for (let i = 0; i < tlist.numberOfItems; i++) {
const xform = tlist.getItem(i)
if (
xform.type === SVGTransform.SVG_TRANSFORM_MATRIX &&
!isIdentity(xform.matrix)
) {
return true
}
}
@@ -121,29 +115,29 @@ export const hasMatrixTransform = function (tlist) {
}
/**
* @typedef {PlainObject} module:math.TransformedBox An object with the following values
* @property {module:math.XYObject} tl - The top left coordinate
* @property {module:math.XYObject} tr - The top right coordinate
* @property {module:math.XYObject} bl - The bottom left coordinate
* @property {module:math.XYObject} br - The bottom right coordinate
* @property {PlainObject} aabox - Object with the following values:
* @property {Float} aabox.x - Float with the axis-aligned x coordinate
* @property {Float} aabox.y - Float with the axis-aligned y coordinate
* @property {Float} aabox.width - Float with the axis-aligned width coordinate
* @property {Float} aabox.height - Float with the axis-aligned height coordinate
* @typedef {Object} TransformedBox
* @property {XYObject} tl - Top-left coordinate
* @property {XYObject} tr - Top-right coordinate
* @property {XYObject} bl - Bottom-left coordinate
* @property {XYObject} br - Bottom-right coordinate
* @property {Object} aabox
* @property {number} aabox.x - Axis-aligned x
* @property {number} aabox.y - Axis-aligned y
* @property {number} aabox.width - Axis-aligned width
* @property {number} aabox.height - Axis-aligned height
*/
/**
* Transforms a rectangle based on the given matrix.
* @function module:math.transformBox
* @param {Float} l - Float with the box's left coordinate
* @param {Float} t - Float with the box's top coordinate
* @param {Float} w - Float with the box width
* @param {Float} h - Float with the box height
* @param {SVGMatrix} m - Matrix object to transform the box by
* @returns {module:math.TransformedBox}
* Transforms a rectangular box using a given matrix.
* @function transformBox
* @param {number} l - Left coordinate
* @param {number} t - Top coordinate
* @param {number} w - Width
* @param {number} h - Height
* @param {SVGMatrix} m - Transformation matrix
* @returns {TransformedBox} The transformed box information
*/
export const transformBox = function (l, t, w, h, m) {
export const transformBox = (l, t, w, h, m) => {
const tl = transformPoint(l, t, m)
const tr = transformPoint(l + w, t, m)
const bl = transformPoint(l, t + h, m)
@@ -169,91 +163,81 @@ export const transformBox = function (l, t, w, h, m) {
}
/**
* This returns a single matrix Transform for a given Transform List
* (this is the equivalent of `SVGTransformList.consolidate()` but unlike
* that method, this one does not modify the actual `SVGTransformList`).
* This function is very liberal with its `min`, `max` arguments.
* @function module:math.transformListToTransform
* @param {SVGTransformList} tlist - The transformlist object
* @param {Integer} [min=0] - Optional integer indicating start transform position
* @param {Integer} [max] - Optional integer indicating end transform position;
* defaults to one less than the tlist's `numberOfItems`
* @returns {SVGTransform} A single matrix transform object
* Consolidates a transform list into a single matrix transform without modifying the original list.
* @function transformListToTransform
* @param {SVGTransformList} tlist - The transform list
* @param {number} [min=0] - Optional start index
* @param {number} [max] - Optional end index, defaults to tlist length-1
* @returns {SVGTransform} A single transform from the combined matrices
*/
export const transformListToTransform = function (tlist, min, max) {
export const transformListToTransform = (tlist, min = 0, max = null) => {
if (!tlist) {
// Or should tlist = null have been prevented before this?
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix())
}
min = min || 0
max = max || tlist.numberOfItems - 1
min = Number.parseInt(min)
max = Number.parseInt(max)
if (min > max) {
const temp = max
max = min
min = temp
}
let m = svg.createSVGMatrix()
for (let i = min; i <= max; ++i) {
// if our indices are out of range, just use a harmless identity matrix
const mtom =
const start = Number.parseInt(min, 10)
const end = Number.parseInt(max ?? tlist.numberOfItems - 1, 10)
const low = Math.min(start, end)
const high = Math.max(start, end)
let combinedMatrix = svg.createSVGMatrix()
for (let i = low; i <= high; i++) {
// If out of range, use identity
const currentMatrix =
i >= 0 && i < tlist.numberOfItems
? tlist.getItem(i).matrix
: svg.createSVGMatrix()
m = matrixMultiply(m, mtom)
combinedMatrix = matrixMultiply(combinedMatrix, currentMatrix)
}
return svg.createSVGTransformFromMatrix(m)
return svg.createSVGTransformFromMatrix(combinedMatrix)
}
/**
* Get the matrix object for a given element.
* @function module:math.getMatrix
* @param {Element} elem - The DOM element to check
* @returns {SVGMatrix} The matrix object associated with the element's transformlist
* Gets the matrix of a given element's transform list.
* @function getMatrix
* @param {Element} elem - The element to check
* @returns {SVGMatrix} The transformation matrix
*/
export const getMatrix = (elem) => {
export const getMatrix = elem => {
const tlist = getTransformList(elem)
return transformListToTransform(tlist).matrix
}
/**
* Returns a 45 degree angle coordinate associated with the two given
* coordinates.
* @function module:math.snapToAngle
* @param {Integer} x1 - First coordinate's x value
* @param {Integer} y1 - First coordinate's y value
* @param {Integer} x2 - Second coordinate's x value
* @param {Integer} y2 - Second coordinate's y value
* @returns {module:math.AngleCoord45}
* Returns a coordinate snapped to the nearest 45-degree angle.
* @function snapToAngle
* @param {number} x1 - First point's x
* @param {number} y1 - First point's y
* @param {number} x2 - Second point's x
* @param {number} y2 - Second point's y
* @returns {AngleCoord45} The angle-snapped coordinates and angle
*/
export const snapToAngle = (x1, y1, x2, y2) => {
const snap = Math.PI / 4 // 45 degrees
const dx = x2 - x1
const dy = y2 - y1
const angle = Math.atan2(dy, dx)
const dist = Math.sqrt(dx * dx + dy * dy)
const snapangle = Math.round(angle / snap) * snap
const dist = Math.hypot(dx, dy)
const snapAngle = Math.round(angle / snap) * snap
return {
x: x1 + dist * Math.cos(snapangle),
y: y1 + dist * Math.sin(snapangle),
a: snapangle
x: x1 + dist * Math.cos(snapAngle),
y: y1 + dist * Math.sin(snapAngle),
a: snapAngle
}
}
/**
* Check if two rectangles (BBoxes objects) intersect each other.
* @function module:math.rectsIntersect
* @param {SVGRect} r1 - The first BBox-like object
* @param {SVGRect} r2 - The second BBox-like object
* @returns {boolean} True if rectangles intersect
* Checks if two rectangles intersect.
* Both r1 and r2 are expected to have {x, y, width, height}.
* @function rectsIntersect
* @param {{x:number,y:number,width:number,height:number}} r1 - First rectangle
* @param {{x:number,y:number,width:number,height:number}} r2 - Second rectangle
* @returns {boolean} True if the rectangles intersect
*/
export const rectsIntersect = (r1, r2) => {
return (
r2.x < r1.x + r1.width &&
r2.x + r2.width > r1.x &&
r2.y < r1.y + r1.height &&
r2.y + r2.height > r1.y
)
}
export const rectsIntersect = (r1, r2) =>
r2.x < r1.x + r1.width &&
r2.x + r2.width > r1.x &&
r2.y < r1.y + r1.height &&
r2.y + r2.height > r1.y

View File

@@ -6,33 +6,31 @@
*/
import { NS } from './namespaces.js'
import { transformPoint, getMatrix } from './math.js'
import {
transformPoint, getMatrix
} from './math.js'
import {
assignAttributes, getElement, getBBox as utilsGetBBox
assignAttributes,
getElement,
getBBox as utilsGetBBox
} from './utilities.js'
import {
supportsGoodTextCharPos
} from '../common/browser.js'
import { supportsGoodTextCharPos } from '../common/browser.js'
let svgCanvas = null
/**
* @function module:text-actions.init
* @param {module:text-actions.svgCanvas} textActionsContext
* @returns {void}
*/
export const init = (canvas) => {
* @function module:text-actions.init
* @param {module:text-actions.svgCanvas} textActionsContext
* @returns {void}
*/
export const init = canvas => {
svgCanvas = canvas
}
/**
* Group: Text edit functions
* Functions relating to editing text elements.
* @namespace {PlainObject} textActions
* @memberof module:svgcanvas.SvgCanvas#
*/
* Group: Text edit functions
* Functions relating to editing text elements.
* @namespace {PlainObject} textActions
* @memberof module:svgcanvas.SvgCanvas#
*/
export const textActionsMethod = (function () {
let curtext
let textinput
@@ -42,23 +40,26 @@ export const textActionsMethod = (function () {
let chardata = []
let textbb // , transbb;
let matrix
let lastX; let lastY
let lastX
let lastY
let allowDbl
/**
*
* @param {Integer} index
* @returns {void}
*/
*
* @param {Integer} index
* @returns {void}
*/
function setCursor (index) {
const empty = (textinput.value === '')
const empty = textinput.value === ''
textinput.focus()
if (!arguments.length) {
if (empty) {
index = 0
} else {
if (textinput.selectionEnd !== textinput.selectionStart) { return }
if (textinput.selectionEnd !== textinput.selectionStart) {
return
}
index = textinput.selectionEnd
}
}
@@ -80,13 +81,13 @@ export const textActionsMethod = (function () {
if (!blinker) {
blinker = setInterval(function () {
const show = (cursor.getAttribute('display') === 'none')
const show = cursor.getAttribute('display') === 'none'
cursor.setAttribute('display', show ? 'inline' : 'none')
}, 600)
}
const startPt = ptToScreen(charbb.x, textbb.y)
const endPt = ptToScreen(charbb.x, (textbb.y + textbb.height))
const endPt = ptToScreen(charbb.x, textbb.y + textbb.height)
assignAttributes(cursor, {
x1: startPt.x,
@@ -97,16 +98,18 @@ export const textActionsMethod = (function () {
display: 'inline'
})
if (selblock) { selblock.setAttribute('d', '') }
if (selblock) {
selblock.setAttribute('d', '')
}
}
/**
*
* @param {Integer} start
* @param {Integer} end
* @param {boolean} skipInput
* @returns {void}
*/
*
* @param {Integer} start
* @param {Integer} end
* @param {boolean} skipInput
* @returns {void}
*/
function setSelection (start, end, skipInput) {
if (start === end) {
setCursor(end)
@@ -137,12 +140,29 @@ export const textActionsMethod = (function () {
const tl = ptToScreen(startbb.x, textbb.y)
const tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y)
const bl = ptToScreen(startbb.x, textbb.y + textbb.height)
const br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height)
const br = ptToScreen(
startbb.x + (endbb.x - startbb.x),
textbb.y + textbb.height
)
const dstr = 'M' + tl.x + ',' + tl.y +
' L' + tr.x + ',' + tr.y +
' ' + br.x + ',' + br.y +
' ' + bl.x + ',' + bl.y + 'z'
const dstr =
'M' +
tl.x +
',' +
tl.y +
' L' +
tr.x +
',' +
tr.y +
' ' +
br.x +
',' +
br.y +
' ' +
bl.x +
',' +
bl.y +
'z'
assignAttributes(selblock, {
d: dstr,
@@ -151,11 +171,11 @@ export const textActionsMethod = (function () {
}
/**
*
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {Integer}
*/
*
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {Integer}
*/
function getIndexFromPoint (mouseX, mouseY) {
// Position cursor here
const pt = svgCanvas.getSvgRoot().createSVGPoint()
@@ -163,7 +183,9 @@ export const textActionsMethod = (function () {
pt.y = mouseY
// No content, so return 0
if (chardata.length === 1) { return 0 }
if (chardata.length === 1) {
return 0
}
// Determine if cursor should be on left or right of character
let charpos = curtext.getCharNumAtPosition(pt)
if (charpos < 0) {
@@ -176,7 +198,7 @@ export const textActionsMethod = (function () {
charpos = chardata.length - 2
}
const charbb = chardata[charpos]
const mid = charbb.x + (charbb.width / 2)
const mid = charbb.x + charbb.width / 2
if (mouseX > mid) {
charpos++
}
@@ -184,22 +206,22 @@ export const textActionsMethod = (function () {
}
/**
*
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
*
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
function setCursorFromPoint (mouseX, mouseY) {
setCursor(getIndexFromPoint(mouseX, mouseY))
}
/**
*
* @param {Float} x
* @param {Float} y
* @param {boolean} apply
* @returns {void}
*/
*
* @param {Float} x
* @param {Float} y
* @param {boolean} apply
* @returns {void}
*/
function setEndSelectionFromPoint (x, y, apply) {
const i1 = textinput.selectionStart
const i2 = getIndexFromPoint(x, y)
@@ -210,11 +232,11 @@ export const textActionsMethod = (function () {
}
/**
*
* @param {Float} xIn
* @param {Float} yIn
* @returns {module:math.XYObject}
*/
*
* @param {Float} xIn
* @param {Float} yIn
* @returns {module:math.XYObject}
*/
function screenToPt (xIn, yIn) {
const out = {
x: xIn,
@@ -234,11 +256,11 @@ export const textActionsMethod = (function () {
}
/**
*
* @param {Float} xIn
* @param {Float} yIn
* @returns {module:math.XYObject}
*/
*
* @param {Float} xIn
* @param {Float} yIn
* @returns {module:math.XYObject}
*/
function ptToScreen (xIn, yIn) {
const out = {
x: xIn,
@@ -258,22 +280,24 @@ export const textActionsMethod = (function () {
}
/**
*
* @param {Event} evt
* @returns {void}
*/
*
* @param {Event} evt
* @returns {void}
*/
function selectAll (evt) {
setSelection(0, curtext.textContent.length)
evt.target.removeEventListener('click', selectAll)
}
/**
*
* @param {Event} evt
* @returns {void}
*/
*
* @param {Event} evt
* @returns {void}
*/
function selectWord (evt) {
if (!allowDbl || !curtext) { return }
if (!allowDbl || !curtext) {
return
}
const zoom = svgCanvas.getZoom()
const ept = transformPoint(evt.pageX, evt.pageY, svgCanvas.getrootSctm())
const mouseX = ept.x * zoom
@@ -297,30 +321,30 @@ export const textActionsMethod = (function () {
return /** @lends module:svgcanvas.SvgCanvas#textActions */ {
/**
* @param {Element} target
* @param {Float} x
* @param {Float} y
* @returns {void}
*/
* @param {Element} target
* @param {Float} x
* @param {Float} y
* @returns {void}
*/
select (target, x, y) {
curtext = target
svgCanvas.textActions.toEditMode(x, y)
},
/**
* @param {Element} elem
* @returns {void}
*/
* @param {Element} elem
* @returns {void}
*/
start (elem) {
curtext = elem
svgCanvas.textActions.toEditMode()
},
/**
* @param {external:MouseEvent} evt
* @param {Element} mouseTarget
* @param {Float} startX
* @param {Float} startY
* @returns {void}
*/
* @param {external:MouseEvent} evt
* @param {Element} mouseTarget
* @param {Float} startX
* @param {Float} startY
* @returns {void}
*/
mouseDown (evt, mouseTarget, startX, startY) {
const pt = screenToPt(startX, startY)
@@ -332,20 +356,20 @@ export const textActionsMethod = (function () {
// TODO: Find way to block native selection
},
/**
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
mouseMove (mouseX, mouseY) {
const pt = screenToPt(mouseX, mouseY)
setEndSelectionFromPoint(pt.x, pt.y)
},
/**
* @param {external:MouseEvent} evt
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
* @param {external:MouseEvent} evt
* @param {Float} mouseX
* @param {Float} mouseY
* @returns {void}
*/
mouseUp (evt, mouseX, mouseY) {
const pt = screenToPt(mouseX, mouseY)
@@ -359,25 +383,25 @@ export const textActionsMethod = (function () {
if (
evt.target !== curtext &&
mouseX < lastX + 2 &&
mouseX > lastX - 2 &&
mouseY < lastY + 2 &&
mouseY > lastY - 2
mouseX < lastX + 2 &&
mouseX > lastX - 2 &&
mouseY < lastY + 2 &&
mouseY > lastY - 2
) {
svgCanvas.textActions.toSelectMode(true)
}
},
/**
* @function
* @param {Integer} index
* @returns {void}
*/
* @function
* @param {Integer} index
* @returns {void}
*/
setCursor,
/**
* @param {Float} x
* @param {Float} y
* @returns {void}
*/
* @param {Float} x
* @param {Float} y
* @returns {void}
*/
toEditMode (x, y) {
allowDbl = false
svgCanvas.setCurrentMode('textedit')
@@ -407,16 +431,20 @@ export const textActionsMethod = (function () {
}, 300)
},
/**
* @param {boolean|Element} selectElem
* @fires module:svgcanvas.SvgCanvas#event:selected
* @returns {void}
*/
* @param {boolean|Element} selectElem
* @fires module:svgcanvas.SvgCanvas#event:selected
* @returns {void}
*/
toSelectMode (selectElem) {
svgCanvas.setCurrentMode('select')
clearInterval(blinker)
blinker = null
if (selblock) { selblock.setAttribute('display', 'none') }
if (cursor) { cursor.setAttribute('visibility', 'hidden') }
if (selblock) {
selblock.setAttribute('display', 'none')
}
if (cursor) {
cursor.setAttribute('visibility', 'hidden')
}
curtext.style.cursor = 'move'
if (selectElem) {
@@ -440,27 +468,30 @@ export const textActionsMethod = (function () {
// }
},
/**
* @param {Element} elem
* @returns {void}
*/
* @param {Element} elem
* @returns {void}
*/
setInputElem (elem) {
textinput = elem
},
/**
* @returns {void}
*/
* @returns {void}
*/
clear () {
if (svgCanvas.getCurrentMode() === 'textedit') {
svgCanvas.textActions.toSelectMode()
}
},
/**
* @param {Element} _inputElem Not in use
* @returns {void}
*/
* @param {Element} _inputElem Not in use
* @returns {void}
*/
init (_inputElem) {
if (!curtext) { return }
let i; let end
if (!curtext) {
return
}
let i
let end
// if (supportsEditableText()) {
// curtext.select();
// return;
@@ -490,7 +521,7 @@ export const textActionsMethod = (function () {
curtext.addEventListener('dblclick', selectWord)
if (!len) {
end = { x: textbb.x + (textbb.width / 2), width: 0 }
end = { x: textbb.x + textbb.width / 2, width: 0 }
}
for (i = 0; i < len; i++) {
@@ -527,4 +558,4 @@ export const textActionsMethod = (function () {
setSelection(textinput.selectionStart, textinput.selectionEnd, true)
}
}
}())
})()