github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/internal/pprof/svg/svgpan.go (about)

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