暂无描述

svgpan.go 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // SVG pan and zoom library.
  2. // See copyright notice in string constant below.
  3. package svg
  4. // https://www.cyberz.org/projects/SVGPan/SVGPan.js
  5. const svgPanJS = `
  6. /**
  7. * SVGPan library 1.2.1
  8. * ======================
  9. *
  10. * Given an unique existing element with id "viewport" (or when missing, the first g
  11. * element), including the the library into any SVG adds the following capabilities:
  12. *
  13. * - Mouse panning
  14. * - Mouse zooming (using the wheel)
  15. * - Object dragging
  16. *
  17. * You can configure the behaviour of the pan/zoom/drag with the variables
  18. * listed in the CONFIGURATION section of this file.
  19. *
  20. * Known issues:
  21. *
  22. * - Zooming (while panning) on Safari has still some issues
  23. *
  24. * Releases:
  25. *
  26. * 1.2.1, Mon Jul 4 00:33:18 CEST 2011, Andrea Leofreddi
  27. * - Fixed a regression with mouse wheel (now working on Firefox 5)
  28. * - Working with viewBox attribute (#4)
  29. * - Added "use strict;" and fixed resulting warnings (#5)
  30. * - Added configuration variables, dragging is disabled by default (#3)
  31. *
  32. * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
  33. * Fixed a bug with browser mouse handler interaction
  34. *
  35. * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui
  36. * Updated the zoom code to support the mouse wheel on Safari/Chrome
  37. *
  38. * 1.0, Andrea Leofreddi
  39. * First release
  40. *
  41. * This code is licensed under the following BSD license:
  42. *
  43. * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved.
  44. *
  45. * Redistribution and use in source and binary forms, with or without modification, are
  46. * permitted provided that the following conditions are met:
  47. *
  48. * 1. Redistributions of source code must retain the above copyright notice, this list of
  49. * conditions and the following disclaimer.
  50. *
  51. * 2. Redistributions in binary form must reproduce the above copyright notice, this list
  52. * of conditions and the following disclaimer in the documentation and/or other materials
  53. * provided with the distribution.
  54. *
  55. * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ` + "``AS IS''" + ` AND ANY EXPRESS OR IMPLIED
  56. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  57. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
  58. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  59. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  60. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  61. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  62. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  63. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  64. *
  65. * The views and conclusions contained in the software and documentation are those of the
  66. * authors and should not be interpreted as representing official policies, either expressed
  67. * or implied, of Andrea Leofreddi.
  68. */
  69. "use strict";
  70. /// CONFIGURATION
  71. /// ====>
  72. var enablePan = 1; // 1 or 0: enable or disable panning (default enabled)
  73. var enableZoom = 1; // 1 or 0: enable or disable zooming (default enabled)
  74. var enableDrag = 0; // 1 or 0: enable or disable dragging (default disabled)
  75. /// <====
  76. /// END OF CONFIGURATION
  77. var root = document.documentElement;
  78. var state = 'none', svgRoot, stateTarget, stateOrigin, stateTf;
  79. setupHandlers(root);
  80. /**
  81. * Register handlers
  82. */
  83. function setupHandlers(root){
  84. setAttributes(root, {
  85. "onmouseup" : "handleMouseUp(evt)",
  86. "onmousedown" : "handleMouseDown(evt)",
  87. "onmousemove" : "handleMouseMove(evt)",
  88. //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
  89. });
  90. if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
  91. window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
  92. else
  93. window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
  94. }
  95. /**
  96. * Retrieves the root element for SVG manipulation. The element is then cached into the svgRoot global variable.
  97. */
  98. function getRoot(root) {
  99. if(typeof(svgRoot) == "undefined") {
  100. var g = null;
  101. g = root.getElementById("viewport");
  102. if(g == null)
  103. g = root.getElementsByTagName('g')[0];
  104. if(g == null)
  105. alert('Unable to obtain SVG root element');
  106. setCTM(g, g.getCTM());
  107. g.removeAttribute("viewBox");
  108. svgRoot = g;
  109. }
  110. return svgRoot;
  111. }
  112. /**
  113. * Instance an SVGPoint object with given event coordinates.
  114. */
  115. function getEventPoint(evt) {
  116. var p = root.createSVGPoint();
  117. p.x = evt.clientX;
  118. p.y = evt.clientY;
  119. return p;
  120. }
  121. /**
  122. * Sets the current transform matrix of an element.
  123. */
  124. function setCTM(element, matrix) {
  125. var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
  126. element.setAttribute("transform", s);
  127. }
  128. /**
  129. * Dumps a matrix to a string (useful for debug).
  130. */
  131. function dumpMatrix(matrix) {
  132. var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
  133. return s;
  134. }
  135. /**
  136. * Sets attributes of an element.
  137. */
  138. function setAttributes(element, attributes){
  139. for (var i in attributes)
  140. element.setAttributeNS(null, i, attributes[i]);
  141. }
  142. /**
  143. * Handle mouse wheel event.
  144. */
  145. function handleMouseWheel(evt) {
  146. if(!enableZoom)
  147. return;
  148. if(evt.preventDefault)
  149. evt.preventDefault();
  150. evt.returnValue = false;
  151. var svgDoc = evt.target.ownerDocument;
  152. var delta;
  153. if(evt.wheelDelta)
  154. delta = evt.wheelDelta / 3600; // Chrome/Safari
  155. else
  156. delta = evt.detail / -90; // Mozilla
  157. var z = 1 + delta; // Zoom factor: 0.9/1.1
  158. var g = getRoot(svgDoc);
  159. var p = getEventPoint(evt);
  160. p = p.matrixTransform(g.getCTM().inverse());
  161. // Compute new scale matrix in current mouse position
  162. var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
  163. setCTM(g, g.getCTM().multiply(k));
  164. if(typeof(stateTf) == "undefined")
  165. stateTf = g.getCTM().inverse();
  166. stateTf = stateTf.multiply(k.inverse());
  167. }
  168. /**
  169. * Handle mouse move event.
  170. */
  171. function handleMouseMove(evt) {
  172. if(evt.preventDefault)
  173. evt.preventDefault();
  174. evt.returnValue = false;
  175. var svgDoc = evt.target.ownerDocument;
  176. var g = getRoot(svgDoc);
  177. if(state == 'pan' && enablePan) {
  178. // Pan mode
  179. var p = getEventPoint(evt).matrixTransform(stateTf);
  180. setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
  181. } else if(state == 'drag' && enableDrag) {
  182. // Drag mode
  183. var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
  184. setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
  185. stateOrigin = p;
  186. }
  187. }
  188. /**
  189. * Handle click event.
  190. */
  191. function handleMouseDown(evt) {
  192. if(evt.preventDefault)
  193. evt.preventDefault();
  194. evt.returnValue = false;
  195. var svgDoc = evt.target.ownerDocument;
  196. var g = getRoot(svgDoc);
  197. if(
  198. evt.target.tagName == "svg"
  199. || !enableDrag // Pan anyway when drag is disabled and the user clicked on an element
  200. ) {
  201. // Pan mode
  202. state = 'pan';
  203. stateTf = g.getCTM().inverse();
  204. stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
  205. } else {
  206. // Drag mode
  207. state = 'drag';
  208. stateTarget = evt.target;
  209. stateTf = g.getCTM().inverse();
  210. stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
  211. }
  212. }
  213. /**
  214. * Handle mouse button release event.
  215. */
  216. function handleMouseUp(evt) {
  217. if(evt.preventDefault)
  218. evt.preventDefault();
  219. evt.returnValue = false;
  220. var svgDoc = evt.target.ownerDocument;
  221. if(state == 'pan' || state == 'drag') {
  222. // Quit pan mode
  223. state = '';
  224. }
  225. }
  226. `