sketchily 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.md +39 -0
- data/Rakefile +40 -0
- data/app/helpers/sketchily.rb~ +10 -0
- data/app/helpers/sketchily_helper.rb +10 -0
- data/app/views/sketchily/_embed.html.erb +28 -0
- data/app/views/sketchily/_embed.html.erb~ +28 -0
- data/app/views/sketchily/_embed.js.erb +50 -0
- data/app/views/sketchily/_embed.js.erb~ +50 -0
- data/app/views/sketchily/_sketchily.html.erb +23 -0
- data/app/views/sketchily/_sketchily.html.erb~ +23 -0
- data/app/views/sketchily/_sketchily_tag.html.erb +21 -0
- data/app/views/sketchily/_sketchily_tag.html.erb~ +21 -0
- data/app/views/sketchily/_svg_edit_tag.html.erb~ +51 -0
- data/app/views/sketchily/svg_edit_tag_.html~ +35 -0
- data/lib/sketchily.rb +15 -0
- data/lib/sketchily.rb~ +16 -0
- data/lib/sketchily/engine.rb +4 -0
- data/lib/sketchily/sketchily.rb +28 -0
- data/lib/sketchily/sketchily_show.rb~ +13 -0
- data/lib/sketchily/sketchily_tag.rb +15 -0
- data/lib/sketchily/svg_edit_tag.rb~ +9 -0
- data/lib/sketchily/version.rb +3 -0
- data/lib/sketchily/version.rb~ +3 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/sketchily_spec.rb +0 -0
- data/spec/spec_helper.rb +11 -0
- data/vendor/assets/svg-edit-2.6/browser-not-supported.html +27 -0
- data/vendor/assets/svg-edit-2.6/browser.js +180 -0
- data/vendor/assets/svg-edit-2.6/canvg/canvg.js +2620 -0
- data/vendor/assets/svg-edit-2.6/canvg/rgbcolor.js +287 -0
- data/vendor/assets/svg-edit-2.6/contextmenu.js +67 -0
- data/vendor/assets/svg-edit-2.6/contextmenu/jquery.contextMenu.js +203 -0
- data/vendor/assets/svg-edit-2.6/draw.js +528 -0
- data/vendor/assets/svg-edit-2.6/embedapi.html +56 -0
- data/vendor/assets/svg-edit-2.6/embedapi.js +173 -0
- data/vendor/assets/svg-edit-2.6/extensions/closepath_icons.svg +41 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-arrows.js +298 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-closepath.js +92 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-connector.js +587 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-eyedropper.js +109 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-foreignobject.js +277 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-grid.js +184 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-helloworld.js +78 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-imagelib.js +453 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-imagelib.xml +14 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-markers.js +572 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-server_moinsave.js +56 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-server_opensave.js +180 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-shapes.js +387 -0
- data/vendor/assets/svg-edit-2.6/extensions/ext-shapes.xml +10 -0
- data/vendor/assets/svg-edit-2.6/extensions/eyedropper-icon.xml +34 -0
- data/vendor/assets/svg-edit-2.6/extensions/eyedropper.png +0 -0
- data/vendor/assets/svg-edit-2.6/extensions/fileopen.php +31 -0
- data/vendor/assets/svg-edit-2.6/extensions/filesave.php +44 -0
- data/vendor/assets/svg-edit-2.6/extensions/foreignobject-icons.xml +96 -0
- data/vendor/assets/svg-edit-2.6/extensions/grid-icon.xml +30 -0
- data/vendor/assets/svg-edit-2.6/extensions/helloworld-icon.xml +21 -0
- data/vendor/assets/svg-edit-2.6/extensions/imagelib/index.html +64 -0
- data/vendor/assets/svg-edit-2.6/extensions/imagelib/smiley.svg +12 -0
- data/vendor/assets/svg-edit-2.6/extensions/markers-icons.xml +115 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/animal.json +21 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/arrow.json +28 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/dialog_balloon.json +9 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/electronics.json +20 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/flowchart.json +25 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/game.json +13 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/math.json +9 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/misc.json +37 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/music.json +21 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/object.json +19 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael.txt +12 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael_1.json +67 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael_2.json +64 -0
- data/vendor/assets/svg-edit-2.6/extensions/shapelib/symbol.json +28 -0
- data/vendor/assets/svg-edit-2.6/history.js +601 -0
- data/vendor/assets/svg-edit-2.6/images/README.txt +61 -0
- data/vendor/assets/svg-edit-2.6/images/align-bottom.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-bottom.svg +277 -0
- data/vendor/assets/svg-edit-2.6/images/align-center.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-center.svg +252 -0
- data/vendor/assets/svg-edit-2.6/images/align-left.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-left.svg +235 -0
- data/vendor/assets/svg-edit-2.6/images/align-middle.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-middle.svg +250 -0
- data/vendor/assets/svg-edit-2.6/images/align-right.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-right.svg +233 -0
- data/vendor/assets/svg-edit-2.6/images/align-top.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/align-top.svg +233 -0
- data/vendor/assets/svg-edit-2.6/images/bold.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/cancel.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/circle.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/clear.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/clone.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/conn.svg +29 -0
- data/vendor/assets/svg-edit-2.6/images/copy.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/cut.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/delete.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/document-properties.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/dropdown.gif +0 -0
- data/vendor/assets/svg-edit-2.6/images/ellipse.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/eye.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/fhpath.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/flyouth.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/flyup.gif +0 -0
- data/vendor/assets/svg-edit-2.6/images/freehand-circle.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/freehand-square.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/go-down.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/go-up.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/image.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/italic.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/line.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/link_controls.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/logo.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/logo.svg +32 -0
- data/vendor/assets/svg-edit-2.6/images/move_bottom.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/move_top.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/node_clone.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/node_delete.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/none.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/open.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/paste.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/path.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/polygon.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/polygon.svg +219 -0
- data/vendor/assets/svg-edit-2.6/images/rect.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/redo.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/reorient.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/rotate.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/save.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/select.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/select_node.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/sep.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/shape_group.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/shape_ungroup.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/source.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/spinbtn_updn_big.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/square.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/svg_edit_icons.svg +1034 -0
- data/vendor/assets/svg-edit-2.6/images/svg_edit_icons.svgz +0 -0
- data/vendor/assets/svg-edit-2.6/images/text.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/text.svg +157 -0
- data/vendor/assets/svg-edit-2.6/images/to_path.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/undo.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/view-refresh.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/wave.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/wireframe.png +0 -0
- data/vendor/assets/svg-edit-2.6/images/zoom.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/LICENSE +202 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/README +3 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/css/jPicker.css +1 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/css/jgraduate.css +351 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/AlphaBar.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/Bars.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/Maps.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/NoColor.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/bar-opacity.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/map-opacity.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint.gif +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint_c.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint_f.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/picker.gif +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/preview-opacity.png +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/rangearrows.gif +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/images/rangearrows2.gif +0 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/jpicker.js +2091 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/jpicker.min.js +1 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/jquery.jgraduate.js +1175 -0
- data/vendor/assets/svg-edit-2.6/jgraduate/jquery.jgraduate.min.js +37 -0
- data/vendor/assets/svg-edit-2.6/jquery-ui/jquery-ui-1.8.17.custom.min.js +54 -0
- data/vendor/assets/svg-edit-2.6/jquery-ui/jquery-ui-1.8.custom.min.js +84 -0
- data/vendor/assets/svg-edit-2.6/jquery.js +4 -0
- data/vendor/assets/svg-edit-2.6/jquerybbq/jquery.bbq.min.js +18 -0
- data/vendor/assets/svg-edit-2.6/js-hotkeys/README.md +45 -0
- data/vendor/assets/svg-edit-2.6/js-hotkeys/jquery.hotkeys.min.js +15 -0
- data/vendor/assets/svg-edit-2.6/locale/README.txt +17 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.af.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ar.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.az.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.be.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.bg.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ca.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.cs.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.cy.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.da.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.de.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.el.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.en.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.es.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.et.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.fa.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.fi.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.fr.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.fy.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ga.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.gl.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.he.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.hi.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.hr.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.hu.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.hy.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.id.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.is.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.it.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ja.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ko.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.lt.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.lv.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.mk.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ms.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.mt.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.nl.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.no.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.pl.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.pt-BR.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.pt-PT.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ro.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.ru.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sk.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sl.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sq.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sr.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sv.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.sw.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.test.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.th.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.tl.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.tr.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.uk.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.vi.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.yi.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.zh-CN.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.zh-HK.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/lang.zh-TW.js +234 -0
- data/vendor/assets/svg-edit-2.6/locale/locale.js +320 -0
- data/vendor/assets/svg-edit-2.6/math.js +246 -0
- data/vendor/assets/svg-edit-2.6/path.js +980 -0
- data/vendor/assets/svg-edit-2.6/sanitize.js +273 -0
- data/vendor/assets/svg-edit-2.6/select.js +532 -0
- data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.css +41 -0
- data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.js +266 -0
- data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.min.js +7 -0
- data/vendor/assets/svg-edit-2.6/spinbtn/spinbtn_updn.png +0 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.css +1495 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.css~ +1500 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.html +788 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.html~ +788 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.js +4969 -0
- data/vendor/assets/svg-edit-2.6/svg-editor.manifest +121 -0
- data/vendor/assets/svg-edit-2.6/svgcanvas.js +8775 -0
- data/vendor/assets/svg-edit-2.6/svgedit.compiled.js +465 -0
- data/vendor/assets/svg-edit-2.6/svgicons/jquery.svgicons.js +486 -0
- data/vendor/assets/svg-edit-2.6/svgtransformlist.js +291 -0
- data/vendor/assets/svg-edit-2.6/svgutils.js +651 -0
- data/vendor/assets/svg-edit-2.6/touch.js +30 -0
- data/vendor/assets/svg-edit-2.6/units.js +281 -0
- metadata +407 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package: svedit.math
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright(c) 2010 Alexis Deveria
|
|
7
|
+
* Copyright(c) 2010 Jeff Schiller
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Dependencies:
|
|
11
|
+
// None.
|
|
12
|
+
|
|
13
|
+
var svgedit = svgedit || {};
|
|
14
|
+
|
|
15
|
+
(function() {
|
|
16
|
+
|
|
17
|
+
if (!svgedit.math) {
|
|
18
|
+
svgedit.math = {};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Constants
|
|
22
|
+
var NEAR_ZERO = 1e-14;
|
|
23
|
+
|
|
24
|
+
// Throw away SVGSVGElement used for creating matrices/transforms.
|
|
25
|
+
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
26
|
+
|
|
27
|
+
// Function: svgedit.math.transformPoint
|
|
28
|
+
// A (hopefully) quicker function to transform a point by a matrix
|
|
29
|
+
// (this function avoids any DOM calls and just does the math)
|
|
30
|
+
//
|
|
31
|
+
// Parameters:
|
|
32
|
+
// x - Float representing the x coordinate
|
|
33
|
+
// y - Float representing the y coordinate
|
|
34
|
+
// m - Matrix object to transform the point with
|
|
35
|
+
// Returns a x,y object representing the transformed point
|
|
36
|
+
svgedit.math.transformPoint = function(x, y, m) {
|
|
37
|
+
return { x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// Function: svgedit.math.isIdentity
|
|
42
|
+
// Helper function to check if the matrix performs no actual transform
|
|
43
|
+
// (i.e. exists for identity purposes)
|
|
44
|
+
//
|
|
45
|
+
// Parameters:
|
|
46
|
+
// m - The matrix object to check
|
|
47
|
+
//
|
|
48
|
+
// Returns:
|
|
49
|
+
// Boolean indicating whether or not the matrix is 1,0,0,1,0,0
|
|
50
|
+
svgedit.math.isIdentity = function(m) {
|
|
51
|
+
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// Function: svgedit.math.matrixMultiply
|
|
56
|
+
// This function tries to return a SVGMatrix that is the multiplication m1*m2.
|
|
57
|
+
// We also round to zero when it's near zero
|
|
58
|
+
//
|
|
59
|
+
// Parameters:
|
|
60
|
+
// >= 2 Matrix objects to multiply
|
|
61
|
+
//
|
|
62
|
+
// Returns:
|
|
63
|
+
// The matrix object resulting from the calculation
|
|
64
|
+
svgedit.math.matrixMultiply = function() {
|
|
65
|
+
var args = arguments, i = args.length, m = args[i-1];
|
|
66
|
+
|
|
67
|
+
while(i-- > 1) {
|
|
68
|
+
var m1 = args[i-1];
|
|
69
|
+
m = m1.multiply(m);
|
|
70
|
+
}
|
|
71
|
+
if (Math.abs(m.a) < NEAR_ZERO) m.a = 0;
|
|
72
|
+
if (Math.abs(m.b) < NEAR_ZERO) m.b = 0;
|
|
73
|
+
if (Math.abs(m.c) < NEAR_ZERO) m.c = 0;
|
|
74
|
+
if (Math.abs(m.d) < NEAR_ZERO) m.d = 0;
|
|
75
|
+
if (Math.abs(m.e) < NEAR_ZERO) m.e = 0;
|
|
76
|
+
if (Math.abs(m.f) < NEAR_ZERO) m.f = 0;
|
|
77
|
+
|
|
78
|
+
return m;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Function: svgedit.math.hasMatrixTransform
|
|
82
|
+
// See if the given transformlist includes a non-indentity matrix transform
|
|
83
|
+
//
|
|
84
|
+
// Parameters:
|
|
85
|
+
// tlist - The transformlist to check
|
|
86
|
+
//
|
|
87
|
+
// Returns:
|
|
88
|
+
// Boolean on whether or not a matrix transform was found
|
|
89
|
+
svgedit.math.hasMatrixTransform = function(tlist) {
|
|
90
|
+
if(!tlist) return false;
|
|
91
|
+
var num = tlist.numberOfItems;
|
|
92
|
+
while (num--) {
|
|
93
|
+
var xform = tlist.getItem(num);
|
|
94
|
+
if (xform.type == 1 && !svgedit.math.isIdentity(xform.matrix)) return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Function: svgedit.math.transformBox
|
|
100
|
+
// Transforms a rectangle based on the given matrix
|
|
101
|
+
//
|
|
102
|
+
// Parameters:
|
|
103
|
+
// l - Float with the box's left coordinate
|
|
104
|
+
// t - Float with the box's top coordinate
|
|
105
|
+
// w - Float with the box width
|
|
106
|
+
// h - Float with the box height
|
|
107
|
+
// m - Matrix object to transform the box by
|
|
108
|
+
//
|
|
109
|
+
// Returns:
|
|
110
|
+
// An object with the following values:
|
|
111
|
+
// * tl - The top left coordinate (x,y object)
|
|
112
|
+
// * tr - The top right coordinate (x,y object)
|
|
113
|
+
// * bl - The bottom left coordinate (x,y object)
|
|
114
|
+
// * br - The bottom right coordinate (x,y object)
|
|
115
|
+
// * aabox - Object with the following values:
|
|
116
|
+
// * Float with the axis-aligned x coordinate
|
|
117
|
+
// * Float with the axis-aligned y coordinate
|
|
118
|
+
// * Float with the axis-aligned width coordinate
|
|
119
|
+
// * Float with the axis-aligned height coordinate
|
|
120
|
+
svgedit.math.transformBox = function(l, t, w, h, m) {
|
|
121
|
+
var topleft = {x:l,y:t},
|
|
122
|
+
topright = {x:(l+w),y:t},
|
|
123
|
+
botright = {x:(l+w),y:(t+h)},
|
|
124
|
+
botleft = {x:l,y:(t+h)};
|
|
125
|
+
var transformPoint = svgedit.math.transformPoint;
|
|
126
|
+
topleft = transformPoint( topleft.x, topleft.y, m );
|
|
127
|
+
var minx = topleft.x,
|
|
128
|
+
maxx = topleft.x,
|
|
129
|
+
miny = topleft.y,
|
|
130
|
+
maxy = topleft.y;
|
|
131
|
+
topright = transformPoint( topright.x, topright.y, m );
|
|
132
|
+
minx = Math.min(minx, topright.x);
|
|
133
|
+
maxx = Math.max(maxx, topright.x);
|
|
134
|
+
miny = Math.min(miny, topright.y);
|
|
135
|
+
maxy = Math.max(maxy, topright.y);
|
|
136
|
+
botleft = transformPoint( botleft.x, botleft.y, m);
|
|
137
|
+
minx = Math.min(minx, botleft.x);
|
|
138
|
+
maxx = Math.max(maxx, botleft.x);
|
|
139
|
+
miny = Math.min(miny, botleft.y);
|
|
140
|
+
maxy = Math.max(maxy, botleft.y);
|
|
141
|
+
botright = transformPoint( botright.x, botright.y, m );
|
|
142
|
+
minx = Math.min(minx, botright.x);
|
|
143
|
+
maxx = Math.max(maxx, botright.x);
|
|
144
|
+
miny = Math.min(miny, botright.y);
|
|
145
|
+
maxy = Math.max(maxy, botright.y);
|
|
146
|
+
|
|
147
|
+
return {tl:topleft, tr:topright, bl:botleft, br:botright,
|
|
148
|
+
aabox: {x:minx, y:miny, width:(maxx-minx), height:(maxy-miny)} };
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Function: svgedit.math.transformListToTransform
|
|
152
|
+
// This returns a single matrix Transform for a given Transform List
|
|
153
|
+
// (this is the equivalent of SVGTransformList.consolidate() but unlike
|
|
154
|
+
// that method, this one does not modify the actual SVGTransformList)
|
|
155
|
+
// This function is very liberal with its min,max arguments
|
|
156
|
+
//
|
|
157
|
+
// Parameters:
|
|
158
|
+
// tlist - The transformlist object
|
|
159
|
+
// min - Optional integer indicating start transform position
|
|
160
|
+
// max - Optional integer indicating end transform position
|
|
161
|
+
//
|
|
162
|
+
// Returns:
|
|
163
|
+
// A single matrix transform object
|
|
164
|
+
svgedit.math.transformListToTransform = function(tlist, min, max) {
|
|
165
|
+
if(tlist == null) {
|
|
166
|
+
// Or should tlist = null have been prevented before this?
|
|
167
|
+
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix());
|
|
168
|
+
}
|
|
169
|
+
var min = min == undefined ? 0 : min;
|
|
170
|
+
var max = max == undefined ? (tlist.numberOfItems-1) : max;
|
|
171
|
+
min = parseInt(min);
|
|
172
|
+
max = parseInt(max);
|
|
173
|
+
if (min > max) { var temp = max; max = min; min = temp; }
|
|
174
|
+
var m = svg.createSVGMatrix();
|
|
175
|
+
for (var i = min; i <= max; ++i) {
|
|
176
|
+
// if our indices are out of range, just use a harmless identity matrix
|
|
177
|
+
var mtom = (i >= 0 && i < tlist.numberOfItems ?
|
|
178
|
+
tlist.getItem(i).matrix :
|
|
179
|
+
svg.createSVGMatrix());
|
|
180
|
+
m = svgedit.math.matrixMultiply(m, mtom);
|
|
181
|
+
}
|
|
182
|
+
return svg.createSVGTransformFromMatrix(m);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
// Function: svgedit.math.getMatrix
|
|
187
|
+
// Get the matrix object for a given element
|
|
188
|
+
//
|
|
189
|
+
// Parameters:
|
|
190
|
+
// elem - The DOM element to check
|
|
191
|
+
//
|
|
192
|
+
// Returns:
|
|
193
|
+
// The matrix object associated with the element's transformlist
|
|
194
|
+
svgedit.math.getMatrix = function(elem) {
|
|
195
|
+
var tlist = svgedit.transformlist.getTransformList(elem);
|
|
196
|
+
return svgedit.math.transformListToTransform(tlist).matrix;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
// Function: svgedit.math.snapToAngle
|
|
201
|
+
// Returns a 45 degree angle coordinate associated with the two given
|
|
202
|
+
// coordinates
|
|
203
|
+
//
|
|
204
|
+
// Parameters:
|
|
205
|
+
// x1 - First coordinate's x value
|
|
206
|
+
// x2 - Second coordinate's x value
|
|
207
|
+
// y1 - First coordinate's y value
|
|
208
|
+
// y2 - Second coordinate's y value
|
|
209
|
+
//
|
|
210
|
+
// Returns:
|
|
211
|
+
// Object with the following values:
|
|
212
|
+
// x - The angle-snapped x value
|
|
213
|
+
// y - The angle-snapped y value
|
|
214
|
+
// snapangle - The angle at which to snap
|
|
215
|
+
svgedit.math.snapToAngle = function(x1,y1,x2,y2) {
|
|
216
|
+
var snap = Math.PI/4; // 45 degrees
|
|
217
|
+
var dx = x2 - x1;
|
|
218
|
+
var dy = y2 - y1;
|
|
219
|
+
var angle = Math.atan2(dy,dx);
|
|
220
|
+
var dist = Math.sqrt(dx * dx + dy * dy);
|
|
221
|
+
var snapangle= Math.round(angle/snap)*snap;
|
|
222
|
+
var x = x1 + dist*Math.cos(snapangle);
|
|
223
|
+
var y = y1 + dist*Math.sin(snapangle);
|
|
224
|
+
//console.log(x1,y1,x2,y2,x,y,angle)
|
|
225
|
+
return {x:x, y:y, a:snapangle};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
// Function: rectsIntersect
|
|
230
|
+
// Check if two rectangles (BBoxes objects) intersect each other
|
|
231
|
+
//
|
|
232
|
+
// Paramaters:
|
|
233
|
+
// r1 - The first BBox-like object
|
|
234
|
+
// r2 - The second BBox-like object
|
|
235
|
+
//
|
|
236
|
+
// Returns:
|
|
237
|
+
// Boolean that's true if rectangles intersect
|
|
238
|
+
svgedit.math.rectsIntersect = function(r1, r2) {
|
|
239
|
+
return r2.x < (r1.x+r1.width) &&
|
|
240
|
+
(r2.x+r2.width) > r1.x &&
|
|
241
|
+
r2.y < (r1.y+r1.height) &&
|
|
242
|
+
(r2.y+r2.height) > r1.y;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
})();
|
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package: svgedit.path
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright(c) 2011 Alexis Deveria
|
|
7
|
+
* Copyright(c) 2011 Jeff Schiller
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Dependencies:
|
|
11
|
+
// 1) jQuery
|
|
12
|
+
// 2) browser.js
|
|
13
|
+
// 3) math.js
|
|
14
|
+
// 4) svgutils.js
|
|
15
|
+
|
|
16
|
+
var svgedit = svgedit || {};
|
|
17
|
+
|
|
18
|
+
(function() {
|
|
19
|
+
|
|
20
|
+
if (!svgedit.path) {
|
|
21
|
+
svgedit.path = {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var svgns = "http://www.w3.org/2000/svg";
|
|
25
|
+
|
|
26
|
+
var uiStrings = {
|
|
27
|
+
"pathNodeTooltip": "Drag node to move it. Double-click node to change segment type",
|
|
28
|
+
"pathCtrlPtTooltip": "Drag control point to adjust curve properties"
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
var segData = {
|
|
32
|
+
2: ['x','y'],
|
|
33
|
+
4: ['x','y'],
|
|
34
|
+
6: ['x','y','x1','y1','x2','y2'],
|
|
35
|
+
8: ['x','y','x1','y1'],
|
|
36
|
+
10: ['x','y','r1','r2','angle','largeArcFlag','sweepFlag'],
|
|
37
|
+
12: ['x'],
|
|
38
|
+
14: ['y'],
|
|
39
|
+
16: ['x','y','x2','y2'],
|
|
40
|
+
18: ['x','y']
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
var pathFuncs = [];
|
|
44
|
+
|
|
45
|
+
var link_control_pts = true;
|
|
46
|
+
|
|
47
|
+
// Stores references to paths via IDs.
|
|
48
|
+
// TODO: Make this cross-document happy.
|
|
49
|
+
var pathData = {};
|
|
50
|
+
|
|
51
|
+
svgedit.path.setLinkControlPoints = function(lcp) {
|
|
52
|
+
link_control_pts = lcp;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
svgedit.path.path = null;
|
|
56
|
+
|
|
57
|
+
var editorContext_ = null;
|
|
58
|
+
|
|
59
|
+
svgedit.path.init = function(editorContext) {
|
|
60
|
+
editorContext_ = editorContext;
|
|
61
|
+
|
|
62
|
+
pathFuncs = [0,'ClosePath'];
|
|
63
|
+
var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc',
|
|
64
|
+
'LinetoHorizontal', 'LinetoVertical','CurvetoCubicSmooth','CurvetoQuadraticSmooth'];
|
|
65
|
+
$.each(pathFuncsStrs, function(i,s) {
|
|
66
|
+
pathFuncs.push(s+'Abs');
|
|
67
|
+
pathFuncs.push(s+'Rel');
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
svgedit.path.insertItemBefore = function(elem, newseg, index) {
|
|
72
|
+
// Support insertItemBefore on paths for FF2
|
|
73
|
+
var list = elem.pathSegList;
|
|
74
|
+
|
|
75
|
+
if(svgedit.browser.supportsPathInsertItemBefore()) {
|
|
76
|
+
list.insertItemBefore(newseg, index);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
var len = list.numberOfItems;
|
|
80
|
+
var arr = [];
|
|
81
|
+
for(var i=0; i<len; i++) {
|
|
82
|
+
var cur_seg = list.getItem(i);
|
|
83
|
+
arr.push(cur_seg)
|
|
84
|
+
}
|
|
85
|
+
list.clear();
|
|
86
|
+
for(var i=0; i<len; i++) {
|
|
87
|
+
if(i == index) { //index+1
|
|
88
|
+
list.appendItem(newseg);
|
|
89
|
+
}
|
|
90
|
+
list.appendItem(arr[i]);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// TODO: See if this should just live in replacePathSeg
|
|
95
|
+
svgedit.path.ptObjToArr = function(type, seg_item) {
|
|
96
|
+
var arr = segData[type], len = arr.length;
|
|
97
|
+
var out = Array(len);
|
|
98
|
+
for(var i=0; i<len; i++) {
|
|
99
|
+
out[i] = seg_item[arr[i]];
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
svgedit.path.getGripPt = function(seg, alt_pt) {
|
|
105
|
+
var out = {
|
|
106
|
+
x: alt_pt? alt_pt.x : seg.item.x,
|
|
107
|
+
y: alt_pt? alt_pt.y : seg.item.y
|
|
108
|
+
}, path = seg.path;
|
|
109
|
+
|
|
110
|
+
if(path.matrix) {
|
|
111
|
+
var pt = svgedit.math.transformPoint(out.x, out.y, path.matrix);
|
|
112
|
+
out = pt;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
out.x *= editorContext_.getCurrentZoom();
|
|
116
|
+
out.y *= editorContext_.getCurrentZoom();
|
|
117
|
+
|
|
118
|
+
return out;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
svgedit.path.getPointFromGrip = function(pt, path) {
|
|
122
|
+
var out = {
|
|
123
|
+
x: pt.x,
|
|
124
|
+
y: pt.y
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if(path.matrix) {
|
|
128
|
+
var pt = svgedit.math.transformPoint(out.x, out.y, path.imatrix);
|
|
129
|
+
out.x = pt.x;
|
|
130
|
+
out.y = pt.y;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
out.x /= editorContext_.getCurrentZoom();
|
|
134
|
+
out.y /= editorContext_.getCurrentZoom();
|
|
135
|
+
|
|
136
|
+
return out;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
svgedit.path.addPointGrip = function(index, x, y) {
|
|
140
|
+
// create the container of all the point grips
|
|
141
|
+
var pointGripContainer = svgedit.path.getGripContainer();
|
|
142
|
+
|
|
143
|
+
var pointGrip = svgedit.utilities.getElem("pathpointgrip_"+index);
|
|
144
|
+
// create it
|
|
145
|
+
if (!pointGrip) {
|
|
146
|
+
pointGrip = document.createElementNS(svgns, "circle");
|
|
147
|
+
svgedit.utilities.assignAttributes(pointGrip, {
|
|
148
|
+
'id': "pathpointgrip_" + index,
|
|
149
|
+
'display': "none",
|
|
150
|
+
'r': 4,
|
|
151
|
+
'fill': "#0FF",
|
|
152
|
+
'stroke': "#00F",
|
|
153
|
+
'stroke-width': 2,
|
|
154
|
+
'cursor': 'move',
|
|
155
|
+
'style': 'pointer-events:all',
|
|
156
|
+
'xlink:title': uiStrings.pathNodeTooltip
|
|
157
|
+
});
|
|
158
|
+
pointGrip = pointGripContainer.appendChild(pointGrip);
|
|
159
|
+
|
|
160
|
+
var grip = $('#pathpointgrip_'+index);
|
|
161
|
+
grip.dblclick(function() {
|
|
162
|
+
if(svgedit.path.path) svgedit.path.path.setSegType();
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if(x && y) {
|
|
166
|
+
// set up the point grip element and display it
|
|
167
|
+
svgedit.utilities.assignAttributes(pointGrip, {
|
|
168
|
+
'cx': x,
|
|
169
|
+
'cy': y,
|
|
170
|
+
'display': "inline"
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return pointGrip;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
svgedit.path.getGripContainer = function() {
|
|
177
|
+
var c = svgedit.utilities.getElem("pathpointgrip_container");
|
|
178
|
+
if (!c) {
|
|
179
|
+
var parent = svgedit.utilities.getElem("selectorParentGroup");
|
|
180
|
+
c = parent.appendChild(document.createElementNS(svgns, "g"));
|
|
181
|
+
c.id = "pathpointgrip_container";
|
|
182
|
+
}
|
|
183
|
+
return c;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
svgedit.path.addCtrlGrip = function(id) {
|
|
187
|
+
var pointGrip = svgedit.utilities.getElem("ctrlpointgrip_"+id);
|
|
188
|
+
if(pointGrip) return pointGrip;
|
|
189
|
+
|
|
190
|
+
pointGrip = document.createElementNS(svgns, "circle");
|
|
191
|
+
svgedit.utilities.assignAttributes(pointGrip, {
|
|
192
|
+
'id': "ctrlpointgrip_" + id,
|
|
193
|
+
'display': "none",
|
|
194
|
+
'r': 4,
|
|
195
|
+
'fill': "#0FF",
|
|
196
|
+
'stroke': "#55F",
|
|
197
|
+
'stroke-width': 1,
|
|
198
|
+
'cursor': 'move',
|
|
199
|
+
'style': 'pointer-events:all',
|
|
200
|
+
'xlink:title': uiStrings.pathCtrlPtTooltip
|
|
201
|
+
});
|
|
202
|
+
svgedit.path.getGripContainer().appendChild(pointGrip);
|
|
203
|
+
return pointGrip;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
svgedit.path.getCtrlLine = function(id) {
|
|
207
|
+
var ctrlLine = svgedit.utilities.getElem("ctrlLine_"+id);
|
|
208
|
+
if(ctrlLine) return ctrlLine;
|
|
209
|
+
|
|
210
|
+
ctrlLine = document.createElementNS(svgns, "line");
|
|
211
|
+
svgedit.utilities.assignAttributes(ctrlLine, {
|
|
212
|
+
'id': "ctrlLine_"+id,
|
|
213
|
+
'stroke': "#555",
|
|
214
|
+
'stroke-width': 1,
|
|
215
|
+
"style": "pointer-events:none"
|
|
216
|
+
});
|
|
217
|
+
svgedit.path.getGripContainer().appendChild(ctrlLine);
|
|
218
|
+
return ctrlLine;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
svgedit.path.getPointGrip = function(seg, update) {
|
|
222
|
+
var index = seg.index;
|
|
223
|
+
var pointGrip = svgedit.path.addPointGrip(index);
|
|
224
|
+
|
|
225
|
+
if(update) {
|
|
226
|
+
var pt = svgedit.path.getGripPt(seg);
|
|
227
|
+
svgedit.utilities.assignAttributes(pointGrip, {
|
|
228
|
+
'cx': pt.x,
|
|
229
|
+
'cy': pt.y,
|
|
230
|
+
'display': "inline"
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return pointGrip;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
svgedit.path.getControlPoints = function(seg) {
|
|
238
|
+
var item = seg.item;
|
|
239
|
+
var index = seg.index;
|
|
240
|
+
if(!("x1" in item) || !("x2" in item)) return null;
|
|
241
|
+
var cpt = {};
|
|
242
|
+
var pointGripContainer = svgedit.path.getGripContainer();
|
|
243
|
+
|
|
244
|
+
// Note that this is intentionally not seg.prev.item
|
|
245
|
+
var prev = svgedit.path.path.segs[index-1].item;
|
|
246
|
+
|
|
247
|
+
var seg_items = [prev, item];
|
|
248
|
+
|
|
249
|
+
for(var i=1; i<3; i++) {
|
|
250
|
+
var id = index + 'c' + i;
|
|
251
|
+
|
|
252
|
+
var ctrlLine = cpt['c' + i + '_line'] = svgedit.path.getCtrlLine(id);
|
|
253
|
+
|
|
254
|
+
var pt = svgedit.path.getGripPt(seg, {x:item['x' + i], y:item['y' + i]});
|
|
255
|
+
var gpt = svgedit.path.getGripPt(seg, {x:seg_items[i-1].x, y:seg_items[i-1].y});
|
|
256
|
+
|
|
257
|
+
svgedit.utilities.assignAttributes(ctrlLine, {
|
|
258
|
+
'x1': pt.x,
|
|
259
|
+
'y1': pt.y,
|
|
260
|
+
'x2': gpt.x,
|
|
261
|
+
'y2': gpt.y,
|
|
262
|
+
'display': "inline"
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
cpt['c' + i + '_line'] = ctrlLine;
|
|
266
|
+
|
|
267
|
+
// create it
|
|
268
|
+
pointGrip = cpt['c' + i] = svgedit.path.addCtrlGrip(id);
|
|
269
|
+
|
|
270
|
+
svgedit.utilities.assignAttributes(pointGrip, {
|
|
271
|
+
'cx': pt.x,
|
|
272
|
+
'cy': pt.y,
|
|
273
|
+
'display': "inline"
|
|
274
|
+
});
|
|
275
|
+
cpt['c' + i] = pointGrip;
|
|
276
|
+
}
|
|
277
|
+
return cpt;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// This replaces the segment at the given index. Type is given as number.
|
|
281
|
+
svgedit.path.replacePathSeg = function(type, index, pts, elem) {
|
|
282
|
+
var path = elem || svgedit.path.path.elem;
|
|
283
|
+
var func = 'createSVGPathSeg' + pathFuncs[type];
|
|
284
|
+
var seg = path[func].apply(path, pts);
|
|
285
|
+
|
|
286
|
+
if(svgedit.browser.supportsPathReplaceItem()) {
|
|
287
|
+
path.pathSegList.replaceItem(seg, index);
|
|
288
|
+
} else {
|
|
289
|
+
var segList = path.pathSegList;
|
|
290
|
+
var len = segList.numberOfItems;
|
|
291
|
+
var arr = [];
|
|
292
|
+
for(var i=0; i<len; i++) {
|
|
293
|
+
var cur_seg = segList.getItem(i);
|
|
294
|
+
arr.push(cur_seg)
|
|
295
|
+
}
|
|
296
|
+
segList.clear();
|
|
297
|
+
for(var i=0; i<len; i++) {
|
|
298
|
+
if(i == index) {
|
|
299
|
+
segList.appendItem(seg);
|
|
300
|
+
} else {
|
|
301
|
+
segList.appendItem(arr[i]);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
svgedit.path.getSegSelector = function(seg, update) {
|
|
308
|
+
var index = seg.index;
|
|
309
|
+
var segLine = svgedit.utilities.getElem("segline_" + index);
|
|
310
|
+
if(!segLine) {
|
|
311
|
+
var pointGripContainer = svgedit.path.getGripContainer();
|
|
312
|
+
// create segline
|
|
313
|
+
segLine = document.createElementNS(svgns, "path");
|
|
314
|
+
svgedit.utilities.assignAttributes(segLine, {
|
|
315
|
+
'id': "segline_" + index,
|
|
316
|
+
'display': 'none',
|
|
317
|
+
'fill': "none",
|
|
318
|
+
'stroke': "#0FF",
|
|
319
|
+
'stroke-width': 2,
|
|
320
|
+
'style':'pointer-events:none',
|
|
321
|
+
'd': 'M0,0 0,0'
|
|
322
|
+
});
|
|
323
|
+
pointGripContainer.appendChild(segLine);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if(update) {
|
|
327
|
+
var prev = seg.prev;
|
|
328
|
+
if(!prev) {
|
|
329
|
+
segLine.setAttribute("display", "none");
|
|
330
|
+
return segLine;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
var pt = svgedit.path.getGripPt(prev);
|
|
334
|
+
// Set start point
|
|
335
|
+
svgedit.path.replacePathSeg(2, 0, [pt.x, pt.y], segLine);
|
|
336
|
+
|
|
337
|
+
var pts = svgedit.path.ptObjToArr(seg.type, seg.item, true);
|
|
338
|
+
for(var i=0; i < pts.length; i+=2) {
|
|
339
|
+
var pt = svgedit.path.getGripPt(seg, {x:pts[i], y:pts[i+1]});
|
|
340
|
+
pts[i] = pt.x;
|
|
341
|
+
pts[i+1] = pt.y;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
svgedit.path.replacePathSeg(seg.type, 1, pts, segLine);
|
|
345
|
+
}
|
|
346
|
+
return segLine;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Function: smoothControlPoints
|
|
350
|
+
// Takes three points and creates a smoother line based on them
|
|
351
|
+
//
|
|
352
|
+
// Parameters:
|
|
353
|
+
// ct1 - Object with x and y values (first control point)
|
|
354
|
+
// ct2 - Object with x and y values (second control point)
|
|
355
|
+
// pt - Object with x and y values (third point)
|
|
356
|
+
//
|
|
357
|
+
// Returns:
|
|
358
|
+
// Array of two "smoothed" point objects
|
|
359
|
+
svgedit.path.smoothControlPoints = this.smoothControlPoints = function(ct1, ct2, pt) {
|
|
360
|
+
// each point must not be the origin
|
|
361
|
+
var x1 = ct1.x - pt.x,
|
|
362
|
+
y1 = ct1.y - pt.y,
|
|
363
|
+
x2 = ct2.x - pt.x,
|
|
364
|
+
y2 = ct2.y - pt.y;
|
|
365
|
+
|
|
366
|
+
if ( (x1 != 0 || y1 != 0) && (x2 != 0 || y2 != 0) ) {
|
|
367
|
+
var anglea = Math.atan2(y1,x1),
|
|
368
|
+
angleb = Math.atan2(y2,x2),
|
|
369
|
+
r1 = Math.sqrt(x1*x1+y1*y1),
|
|
370
|
+
r2 = Math.sqrt(x2*x2+y2*y2),
|
|
371
|
+
nct1 = editorContext_.getSVGRoot().createSVGPoint(),
|
|
372
|
+
nct2 = editorContext_.getSVGRoot().createSVGPoint();
|
|
373
|
+
if (anglea < 0) { anglea += 2*Math.PI; }
|
|
374
|
+
if (angleb < 0) { angleb += 2*Math.PI; }
|
|
375
|
+
|
|
376
|
+
var angleBetween = Math.abs(anglea - angleb),
|
|
377
|
+
angleDiff = Math.abs(Math.PI - angleBetween)/2;
|
|
378
|
+
|
|
379
|
+
var new_anglea, new_angleb;
|
|
380
|
+
if (anglea - angleb > 0) {
|
|
381
|
+
new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
|
|
382
|
+
new_angleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
|
|
386
|
+
new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// rotate the points
|
|
390
|
+
nct1.x = r1 * Math.cos(new_anglea) + pt.x;
|
|
391
|
+
nct1.y = r1 * Math.sin(new_anglea) + pt.y;
|
|
392
|
+
nct2.x = r2 * Math.cos(new_angleb) + pt.x;
|
|
393
|
+
nct2.y = r2 * Math.sin(new_angleb) + pt.y;
|
|
394
|
+
|
|
395
|
+
return [nct1, nct2];
|
|
396
|
+
}
|
|
397
|
+
return undefined;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
svgedit.path.Segment = function(index, item) {
|
|
401
|
+
this.selected = false;
|
|
402
|
+
this.index = index;
|
|
403
|
+
this.item = item;
|
|
404
|
+
this.type = item.pathSegType;
|
|
405
|
+
|
|
406
|
+
this.ctrlpts = [];
|
|
407
|
+
this.ptgrip = null;
|
|
408
|
+
this.segsel = null;
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
svgedit.path.Segment.prototype.showCtrlPts = function(y) {
|
|
412
|
+
for (var i in this.ctrlpts) {
|
|
413
|
+
this.ctrlpts[i].setAttribute("display", y ? "inline" : "none");
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
svgedit.path.Segment.prototype.selectCtrls = function(y) {
|
|
418
|
+
$('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2').
|
|
419
|
+
attr('fill', y ? '#0FF' : '#EEE');
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
svgedit.path.Segment.prototype.show = function(y) {
|
|
423
|
+
if(this.ptgrip) {
|
|
424
|
+
this.ptgrip.setAttribute("display", y ? "inline" : "none");
|
|
425
|
+
this.segsel.setAttribute("display", y ? "inline" : "none");
|
|
426
|
+
// Show/hide all control points if available
|
|
427
|
+
this.showCtrlPts(y);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
svgedit.path.Segment.prototype.select = function(y) {
|
|
432
|
+
if(this.ptgrip) {
|
|
433
|
+
this.ptgrip.setAttribute("stroke", y ? "#0FF" : "#00F");
|
|
434
|
+
this.segsel.setAttribute("display", y ? "inline" : "none");
|
|
435
|
+
if(this.ctrlpts) {
|
|
436
|
+
this.selectCtrls(y);
|
|
437
|
+
}
|
|
438
|
+
this.selected = y;
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
svgedit.path.Segment.prototype.addGrip = function() {
|
|
443
|
+
this.ptgrip = svgedit.path.getPointGrip(this, true);
|
|
444
|
+
this.ctrlpts = svgedit.path.getControlPoints(this, true);
|
|
445
|
+
this.segsel = svgedit.path.getSegSelector(this, true);
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
svgedit.path.Segment.prototype.update = function(full) {
|
|
449
|
+
if(this.ptgrip) {
|
|
450
|
+
var pt = svgedit.path.getGripPt(this);
|
|
451
|
+
svgedit.utilities.assignAttributes(this.ptgrip, {
|
|
452
|
+
'cx': pt.x,
|
|
453
|
+
'cy': pt.y
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
svgedit.path.getSegSelector(this, true);
|
|
457
|
+
|
|
458
|
+
if(this.ctrlpts) {
|
|
459
|
+
if(full) {
|
|
460
|
+
this.item = svgedit.path.path.elem.pathSegList.getItem(this.index);
|
|
461
|
+
this.type = this.item.pathSegType;
|
|
462
|
+
}
|
|
463
|
+
svgedit.path.getControlPoints(this);
|
|
464
|
+
}
|
|
465
|
+
// this.segsel.setAttribute("display", y?"inline":"none");
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
svgedit.path.Segment.prototype.move = function(dx, dy) {
|
|
470
|
+
var item = this.item;
|
|
471
|
+
|
|
472
|
+
if(this.ctrlpts) {
|
|
473
|
+
var cur_pts = [item.x += dx, item.y += dy,
|
|
474
|
+
item.x1, item.y1, item.x2 += dx, item.y2 += dy];
|
|
475
|
+
} else {
|
|
476
|
+
var cur_pts = [item.x += dx, item.y += dy];
|
|
477
|
+
}
|
|
478
|
+
svgedit.path.replacePathSeg(this.type, this.index, cur_pts);
|
|
479
|
+
|
|
480
|
+
if(this.next && this.next.ctrlpts) {
|
|
481
|
+
var next = this.next.item;
|
|
482
|
+
var next_pts = [next.x, next.y,
|
|
483
|
+
next.x1 += dx, next.y1 += dy, next.x2, next.y2];
|
|
484
|
+
svgedit.path.replacePathSeg(this.next.type, this.next.index, next_pts);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if(this.mate) {
|
|
488
|
+
// The last point of a closed subpath has a "mate",
|
|
489
|
+
// which is the "M" segment of the subpath
|
|
490
|
+
var item = this.mate.item;
|
|
491
|
+
var pts = [item.x += dx, item.y += dy];
|
|
492
|
+
svgedit.path.replacePathSeg(this.mate.type, this.mate.index, pts);
|
|
493
|
+
// Has no grip, so does not need "updating"?
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.update(true);
|
|
497
|
+
if(this.next) this.next.update(true);
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
svgedit.path.Segment.prototype.setLinked = function(num) {
|
|
501
|
+
var seg, anum, pt;
|
|
502
|
+
if (num == 2) {
|
|
503
|
+
anum = 1;
|
|
504
|
+
seg = this.next;
|
|
505
|
+
if(!seg) return;
|
|
506
|
+
pt = this.item;
|
|
507
|
+
} else {
|
|
508
|
+
anum = 2;
|
|
509
|
+
seg = this.prev;
|
|
510
|
+
if(!seg) return;
|
|
511
|
+
pt = seg.item;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
var item = seg.item;
|
|
515
|
+
|
|
516
|
+
item['x' + anum] = pt.x + (pt.x - this.item['x' + num]);
|
|
517
|
+
item['y' + anum] = pt.y + (pt.y - this.item['y' + num]);
|
|
518
|
+
|
|
519
|
+
var pts = [item.x, item.y,
|
|
520
|
+
item.x1, item.y1,
|
|
521
|
+
item.x2, item.y2];
|
|
522
|
+
|
|
523
|
+
svgedit.path.replacePathSeg(seg.type, seg.index, pts);
|
|
524
|
+
seg.update(true);
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
svgedit.path.Segment.prototype.moveCtrl = function(num, dx, dy) {
|
|
528
|
+
var item = this.item;
|
|
529
|
+
|
|
530
|
+
item['x' + num] += dx;
|
|
531
|
+
item['y' + num] += dy;
|
|
532
|
+
|
|
533
|
+
var pts = [item.x,item.y,
|
|
534
|
+
item.x1,item.y1, item.x2,item.y2];
|
|
535
|
+
|
|
536
|
+
svgedit.path.replacePathSeg(this.type, this.index, pts);
|
|
537
|
+
this.update(true);
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
svgedit.path.Segment.prototype.setType = function(new_type, pts) {
|
|
541
|
+
svgedit.path.replacePathSeg(new_type, this.index, pts);
|
|
542
|
+
this.type = new_type;
|
|
543
|
+
this.item = svgedit.path.path.elem.pathSegList.getItem(this.index);
|
|
544
|
+
this.showCtrlPts(new_type === 6);
|
|
545
|
+
this.ctrlpts = svgedit.path.getControlPoints(this);
|
|
546
|
+
this.update(true);
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
svgedit.path.Path = function(elem) {
|
|
550
|
+
if(!elem || elem.tagName !== "path") {
|
|
551
|
+
throw "svgedit.path.Path constructed without a <path> element";
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
this.elem = elem;
|
|
555
|
+
this.segs = [];
|
|
556
|
+
this.selected_pts = [];
|
|
557
|
+
svgedit.path.path = this;
|
|
558
|
+
|
|
559
|
+
this.init();
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
// Reset path data
|
|
563
|
+
svgedit.path.Path.prototype.init = function() {
|
|
564
|
+
// Hide all grips, etc
|
|
565
|
+
$(svgedit.path.getGripContainer()).find("*").attr("display", "none");
|
|
566
|
+
var segList = this.elem.pathSegList;
|
|
567
|
+
var len = segList.numberOfItems;
|
|
568
|
+
this.segs = [];
|
|
569
|
+
this.selected_pts = [];
|
|
570
|
+
this.first_seg = null;
|
|
571
|
+
|
|
572
|
+
// Set up segs array
|
|
573
|
+
for(var i=0; i < len; i++) {
|
|
574
|
+
var item = segList.getItem(i);
|
|
575
|
+
var segment = new svgedit.path.Segment(i, item);
|
|
576
|
+
segment.path = this;
|
|
577
|
+
this.segs.push(segment);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
var segs = this.segs;
|
|
581
|
+
var start_i = null;
|
|
582
|
+
|
|
583
|
+
for(var i=0; i < len; i++) {
|
|
584
|
+
var seg = segs[i];
|
|
585
|
+
var next_seg = (i+1) >= len ? null : segs[i+1];
|
|
586
|
+
var prev_seg = (i-1) < 0 ? null : segs[i-1];
|
|
587
|
+
|
|
588
|
+
if(seg.type === 2) {
|
|
589
|
+
if(prev_seg && prev_seg.type !== 1) {
|
|
590
|
+
// New sub-path, last one is open,
|
|
591
|
+
// so add a grip to last sub-path's first point
|
|
592
|
+
var start_seg = segs[start_i];
|
|
593
|
+
start_seg.next = segs[start_i+1];
|
|
594
|
+
start_seg.next.prev = start_seg;
|
|
595
|
+
start_seg.addGrip();
|
|
596
|
+
}
|
|
597
|
+
// Remember that this is a starter seg
|
|
598
|
+
start_i = i;
|
|
599
|
+
} else if(next_seg && next_seg.type === 1) {
|
|
600
|
+
// This is the last real segment of a closed sub-path
|
|
601
|
+
// Next is first seg after "M"
|
|
602
|
+
seg.next = segs[start_i+1];
|
|
603
|
+
|
|
604
|
+
// First seg after "M"'s prev is this
|
|
605
|
+
seg.next.prev = seg;
|
|
606
|
+
seg.mate = segs[start_i];
|
|
607
|
+
seg.addGrip();
|
|
608
|
+
if(this.first_seg == null) {
|
|
609
|
+
this.first_seg = seg;
|
|
610
|
+
}
|
|
611
|
+
} else if(!next_seg) {
|
|
612
|
+
if(seg.type !== 1) {
|
|
613
|
+
// Last seg, doesn't close so add a grip
|
|
614
|
+
// to last sub-path's first point
|
|
615
|
+
var start_seg = segs[start_i];
|
|
616
|
+
start_seg.next = segs[start_i+1];
|
|
617
|
+
start_seg.next.prev = start_seg;
|
|
618
|
+
start_seg.addGrip();
|
|
619
|
+
seg.addGrip();
|
|
620
|
+
|
|
621
|
+
if(!this.first_seg) {
|
|
622
|
+
// Open path, so set first as real first and add grip
|
|
623
|
+
this.first_seg = segs[start_i];
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
} else if(seg.type !== 1){
|
|
627
|
+
// Regular segment, so add grip and its "next"
|
|
628
|
+
seg.addGrip();
|
|
629
|
+
|
|
630
|
+
// Don't set its "next" if it's an "M"
|
|
631
|
+
if(next_seg && next_seg.type !== 2) {
|
|
632
|
+
seg.next = next_seg;
|
|
633
|
+
seg.next.prev = seg;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return this;
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
svgedit.path.Path.prototype.eachSeg = function(fn) {
|
|
641
|
+
var len = this.segs.length
|
|
642
|
+
for(var i=0; i < len; i++) {
|
|
643
|
+
var ret = fn.call(this.segs[i], i);
|
|
644
|
+
if(ret === false) break;
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
svgedit.path.Path.prototype.addSeg = function(index) {
|
|
649
|
+
// Adds a new segment
|
|
650
|
+
var seg = this.segs[index];
|
|
651
|
+
if(!seg.prev) return;
|
|
652
|
+
|
|
653
|
+
var prev = seg.prev;
|
|
654
|
+
var newseg;
|
|
655
|
+
switch(seg.item.pathSegType) {
|
|
656
|
+
case 4:
|
|
657
|
+
var new_x = (seg.item.x + prev.item.x) / 2;
|
|
658
|
+
var new_y = (seg.item.y + prev.item.y) / 2;
|
|
659
|
+
newseg = this.elem.createSVGPathSegLinetoAbs(new_x, new_y);
|
|
660
|
+
break;
|
|
661
|
+
case 6: //make it a curved segment to preserve the shape (WRS)
|
|
662
|
+
// http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation
|
|
663
|
+
var p0_x = (prev.item.x + seg.item.x1)/2;
|
|
664
|
+
var p1_x = (seg.item.x1 + seg.item.x2)/2;
|
|
665
|
+
var p2_x = (seg.item.x2 + seg.item.x)/2;
|
|
666
|
+
var p01_x = (p0_x + p1_x)/2;
|
|
667
|
+
var p12_x = (p1_x + p2_x)/2;
|
|
668
|
+
var new_x = (p01_x + p12_x)/2;
|
|
669
|
+
var p0_y = (prev.item.y + seg.item.y1)/2;
|
|
670
|
+
var p1_y = (seg.item.y1 + seg.item.y2)/2;
|
|
671
|
+
var p2_y = (seg.item.y2 + seg.item.y)/2;
|
|
672
|
+
var p01_y = (p0_y + p1_y)/2;
|
|
673
|
+
var p12_y = (p1_y + p2_y)/2;
|
|
674
|
+
var new_y = (p01_y + p12_y)/2;
|
|
675
|
+
newseg = this.elem.createSVGPathSegCurvetoCubicAbs(new_x,new_y, p0_x,p0_y, p01_x,p01_y);
|
|
676
|
+
var pts = [seg.item.x,seg.item.y,p12_x,p12_y,p2_x,p2_y];
|
|
677
|
+
svgedit.path.replacePathSeg(seg.type,index,pts);
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
svgedit.path.insertItemBefore(this.elem, newseg, index);
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
svgedit.path.Path.prototype.deleteSeg = function(index) {
|
|
685
|
+
var seg = this.segs[index];
|
|
686
|
+
var list = this.elem.pathSegList;
|
|
687
|
+
|
|
688
|
+
seg.show(false);
|
|
689
|
+
var next = seg.next;
|
|
690
|
+
if(seg.mate) {
|
|
691
|
+
// Make the next point be the "M" point
|
|
692
|
+
var pt = [next.item.x, next.item.y];
|
|
693
|
+
svgedit.path.replacePathSeg(2, next.index, pt);
|
|
694
|
+
|
|
695
|
+
// Reposition last node
|
|
696
|
+
svgedit.path.replacePathSeg(4, seg.index, pt);
|
|
697
|
+
|
|
698
|
+
list.removeItem(seg.mate.index);
|
|
699
|
+
} else if(!seg.prev) {
|
|
700
|
+
// First node of open path, make next point the M
|
|
701
|
+
var item = seg.item;
|
|
702
|
+
var pt = [next.item.x, next.item.y];
|
|
703
|
+
svgedit.path.replacePathSeg(2, seg.next.index, pt);
|
|
704
|
+
list.removeItem(index);
|
|
705
|
+
|
|
706
|
+
} else {
|
|
707
|
+
list.removeItem(index);
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
svgedit.path.Path.prototype.subpathIsClosed = function(index) {
|
|
712
|
+
var closed = false;
|
|
713
|
+
// Check if subpath is already open
|
|
714
|
+
svgedit.path.path.eachSeg(function(i) {
|
|
715
|
+
if(i <= index) return true;
|
|
716
|
+
if(this.type === 2) {
|
|
717
|
+
// Found M first, so open
|
|
718
|
+
return false;
|
|
719
|
+
} else if(this.type === 1) {
|
|
720
|
+
// Found Z first, so closed
|
|
721
|
+
closed = true;
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
return closed;
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
svgedit.path.Path.prototype.removePtFromSelection = function(index) {
|
|
730
|
+
var pos = this.selected_pts.indexOf(index);
|
|
731
|
+
if(pos == -1) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
this.segs[index].select(false);
|
|
735
|
+
this.selected_pts.splice(pos, 1);
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
svgedit.path.Path.prototype.clearSelection = function() {
|
|
739
|
+
this.eachSeg(function(i) {
|
|
740
|
+
// 'this' is the segment here
|
|
741
|
+
this.select(false);
|
|
742
|
+
});
|
|
743
|
+
this.selected_pts = [];
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
svgedit.path.Path.prototype.storeD = function() {
|
|
747
|
+
this.last_d = this.elem.getAttribute('d');
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
svgedit.path.Path.prototype.show = function(y) {
|
|
751
|
+
// Shows this path's segment grips
|
|
752
|
+
this.eachSeg(function() {
|
|
753
|
+
// 'this' is the segment here
|
|
754
|
+
this.show(y);
|
|
755
|
+
});
|
|
756
|
+
if(y) {
|
|
757
|
+
this.selectPt(this.first_seg.index);
|
|
758
|
+
}
|
|
759
|
+
return this;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// Move selected points
|
|
763
|
+
svgedit.path.Path.prototype.movePts = function(d_x, d_y) {
|
|
764
|
+
var i = this.selected_pts.length;
|
|
765
|
+
while(i--) {
|
|
766
|
+
var seg = this.segs[this.selected_pts[i]];
|
|
767
|
+
seg.move(d_x, d_y);
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
svgedit.path.Path.prototype.moveCtrl = function(d_x, d_y) {
|
|
772
|
+
var seg = this.segs[this.selected_pts[0]];
|
|
773
|
+
seg.moveCtrl(this.dragctrl, d_x, d_y);
|
|
774
|
+
if(link_control_pts) {
|
|
775
|
+
seg.setLinked(this.dragctrl);
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
svgedit.path.Path.prototype.setSegType = function(new_type) {
|
|
780
|
+
this.storeD();
|
|
781
|
+
var i = this.selected_pts.length;
|
|
782
|
+
var text;
|
|
783
|
+
while(i--) {
|
|
784
|
+
var sel_pt = this.selected_pts[i];
|
|
785
|
+
|
|
786
|
+
// Selected seg
|
|
787
|
+
var cur = this.segs[sel_pt];
|
|
788
|
+
var prev = cur.prev;
|
|
789
|
+
if(!prev) continue;
|
|
790
|
+
|
|
791
|
+
if(!new_type) { // double-click, so just toggle
|
|
792
|
+
text = "Toggle Path Segment Type";
|
|
793
|
+
|
|
794
|
+
// Toggle segment to curve/straight line
|
|
795
|
+
var old_type = cur.type;
|
|
796
|
+
|
|
797
|
+
new_type = (old_type == 6) ? 4 : 6;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
new_type = new_type-0;
|
|
801
|
+
|
|
802
|
+
var cur_x = cur.item.x;
|
|
803
|
+
var cur_y = cur.item.y;
|
|
804
|
+
var prev_x = prev.item.x;
|
|
805
|
+
var prev_y = prev.item.y;
|
|
806
|
+
var points;
|
|
807
|
+
switch ( new_type ) {
|
|
808
|
+
case 6:
|
|
809
|
+
if(cur.olditem) {
|
|
810
|
+
var old = cur.olditem;
|
|
811
|
+
points = [cur_x,cur_y, old.x1,old.y1, old.x2,old.y2];
|
|
812
|
+
} else {
|
|
813
|
+
var diff_x = cur_x - prev_x;
|
|
814
|
+
var diff_y = cur_y - prev_y;
|
|
815
|
+
// get control points from straight line segment
|
|
816
|
+
/*
|
|
817
|
+
var ct1_x = (prev_x + (diff_y/2));
|
|
818
|
+
var ct1_y = (prev_y - (diff_x/2));
|
|
819
|
+
var ct2_x = (cur_x + (diff_y/2));
|
|
820
|
+
var ct2_y = (cur_y - (diff_x/2));
|
|
821
|
+
*/
|
|
822
|
+
//create control points on the line to preserve the shape (WRS)
|
|
823
|
+
var ct1_x = (prev_x + (diff_x/3));
|
|
824
|
+
var ct1_y = (prev_y + (diff_y/3));
|
|
825
|
+
var ct2_x = (cur_x - (diff_x/3));
|
|
826
|
+
var ct2_y = (cur_y - (diff_y/3));
|
|
827
|
+
points = [cur_x,cur_y, ct1_x,ct1_y, ct2_x,ct2_y];
|
|
828
|
+
}
|
|
829
|
+
break;
|
|
830
|
+
case 4:
|
|
831
|
+
points = [cur_x,cur_y];
|
|
832
|
+
|
|
833
|
+
// Store original prevve segment nums
|
|
834
|
+
cur.olditem = cur.item;
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
cur.setType(new_type, points);
|
|
839
|
+
}
|
|
840
|
+
svgedit.path.path.endChanges(text);
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) {
|
|
844
|
+
this.clearSelection();
|
|
845
|
+
if(pt == null) {
|
|
846
|
+
this.eachSeg(function(i) {
|
|
847
|
+
// 'this' is the segment here.
|
|
848
|
+
if(this.prev) {
|
|
849
|
+
pt = i;
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
this.addPtsToSelection(pt);
|
|
854
|
+
if(ctrl_num) {
|
|
855
|
+
this.dragctrl = ctrl_num;
|
|
856
|
+
|
|
857
|
+
if(link_control_pts) {
|
|
858
|
+
this.segs[pt].setLinked(ctrl_num);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// Update position of all points
|
|
864
|
+
svgedit.path.Path.prototype.update = function() {
|
|
865
|
+
var elem = this.elem;
|
|
866
|
+
if(svgedit.utilities.getRotationAngle(elem)) {
|
|
867
|
+
this.matrix = svgedit.math.getMatrix(elem);
|
|
868
|
+
this.imatrix = this.matrix.inverse();
|
|
869
|
+
} else {
|
|
870
|
+
this.matrix = null;
|
|
871
|
+
this.imatrix = null;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
this.eachSeg(function(i) {
|
|
875
|
+
this.item = elem.pathSegList.getItem(i);
|
|
876
|
+
this.update();
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
return this;
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
svgedit.path.getPath_ = function(elem) {
|
|
883
|
+
var p = pathData[elem.id];
|
|
884
|
+
if(!p) p = pathData[elem.id] = new svgedit.path.Path(elem);
|
|
885
|
+
return p;
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
svgedit.path.removePath_ = function(id) {
|
|
889
|
+
if(id in pathData) delete pathData[id];
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
var getRotVals = function(x, y) {
|
|
893
|
+
dx = x - oldcx;
|
|
894
|
+
dy = y - oldcy;
|
|
895
|
+
|
|
896
|
+
// rotate the point around the old center
|
|
897
|
+
r = Math.sqrt(dx*dx + dy*dy);
|
|
898
|
+
theta = Math.atan2(dy,dx) + angle;
|
|
899
|
+
dx = r * Math.cos(theta) + oldcx;
|
|
900
|
+
dy = r * Math.sin(theta) + oldcy;
|
|
901
|
+
|
|
902
|
+
// dx,dy should now hold the actual coordinates of each
|
|
903
|
+
// point after being rotated
|
|
904
|
+
|
|
905
|
+
// now we want to rotate them around the new center in the reverse direction
|
|
906
|
+
dx -= newcx;
|
|
907
|
+
dy -= newcy;
|
|
908
|
+
|
|
909
|
+
r = Math.sqrt(dx*dx + dy*dy);
|
|
910
|
+
theta = Math.atan2(dy,dx) - angle;
|
|
911
|
+
|
|
912
|
+
return {'x':(r * Math.cos(theta) + newcx)/1,
|
|
913
|
+
'y':(r * Math.sin(theta) + newcy)/1};
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
// If the path was rotated, we must now pay the piper:
|
|
917
|
+
// Every path point must be rotated into the rotated coordinate system of
|
|
918
|
+
// its old center, then determine the new center, then rotate it back
|
|
919
|
+
// This is because we want the path to remember its rotation
|
|
920
|
+
|
|
921
|
+
// TODO: This is still using ye olde transform methods, can probably
|
|
922
|
+
// be optimized or even taken care of by recalculateDimensions
|
|
923
|
+
svgedit.path.recalcRotatedPath = function() {
|
|
924
|
+
var current_path = svgedit.path.path.elem;
|
|
925
|
+
var angle = svgedit.utilities.getRotationAngle(current_path, true);
|
|
926
|
+
if(!angle) return;
|
|
927
|
+
// selectedBBoxes[0] = svgedit.path.path.oldbbox;
|
|
928
|
+
var box = svgedit.utilities.getBBox(current_path),
|
|
929
|
+
oldbox = svgedit.path.path.oldbbox,//selectedBBoxes[0],
|
|
930
|
+
oldcx = oldbox.x + oldbox.width/2,
|
|
931
|
+
oldcy = oldbox.y + oldbox.height/2,
|
|
932
|
+
newcx = box.x + box.width/2,
|
|
933
|
+
newcy = box.y + box.height/2,
|
|
934
|
+
|
|
935
|
+
// un-rotate the new center to the proper position
|
|
936
|
+
dx = newcx - oldcx,
|
|
937
|
+
dy = newcy - oldcy,
|
|
938
|
+
r = Math.sqrt(dx*dx + dy*dy),
|
|
939
|
+
theta = Math.atan2(dy,dx) + angle;
|
|
940
|
+
|
|
941
|
+
newcx = r * Math.cos(theta) + oldcx;
|
|
942
|
+
newcy = r * Math.sin(theta) + oldcy;
|
|
943
|
+
|
|
944
|
+
var list = current_path.pathSegList,
|
|
945
|
+
i = list.numberOfItems;
|
|
946
|
+
while (i) {
|
|
947
|
+
i -= 1;
|
|
948
|
+
var seg = list.getItem(i),
|
|
949
|
+
type = seg.pathSegType;
|
|
950
|
+
if(type == 1) continue;
|
|
951
|
+
|
|
952
|
+
var rvals = getRotVals(seg.x,seg.y),
|
|
953
|
+
points = [rvals.x, rvals.y];
|
|
954
|
+
if(seg.x1 != null && seg.x2 != null) {
|
|
955
|
+
c_vals1 = getRotVals(seg.x1, seg.y1);
|
|
956
|
+
c_vals2 = getRotVals(seg.x2, seg.y2);
|
|
957
|
+
points.splice(points.length, 0, c_vals1.x , c_vals1.y, c_vals2.x, c_vals2.y);
|
|
958
|
+
}
|
|
959
|
+
svgedit.path.replacePathSeg(type, i, points);
|
|
960
|
+
} // loop for each point
|
|
961
|
+
|
|
962
|
+
box = svgedit.utilities.getBBox(current_path);
|
|
963
|
+
// selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y;
|
|
964
|
+
// selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height;
|
|
965
|
+
|
|
966
|
+
// now we must set the new transform to be rotated around the new center
|
|
967
|
+
var R_nc = svgroot.createSVGTransform(),
|
|
968
|
+
tlist = svgedit.transformlist.getTransformList(current_path);
|
|
969
|
+
R_nc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
|
|
970
|
+
tlist.replaceItem(R_nc,0);
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
// ====================================
|
|
974
|
+
// Public API starts here
|
|
975
|
+
|
|
976
|
+
svgedit.path.clearData = function() {
|
|
977
|
+
pathData = {};
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
})();
|