sketchily 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (284) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +39 -0
  3. data/Rakefile +40 -0
  4. data/app/helpers/sketchily.rb~ +10 -0
  5. data/app/helpers/sketchily_helper.rb +10 -0
  6. data/app/views/sketchily/_embed.html.erb +28 -0
  7. data/app/views/sketchily/_embed.html.erb~ +28 -0
  8. data/app/views/sketchily/_embed.js.erb +50 -0
  9. data/app/views/sketchily/_embed.js.erb~ +50 -0
  10. data/app/views/sketchily/_sketchily.html.erb +23 -0
  11. data/app/views/sketchily/_sketchily.html.erb~ +23 -0
  12. data/app/views/sketchily/_sketchily_tag.html.erb +21 -0
  13. data/app/views/sketchily/_sketchily_tag.html.erb~ +21 -0
  14. data/app/views/sketchily/_svg_edit_tag.html.erb~ +51 -0
  15. data/app/views/sketchily/svg_edit_tag_.html~ +35 -0
  16. data/lib/sketchily.rb +15 -0
  17. data/lib/sketchily.rb~ +16 -0
  18. data/lib/sketchily/engine.rb +4 -0
  19. data/lib/sketchily/sketchily.rb +28 -0
  20. data/lib/sketchily/sketchily_show.rb~ +13 -0
  21. data/lib/sketchily/sketchily_tag.rb +15 -0
  22. data/lib/sketchily/svg_edit_tag.rb~ +9 -0
  23. data/lib/sketchily/version.rb +3 -0
  24. data/lib/sketchily/version.rb~ +3 -0
  25. data/spec/dummy/README.rdoc +261 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  28. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  29. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  30. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  31. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/spec/dummy/config.ru +4 -0
  33. data/spec/dummy/config/application.rb +59 -0
  34. data/spec/dummy/config/boot.rb +10 -0
  35. data/spec/dummy/config/database.yml +25 -0
  36. data/spec/dummy/config/environment.rb +5 -0
  37. data/spec/dummy/config/environments/development.rb +37 -0
  38. data/spec/dummy/config/environments/production.rb +67 -0
  39. data/spec/dummy/config/environments/test.rb +37 -0
  40. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec/dummy/config/initializers/inflections.rb +15 -0
  42. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  43. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  44. data/spec/dummy/config/initializers/session_store.rb +8 -0
  45. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  46. data/spec/dummy/config/locales/en.yml +5 -0
  47. data/spec/dummy/config/routes.rb +58 -0
  48. data/spec/dummy/public/404.html +26 -0
  49. data/spec/dummy/public/422.html +26 -0
  50. data/spec/dummy/public/500.html +25 -0
  51. data/spec/dummy/public/favicon.ico +0 -0
  52. data/spec/dummy/script/rails +6 -0
  53. data/spec/lib/sketchily_spec.rb +0 -0
  54. data/spec/spec_helper.rb +11 -0
  55. data/vendor/assets/svg-edit-2.6/browser-not-supported.html +27 -0
  56. data/vendor/assets/svg-edit-2.6/browser.js +180 -0
  57. data/vendor/assets/svg-edit-2.6/canvg/canvg.js +2620 -0
  58. data/vendor/assets/svg-edit-2.6/canvg/rgbcolor.js +287 -0
  59. data/vendor/assets/svg-edit-2.6/contextmenu.js +67 -0
  60. data/vendor/assets/svg-edit-2.6/contextmenu/jquery.contextMenu.js +203 -0
  61. data/vendor/assets/svg-edit-2.6/draw.js +528 -0
  62. data/vendor/assets/svg-edit-2.6/embedapi.html +56 -0
  63. data/vendor/assets/svg-edit-2.6/embedapi.js +173 -0
  64. data/vendor/assets/svg-edit-2.6/extensions/closepath_icons.svg +41 -0
  65. data/vendor/assets/svg-edit-2.6/extensions/ext-arrows.js +298 -0
  66. data/vendor/assets/svg-edit-2.6/extensions/ext-closepath.js +92 -0
  67. data/vendor/assets/svg-edit-2.6/extensions/ext-connector.js +587 -0
  68. data/vendor/assets/svg-edit-2.6/extensions/ext-eyedropper.js +109 -0
  69. data/vendor/assets/svg-edit-2.6/extensions/ext-foreignobject.js +277 -0
  70. data/vendor/assets/svg-edit-2.6/extensions/ext-grid.js +184 -0
  71. data/vendor/assets/svg-edit-2.6/extensions/ext-helloworld.js +78 -0
  72. data/vendor/assets/svg-edit-2.6/extensions/ext-imagelib.js +453 -0
  73. data/vendor/assets/svg-edit-2.6/extensions/ext-imagelib.xml +14 -0
  74. data/vendor/assets/svg-edit-2.6/extensions/ext-markers.js +572 -0
  75. data/vendor/assets/svg-edit-2.6/extensions/ext-server_moinsave.js +56 -0
  76. data/vendor/assets/svg-edit-2.6/extensions/ext-server_opensave.js +180 -0
  77. data/vendor/assets/svg-edit-2.6/extensions/ext-shapes.js +387 -0
  78. data/vendor/assets/svg-edit-2.6/extensions/ext-shapes.xml +10 -0
  79. data/vendor/assets/svg-edit-2.6/extensions/eyedropper-icon.xml +34 -0
  80. data/vendor/assets/svg-edit-2.6/extensions/eyedropper.png +0 -0
  81. data/vendor/assets/svg-edit-2.6/extensions/fileopen.php +31 -0
  82. data/vendor/assets/svg-edit-2.6/extensions/filesave.php +44 -0
  83. data/vendor/assets/svg-edit-2.6/extensions/foreignobject-icons.xml +96 -0
  84. data/vendor/assets/svg-edit-2.6/extensions/grid-icon.xml +30 -0
  85. data/vendor/assets/svg-edit-2.6/extensions/helloworld-icon.xml +21 -0
  86. data/vendor/assets/svg-edit-2.6/extensions/imagelib/index.html +64 -0
  87. data/vendor/assets/svg-edit-2.6/extensions/imagelib/smiley.svg +12 -0
  88. data/vendor/assets/svg-edit-2.6/extensions/markers-icons.xml +115 -0
  89. data/vendor/assets/svg-edit-2.6/extensions/shapelib/animal.json +21 -0
  90. data/vendor/assets/svg-edit-2.6/extensions/shapelib/arrow.json +28 -0
  91. data/vendor/assets/svg-edit-2.6/extensions/shapelib/dialog_balloon.json +9 -0
  92. data/vendor/assets/svg-edit-2.6/extensions/shapelib/electronics.json +20 -0
  93. data/vendor/assets/svg-edit-2.6/extensions/shapelib/flowchart.json +25 -0
  94. data/vendor/assets/svg-edit-2.6/extensions/shapelib/game.json +13 -0
  95. data/vendor/assets/svg-edit-2.6/extensions/shapelib/math.json +9 -0
  96. data/vendor/assets/svg-edit-2.6/extensions/shapelib/misc.json +37 -0
  97. data/vendor/assets/svg-edit-2.6/extensions/shapelib/music.json +21 -0
  98. data/vendor/assets/svg-edit-2.6/extensions/shapelib/object.json +19 -0
  99. data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael.txt +12 -0
  100. data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael_1.json +67 -0
  101. data/vendor/assets/svg-edit-2.6/extensions/shapelib/raphael_2.json +64 -0
  102. data/vendor/assets/svg-edit-2.6/extensions/shapelib/symbol.json +28 -0
  103. data/vendor/assets/svg-edit-2.6/history.js +601 -0
  104. data/vendor/assets/svg-edit-2.6/images/README.txt +61 -0
  105. data/vendor/assets/svg-edit-2.6/images/align-bottom.png +0 -0
  106. data/vendor/assets/svg-edit-2.6/images/align-bottom.svg +277 -0
  107. data/vendor/assets/svg-edit-2.6/images/align-center.png +0 -0
  108. data/vendor/assets/svg-edit-2.6/images/align-center.svg +252 -0
  109. data/vendor/assets/svg-edit-2.6/images/align-left.png +0 -0
  110. data/vendor/assets/svg-edit-2.6/images/align-left.svg +235 -0
  111. data/vendor/assets/svg-edit-2.6/images/align-middle.png +0 -0
  112. data/vendor/assets/svg-edit-2.6/images/align-middle.svg +250 -0
  113. data/vendor/assets/svg-edit-2.6/images/align-right.png +0 -0
  114. data/vendor/assets/svg-edit-2.6/images/align-right.svg +233 -0
  115. data/vendor/assets/svg-edit-2.6/images/align-top.png +0 -0
  116. data/vendor/assets/svg-edit-2.6/images/align-top.svg +233 -0
  117. data/vendor/assets/svg-edit-2.6/images/bold.png +0 -0
  118. data/vendor/assets/svg-edit-2.6/images/cancel.png +0 -0
  119. data/vendor/assets/svg-edit-2.6/images/circle.png +0 -0
  120. data/vendor/assets/svg-edit-2.6/images/clear.png +0 -0
  121. data/vendor/assets/svg-edit-2.6/images/clone.png +0 -0
  122. data/vendor/assets/svg-edit-2.6/images/conn.svg +29 -0
  123. data/vendor/assets/svg-edit-2.6/images/copy.png +0 -0
  124. data/vendor/assets/svg-edit-2.6/images/cut.png +0 -0
  125. data/vendor/assets/svg-edit-2.6/images/delete.png +0 -0
  126. data/vendor/assets/svg-edit-2.6/images/document-properties.png +0 -0
  127. data/vendor/assets/svg-edit-2.6/images/dropdown.gif +0 -0
  128. data/vendor/assets/svg-edit-2.6/images/ellipse.png +0 -0
  129. data/vendor/assets/svg-edit-2.6/images/eye.png +0 -0
  130. data/vendor/assets/svg-edit-2.6/images/fhpath.png +0 -0
  131. data/vendor/assets/svg-edit-2.6/images/flyouth.png +0 -0
  132. data/vendor/assets/svg-edit-2.6/images/flyup.gif +0 -0
  133. data/vendor/assets/svg-edit-2.6/images/freehand-circle.png +0 -0
  134. data/vendor/assets/svg-edit-2.6/images/freehand-square.png +0 -0
  135. data/vendor/assets/svg-edit-2.6/images/go-down.png +0 -0
  136. data/vendor/assets/svg-edit-2.6/images/go-up.png +0 -0
  137. data/vendor/assets/svg-edit-2.6/images/image.png +0 -0
  138. data/vendor/assets/svg-edit-2.6/images/italic.png +0 -0
  139. data/vendor/assets/svg-edit-2.6/images/line.png +0 -0
  140. data/vendor/assets/svg-edit-2.6/images/link_controls.png +0 -0
  141. data/vendor/assets/svg-edit-2.6/images/logo.png +0 -0
  142. data/vendor/assets/svg-edit-2.6/images/logo.svg +32 -0
  143. data/vendor/assets/svg-edit-2.6/images/move_bottom.png +0 -0
  144. data/vendor/assets/svg-edit-2.6/images/move_top.png +0 -0
  145. data/vendor/assets/svg-edit-2.6/images/node_clone.png +0 -0
  146. data/vendor/assets/svg-edit-2.6/images/node_delete.png +0 -0
  147. data/vendor/assets/svg-edit-2.6/images/none.png +0 -0
  148. data/vendor/assets/svg-edit-2.6/images/open.png +0 -0
  149. data/vendor/assets/svg-edit-2.6/images/paste.png +0 -0
  150. data/vendor/assets/svg-edit-2.6/images/path.png +0 -0
  151. data/vendor/assets/svg-edit-2.6/images/polygon.png +0 -0
  152. data/vendor/assets/svg-edit-2.6/images/polygon.svg +219 -0
  153. data/vendor/assets/svg-edit-2.6/images/rect.png +0 -0
  154. data/vendor/assets/svg-edit-2.6/images/redo.png +0 -0
  155. data/vendor/assets/svg-edit-2.6/images/reorient.png +0 -0
  156. data/vendor/assets/svg-edit-2.6/images/rotate.png +0 -0
  157. data/vendor/assets/svg-edit-2.6/images/save.png +0 -0
  158. data/vendor/assets/svg-edit-2.6/images/select.png +0 -0
  159. data/vendor/assets/svg-edit-2.6/images/select_node.png +0 -0
  160. data/vendor/assets/svg-edit-2.6/images/sep.png +0 -0
  161. data/vendor/assets/svg-edit-2.6/images/shape_group.png +0 -0
  162. data/vendor/assets/svg-edit-2.6/images/shape_ungroup.png +0 -0
  163. data/vendor/assets/svg-edit-2.6/images/source.png +0 -0
  164. data/vendor/assets/svg-edit-2.6/images/spinbtn_updn_big.png +0 -0
  165. data/vendor/assets/svg-edit-2.6/images/square.png +0 -0
  166. data/vendor/assets/svg-edit-2.6/images/svg_edit_icons.svg +1034 -0
  167. data/vendor/assets/svg-edit-2.6/images/svg_edit_icons.svgz +0 -0
  168. data/vendor/assets/svg-edit-2.6/images/text.png +0 -0
  169. data/vendor/assets/svg-edit-2.6/images/text.svg +157 -0
  170. data/vendor/assets/svg-edit-2.6/images/to_path.png +0 -0
  171. data/vendor/assets/svg-edit-2.6/images/undo.png +0 -0
  172. data/vendor/assets/svg-edit-2.6/images/view-refresh.png +0 -0
  173. data/vendor/assets/svg-edit-2.6/images/wave.png +0 -0
  174. data/vendor/assets/svg-edit-2.6/images/wireframe.png +0 -0
  175. data/vendor/assets/svg-edit-2.6/images/zoom.png +0 -0
  176. data/vendor/assets/svg-edit-2.6/jgraduate/LICENSE +202 -0
  177. data/vendor/assets/svg-edit-2.6/jgraduate/README +3 -0
  178. data/vendor/assets/svg-edit-2.6/jgraduate/css/jPicker.css +1 -0
  179. data/vendor/assets/svg-edit-2.6/jgraduate/css/jgraduate.css +351 -0
  180. data/vendor/assets/svg-edit-2.6/jgraduate/images/AlphaBar.png +0 -0
  181. data/vendor/assets/svg-edit-2.6/jgraduate/images/Bars.png +0 -0
  182. data/vendor/assets/svg-edit-2.6/jgraduate/images/Maps.png +0 -0
  183. data/vendor/assets/svg-edit-2.6/jgraduate/images/NoColor.png +0 -0
  184. data/vendor/assets/svg-edit-2.6/jgraduate/images/bar-opacity.png +0 -0
  185. data/vendor/assets/svg-edit-2.6/jgraduate/images/map-opacity.png +0 -0
  186. data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint.gif +0 -0
  187. data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint_c.png +0 -0
  188. data/vendor/assets/svg-edit-2.6/jgraduate/images/mappoint_f.png +0 -0
  189. data/vendor/assets/svg-edit-2.6/jgraduate/images/picker.gif +0 -0
  190. data/vendor/assets/svg-edit-2.6/jgraduate/images/preview-opacity.png +0 -0
  191. data/vendor/assets/svg-edit-2.6/jgraduate/images/rangearrows.gif +0 -0
  192. data/vendor/assets/svg-edit-2.6/jgraduate/images/rangearrows2.gif +0 -0
  193. data/vendor/assets/svg-edit-2.6/jgraduate/jpicker.js +2091 -0
  194. data/vendor/assets/svg-edit-2.6/jgraduate/jpicker.min.js +1 -0
  195. data/vendor/assets/svg-edit-2.6/jgraduate/jquery.jgraduate.js +1175 -0
  196. data/vendor/assets/svg-edit-2.6/jgraduate/jquery.jgraduate.min.js +37 -0
  197. data/vendor/assets/svg-edit-2.6/jquery-ui/jquery-ui-1.8.17.custom.min.js +54 -0
  198. data/vendor/assets/svg-edit-2.6/jquery-ui/jquery-ui-1.8.custom.min.js +84 -0
  199. data/vendor/assets/svg-edit-2.6/jquery.js +4 -0
  200. data/vendor/assets/svg-edit-2.6/jquerybbq/jquery.bbq.min.js +18 -0
  201. data/vendor/assets/svg-edit-2.6/js-hotkeys/README.md +45 -0
  202. data/vendor/assets/svg-edit-2.6/js-hotkeys/jquery.hotkeys.min.js +15 -0
  203. data/vendor/assets/svg-edit-2.6/locale/README.txt +17 -0
  204. data/vendor/assets/svg-edit-2.6/locale/lang.af.js +234 -0
  205. data/vendor/assets/svg-edit-2.6/locale/lang.ar.js +234 -0
  206. data/vendor/assets/svg-edit-2.6/locale/lang.az.js +234 -0
  207. data/vendor/assets/svg-edit-2.6/locale/lang.be.js +234 -0
  208. data/vendor/assets/svg-edit-2.6/locale/lang.bg.js +234 -0
  209. data/vendor/assets/svg-edit-2.6/locale/lang.ca.js +234 -0
  210. data/vendor/assets/svg-edit-2.6/locale/lang.cs.js +234 -0
  211. data/vendor/assets/svg-edit-2.6/locale/lang.cy.js +234 -0
  212. data/vendor/assets/svg-edit-2.6/locale/lang.da.js +234 -0
  213. data/vendor/assets/svg-edit-2.6/locale/lang.de.js +234 -0
  214. data/vendor/assets/svg-edit-2.6/locale/lang.el.js +234 -0
  215. data/vendor/assets/svg-edit-2.6/locale/lang.en.js +234 -0
  216. data/vendor/assets/svg-edit-2.6/locale/lang.es.js +234 -0
  217. data/vendor/assets/svg-edit-2.6/locale/lang.et.js +234 -0
  218. data/vendor/assets/svg-edit-2.6/locale/lang.fa.js +234 -0
  219. data/vendor/assets/svg-edit-2.6/locale/lang.fi.js +234 -0
  220. data/vendor/assets/svg-edit-2.6/locale/lang.fr.js +234 -0
  221. data/vendor/assets/svg-edit-2.6/locale/lang.fy.js +234 -0
  222. data/vendor/assets/svg-edit-2.6/locale/lang.ga.js +234 -0
  223. data/vendor/assets/svg-edit-2.6/locale/lang.gl.js +234 -0
  224. data/vendor/assets/svg-edit-2.6/locale/lang.he.js +234 -0
  225. data/vendor/assets/svg-edit-2.6/locale/lang.hi.js +234 -0
  226. data/vendor/assets/svg-edit-2.6/locale/lang.hr.js +234 -0
  227. data/vendor/assets/svg-edit-2.6/locale/lang.hu.js +234 -0
  228. data/vendor/assets/svg-edit-2.6/locale/lang.hy.js +234 -0
  229. data/vendor/assets/svg-edit-2.6/locale/lang.id.js +234 -0
  230. data/vendor/assets/svg-edit-2.6/locale/lang.is.js +234 -0
  231. data/vendor/assets/svg-edit-2.6/locale/lang.it.js +234 -0
  232. data/vendor/assets/svg-edit-2.6/locale/lang.ja.js +234 -0
  233. data/vendor/assets/svg-edit-2.6/locale/lang.ko.js +234 -0
  234. data/vendor/assets/svg-edit-2.6/locale/lang.lt.js +234 -0
  235. data/vendor/assets/svg-edit-2.6/locale/lang.lv.js +234 -0
  236. data/vendor/assets/svg-edit-2.6/locale/lang.mk.js +234 -0
  237. data/vendor/assets/svg-edit-2.6/locale/lang.ms.js +234 -0
  238. data/vendor/assets/svg-edit-2.6/locale/lang.mt.js +234 -0
  239. data/vendor/assets/svg-edit-2.6/locale/lang.nl.js +234 -0
  240. data/vendor/assets/svg-edit-2.6/locale/lang.no.js +234 -0
  241. data/vendor/assets/svg-edit-2.6/locale/lang.pl.js +234 -0
  242. data/vendor/assets/svg-edit-2.6/locale/lang.pt-BR.js +234 -0
  243. data/vendor/assets/svg-edit-2.6/locale/lang.pt-PT.js +234 -0
  244. data/vendor/assets/svg-edit-2.6/locale/lang.ro.js +234 -0
  245. data/vendor/assets/svg-edit-2.6/locale/lang.ru.js +234 -0
  246. data/vendor/assets/svg-edit-2.6/locale/lang.sk.js +234 -0
  247. data/vendor/assets/svg-edit-2.6/locale/lang.sl.js +234 -0
  248. data/vendor/assets/svg-edit-2.6/locale/lang.sq.js +234 -0
  249. data/vendor/assets/svg-edit-2.6/locale/lang.sr.js +234 -0
  250. data/vendor/assets/svg-edit-2.6/locale/lang.sv.js +234 -0
  251. data/vendor/assets/svg-edit-2.6/locale/lang.sw.js +234 -0
  252. data/vendor/assets/svg-edit-2.6/locale/lang.test.js +234 -0
  253. data/vendor/assets/svg-edit-2.6/locale/lang.th.js +234 -0
  254. data/vendor/assets/svg-edit-2.6/locale/lang.tl.js +234 -0
  255. data/vendor/assets/svg-edit-2.6/locale/lang.tr.js +234 -0
  256. data/vendor/assets/svg-edit-2.6/locale/lang.uk.js +234 -0
  257. data/vendor/assets/svg-edit-2.6/locale/lang.vi.js +234 -0
  258. data/vendor/assets/svg-edit-2.6/locale/lang.yi.js +234 -0
  259. data/vendor/assets/svg-edit-2.6/locale/lang.zh-CN.js +234 -0
  260. data/vendor/assets/svg-edit-2.6/locale/lang.zh-HK.js +234 -0
  261. data/vendor/assets/svg-edit-2.6/locale/lang.zh-TW.js +234 -0
  262. data/vendor/assets/svg-edit-2.6/locale/locale.js +320 -0
  263. data/vendor/assets/svg-edit-2.6/math.js +246 -0
  264. data/vendor/assets/svg-edit-2.6/path.js +980 -0
  265. data/vendor/assets/svg-edit-2.6/sanitize.js +273 -0
  266. data/vendor/assets/svg-edit-2.6/select.js +532 -0
  267. data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.css +41 -0
  268. data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.js +266 -0
  269. data/vendor/assets/svg-edit-2.6/spinbtn/JQuerySpinBtn.min.js +7 -0
  270. data/vendor/assets/svg-edit-2.6/spinbtn/spinbtn_updn.png +0 -0
  271. data/vendor/assets/svg-edit-2.6/svg-editor.css +1495 -0
  272. data/vendor/assets/svg-edit-2.6/svg-editor.css~ +1500 -0
  273. data/vendor/assets/svg-edit-2.6/svg-editor.html +788 -0
  274. data/vendor/assets/svg-edit-2.6/svg-editor.html~ +788 -0
  275. data/vendor/assets/svg-edit-2.6/svg-editor.js +4969 -0
  276. data/vendor/assets/svg-edit-2.6/svg-editor.manifest +121 -0
  277. data/vendor/assets/svg-edit-2.6/svgcanvas.js +8775 -0
  278. data/vendor/assets/svg-edit-2.6/svgedit.compiled.js +465 -0
  279. data/vendor/assets/svg-edit-2.6/svgicons/jquery.svgicons.js +486 -0
  280. data/vendor/assets/svg-edit-2.6/svgtransformlist.js +291 -0
  281. data/vendor/assets/svg-edit-2.6/svgutils.js +651 -0
  282. data/vendor/assets/svg-edit-2.6/touch.js +30 -0
  283. data/vendor/assets/svg-edit-2.6/units.js +281 -0
  284. 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
+ })();