diff --git a/coverage/coverage-summary.json b/coverage/coverage-summary.json index 9d5114cee..e9a865f8d 100644 --- a/coverage/coverage-summary.json +++ b/coverage/coverage-summary.json @@ -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}} } diff --git a/cypress/__svgSnapshots__/scenario-check tool_bold.svg b/cypress/__svgSnapshots__/scenario-check tool_bold.svg index 33fc767d2..6f78b5466 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_bold.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_bold.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_clone.svg b/cypress/__svgSnapshots__/scenario-check tool_clone.svg index 49a40a1ea..8356343ee 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_clone.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_clone.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_italic.svg b/cypress/__svgSnapshots__/scenario-check tool_italic.svg index 67f60f7e9..884cb0cc8 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_italic.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_italic.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_align_to_page.svg b/cypress/__svgSnapshots__/scenario-check tool_text_align_to_page.svg index 490ababf5..614975fd1 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_align_to_page.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_align_to_page.svg @@ -2,7 +2,7 @@ Layer 1 AB - AB + AB diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_blur.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_blur.svg index 3cd30e527..3384e2b0e 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_blur.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_blur.svg @@ -2,7 +2,7 @@ Layer 1 AB - AB + AB diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_font_size.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_font_size.svg index 577070c99..eb930043e 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_font_size.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_font_size.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_opacity.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_opacity.svg index d85cc40d6..f4f5cffb5 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_opacity.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_opacity.svg @@ -2,7 +2,7 @@ Layer 1 AB - AB + AB diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_stoke_fill_color.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_stoke_fill_color.svg index e6fb49891..9f4570fc9 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_stoke_fill_color.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_stoke_fill_color.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_stroke_width.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_stroke_width.svg index 5710c7e0f..8bdb91833 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_stroke_width.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_stroke_width.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/__svgSnapshots__/scenario-check tool_text_change_x_y_coordinate.svg b/cypress/__svgSnapshots__/scenario-check tool_text_change_x_y_coordinate.svg index b8fa5cbc1..8aa197965 100644 --- a/cypress/__svgSnapshots__/scenario-check tool_text_change_x_y_coordinate.svg +++ b/cypress/__svgSnapshots__/scenario-check tool_text_change_x_y_coordinate.svg @@ -2,6 +2,6 @@ Layer 1 AB - AB + AB \ No newline at end of file diff --git a/cypress/e2e/unit/math.cy.js b/cypress/e2e/unit/math.cy.js index a3a4ebc3c..665695cb5 100644 --- a/cypress/e2e/unit/math.cy.js +++ b/cypress/e2e/unit/math.cy.js @@ -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 + + // Test empty arguments + const iDefault = matrixMultiply() + assert.ok( + isIdentity(iDefault), + 'No arguments should return identity matrix' + ) - // translate there and back + // 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') - - // 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') + 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' + ) + + // 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' + ) }) }) diff --git a/package-lock.json b/package-lock.json index 04c8a4105..1b5071747 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" } }, diff --git a/package.json b/package.json index f7da55caf..1cec41c47 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/packages/svgcanvas/core/coords.js b/packages/svgcanvas/core/coords.js index 7a1961b1a..508418332 100644 --- a/packages/svgcanvas/core/coords.js +++ b/packages/svgcanvas/core/coords.js @@ -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 } diff --git a/packages/svgcanvas/core/event.js b/packages/svgcanvas/core/event.js index 7e24d40b1..068c63863 100644 --- a/packages/svgcanvas/core/event.js +++ b/packages/svgcanvas/core/event.js @@ -570,6 +570,7 @@ const mouseOutEvent = () => { * @returns {void} */ const mouseUpEvent = (evt) => { + evt.preventDefault() moveSelectionThresholdReached = false if (evt.button === 2) { return } if (!svgCanvas.getStarted()) { return } diff --git a/packages/svgcanvas/core/math.js b/packages/svgcanvas/core/math.js index 7d4bc5c64..b954778eb 100644 --- a/packages/svgcanvas/core/math.js +++ b/packages/svgcanvas/core/math.js @@ -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) - }) - - 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 +export const matrixMultiply = (...args) => { + // If no matrices are given, return an identity matrix + if (args.length === 0) { + return svg.createSVGMatrix() } + 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 diff --git a/packages/svgcanvas/core/text-actions.js b/packages/svgcanvas/core/text-actions.js index 9832324ae..73fd209cf 100644 --- a/packages/svgcanvas/core/text-actions.js +++ b/packages/svgcanvas/core/text-actions.js @@ -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 dstr = 'M' + tl.x + ',' + tl.y + -' L' + tr.x + ',' + tr.y + -' ' + br.x + ',' + br.y + -' ' + bl.x + ',' + bl.y + 'z' + 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' 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) } } -}()) +})()