about summary refs log tree commit diff
path: root/sourcecodes/scripts/cytoscape-panzoom.js
diff options
context:
space:
mode:
authorziejd22021-02-24 14:36:59 -0600
committerziejd22021-02-24 14:36:59 -0600
commit25b843f6bbacb1937bdb960777b73acbece64115 (patch)
tree88645b9d1d8a0eea19d7229555bf8805571bc8b7 /sourcecodes/scripts/cytoscape-panzoom.js
parent33cedf36248f616aa37d1462c69a4a3058a5d92e (diff)
downloadBNW-25b843f6bbacb1937bdb960777b73acbece64115.tar.gz
GENENET8 update
Diffstat (limited to 'sourcecodes/scripts/cytoscape-panzoom.js')
-rw-r--r--sourcecodes/scripts/cytoscape-panzoom.js587
1 files changed, 587 insertions, 0 deletions
diff --git a/sourcecodes/scripts/cytoscape-panzoom.js b/sourcecodes/scripts/cytoscape-panzoom.js
new file mode 100644
index 00000000..77ac7355
--- /dev/null
+++ b/sourcecodes/scripts/cytoscape-panzoom.js
@@ -0,0 +1,587 @@
+/*!
+Copyright (c) The Cytoscape Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the “Software”), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+;(function(){ 'use strict';
+
+  // registers the extension on a cytoscape lib ref
+  var register = function( cytoscape, $ ){
+    if( !cytoscape || !$ ){ return; } // can't register if cytoscape or jquery unspecified
+
+    $.fn.cyPanzoom = $.fn.cytoscapePanzoom = function( options ){
+      panzoom.apply( this, [ options, cytoscape, $ ] );
+
+      return this; // chainability
+    };
+
+    // if you want a core extension
+    cytoscape('core', 'panzoom', function( options ){ // could use options object, but args are up to you
+      panzoom.apply( this, [ options, cytoscape, $ ] );
+
+      return this; // chainability
+    });
+
+  };
+
+  var defaults = {
+    zoomFactor: 0.05, // zoom factor per zoom tick
+    zoomDelay: 45, // how many ms between zoom ticks
+    minZoom: 0.1, // min zoom level
+    maxZoom: 10, // max zoom level
+    fitPadding: 50, // padding when fitting
+    panSpeed: 10, // how many ms in between pan ticks
+    panDistance: 10, // max pan distance per tick
+    panDragAreaSize: 75, // the length of the pan drag box in which the vector for panning is calculated (bigger = finer control of pan speed and direction)
+    panMinPercentSpeed: 0.25, // the slowest speed we can pan by (as a percent of panSpeed)
+    panInactiveArea: 8, // radius of inactive area in pan drag box
+    panIndicatorMinOpacity: 0.5, // min opacity of pan indicator (the draggable nib); scales from this to 1.0
+    zoomOnly: false, // a minimal version of the ui only with zooming (useful on systems with bad mousewheel resolution)
+    fitSelector: undefined, // selector of elements to fit
+    animateOnFit: function(){ // whether to animate on fit
+      return false;
+    },
+    fitAnimationDuration: 1000, // duration of animation on fit
+
+    // icon class names
+    sliderHandleIcon: 'fa fa-minus',
+    zoomInIcon: 'fa fa-plus',
+    zoomOutIcon: 'fa fa-minus',
+    resetIcon: 'fa fa-expand'
+  };
+
+  var panzoom = function( params, cytoscape, $ ){
+    var cyRef = this;
+    var options = $.extend(true, {}, defaults, params);
+    var fn = params;
+
+    var functions = {
+      destroy: function(){
+        var $this = $(cyRef.container());
+        var $pz = $this.find(".cy-panzoom");
+
+        $pz.data('winbdgs').forEach(function( l ){
+          $(window).unbind( l.evt, l.fn );
+        });
+
+        $pz.data('cybdgs').forEach(function( l ){
+          cyRef.off( l.evt, l.fn );
+        });
+
+        $pz.remove();
+      },
+
+      init: function(){
+        var browserIsMobile = 'ontouchstart' in window;
+
+        return $(cyRef.container()).each(function(){
+          var $container = $(this);
+          $container.cytoscape = cytoscape;
+
+          var winbdgs = [];
+          var $win = $(window);
+
+          var windowBind = function( evt, fn ){
+            winbdgs.push({ evt: evt, fn: fn });
+
+            $win.bind( evt, fn );
+          };
+
+          var windowUnbind = function( evt, fn ){
+            for( var i = 0; i < winbdgs.length; i++ ){
+              var l = winbdgs[i];
+
+              if( l.evt === evt && l.fn === fn ){
+                winbdgs.splice( i, 1 );
+                break;
+              }
+            }
+
+            $win.unbind( evt, fn );
+          };
+
+          var cybdgs = [];
+
+          var cyOn = function( evt, fn ){
+            cybdgs.push({ evt: evt, fn: fn });
+
+            cyRef.on( evt, fn );
+          };
+
+          var cyOff = function( evt, fn ){
+            for( var i = 0; i < cybdgs.length; i++ ){
+              var l = cybdgs[i];
+
+              if( l.evt === evt && l.fn === fn ){
+                cybdgs.splice( i, 1 );
+                break;
+              }
+            }
+
+            cyRef.off( evt, fn );
+          };
+
+          var $panzoom = $('<div class="cy-panzoom"></div>');
+          $container.prepend( $panzoom );
+
+          $panzoom.css('position', 'absolute'); // must be absolute regardless of stylesheet
+
+          $panzoom.data('winbdgs', winbdgs);
+          $panzoom.data('cybdgs', cybdgs);
+
+          if( options.zoomOnly ){
+            $panzoom.addClass("cy-panzoom-zoom-only");
+          }
+
+          // add base html elements
+          /////////////////////////
+
+          var $zoomIn = $('<div class="cy-panzoom-zoom-in cy-panzoom-zoom-button"><span class="icon '+ options.zoomInIcon +'"></span></div>');
+          $panzoom.append( $zoomIn );
+
+          var $zoomOut = $('<div class="cy-panzoom-zoom-out cy-panzoom-zoom-button"><span class="icon ' + options.zoomOutIcon + '"></span></div>');
+          $panzoom.append( $zoomOut );
+
+          var $reset = $('<div class="cy-panzoom-reset cy-panzoom-zoom-button"><span class="icon ' + options.resetIcon + '"></span></div>');
+          $panzoom.append( $reset );
+
+          var $slider = $('<div class="cy-panzoom-slider"></div>');
+          $panzoom.append( $slider );
+
+          $slider.append('<div class="cy-panzoom-slider-background"></div>');
+
+          var $sliderHandle = $('<div class="cy-panzoom-slider-handle"><span class="icon ' + options.sliderHandleIcon + '"></span></div>');
+          $slider.append( $sliderHandle );
+
+          var $noZoomTick = $('<div class="cy-panzoom-no-zoom-tick"></div>');
+          $slider.append( $noZoomTick );
+
+          var $panner = $('<div class="cy-panzoom-panner"></div>');
+          $panzoom.append( $panner );
+
+          var $pHandle = $('<div class="cy-panzoom-panner-handle"></div>');
+          $panner.append( $pHandle );
+
+          var $pUp = $('<div class="cy-panzoom-pan-up cy-panzoom-pan-button"></div>');
+          var $pDown = $('<div class="cy-panzoom-pan-down cy-panzoom-pan-button"></div>');
+          var $pLeft = $('<div class="cy-panzoom-pan-left cy-panzoom-pan-button"></div>');
+          var $pRight = $('<div class="cy-panzoom-pan-right cy-panzoom-pan-button"></div>');
+          $panner.append( $pUp ).append( $pDown ).append( $pLeft ).append( $pRight );
+
+          var $pIndicator = $('<div class="cy-panzoom-pan-indicator"></div>');
+          $panner.append( $pIndicator );
+
+          // functions for calculating panning
+          ////////////////////////////////////
+
+          function handle2pan(e){
+            var v = {
+              x: e.originalEvent.pageX - $panner.offset().left - $panner.width()/2,
+              y: e.originalEvent.pageY - $panner.offset().top - $panner.height()/2
+            }
+
+            var r = options.panDragAreaSize;
+            var d = Math.sqrt( v.x*v.x + v.y*v.y );
+            var percent = Math.min( d/r, 1 );
+
+            if( d < options.panInactiveArea ){
+              return {
+                x: NaN,
+                y: NaN
+              };
+            }
+
+            v = {
+              x: v.x/d,
+              y: v.y/d
+            };
+
+            percent = Math.max( options.panMinPercentSpeed, percent );
+
+            var vnorm = {
+              x: -1 * v.x * (percent * options.panDistance),
+              y: -1 * v.y * (percent * options.panDistance)
+            };
+
+            return vnorm;
+          }
+
+          function donePanning(){
+            clearInterval(panInterval);
+            windowUnbind("mousemove", handler);
+
+            $pIndicator.hide();
+          }
+
+          function positionIndicator(pan){
+            var v = pan;
+            var d = Math.sqrt( v.x*v.x + v.y*v.y );
+            var vnorm = {
+              x: -1 * v.x/d,
+              y: -1 * v.y/d
+            };
+
+            var w = $panner.width();
+            var h = $panner.height();
+            var percent = d/options.panDistance;
+            var opacity = Math.max( options.panIndicatorMinOpacity, percent );
+            var color = 255 - Math.round( opacity * 255 );
+
+            $pIndicator.show().css({
+              left: w/2 * vnorm.x + w/2,
+              top: h/2 * vnorm.y + h/2,
+              background: "rgb(" + color + ", " + color + ", " + color + ")"
+            });
+          }
+
+          function calculateZoomCenterPoint(){
+            var pan = cyRef.pan();
+            var zoom = cyRef.zoom();
+
+            zx = $container.width()/2;
+            zy = $container.height()/2;
+          }
+
+          var zooming = false;
+          function startZooming(){
+            zooming = true;
+
+            calculateZoomCenterPoint();
+          }
+
+
+          function endZooming(){
+            zooming = false;
+          }
+
+          var zx, zy;
+          function zoomTo(level){
+            if( !zooming ){ // for non-continuous zooming (e.g. click slider at pt)
+              calculateZoomCenterPoint();
+            }
+
+            cyRef.zoom({
+              level: level,
+              renderedPosition: { x: zx, y: zy }
+            });
+          }
+
+          var panInterval;
+
+          var handler = function(e){
+            e.stopPropagation(); // don't trigger dragging of panzoom
+            e.preventDefault(); // don't cause text selection
+            clearInterval(panInterval);
+
+            var pan = handle2pan(e);
+
+            if( isNaN(pan.x) || isNaN(pan.y) ){
+              $pIndicator.hide();
+              return;
+            }
+
+            positionIndicator(pan);
+            panInterval = setInterval(function(){
+              cyRef.panBy(pan);
+            }, options.panSpeed);
+          };
+
+          $pHandle.bind("mousedown", function(e){
+            // handle click of icon
+            handler(e);
+
+            // update on mousemove
+            windowBind("mousemove", handler);
+          });
+
+          $pHandle.bind("mouseup", function(){
+            donePanning();
+          });
+
+          windowBind("mouseup blur", function(){
+            donePanning();
+          });
+
+
+
+          // set up slider behaviour
+          //////////////////////////
+
+          $slider.bind('mousedown', function(){
+            return false; // so we don't pan close to the slider handle
+          });
+
+          var sliderVal;
+          var sliding = false;
+          var sliderPadding = 2;
+
+          function setSliderFromMouse(evt, handleOffset){
+            if( handleOffset === undefined ){
+              handleOffset = 0;
+            }
+
+            var padding = sliderPadding;
+            var min = 0 + padding;
+            var max = $slider.height() - $sliderHandle.height() - 2*padding;
+            var top = evt.pageY - $slider.offset().top - handleOffset;
+
+            // constrain to slider bounds
+            if( top < min ){ top = min }
+            if( top > max ){ top = max }
+
+            var percent = 1 - (top - min) / ( max - min );
+
+            // move the handle
+            $sliderHandle.css('top', top);
+
+            var zmin = options.minZoom;
+            var zmax = options.maxZoom;
+
+            // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+            var x = Math.log(zmin) / Math.log(zmax);
+            var p = (1 - x)*percent + x;
+
+            // change the zoom level
+            var z = Math.pow( zmax, p );
+
+            // bound the zoom value in case of floating pt rounding error
+            if( z < zmin ){
+              z = zmin;
+            } else if( z > zmax ){
+              z = zmax;
+            }
+
+            zoomTo( z );
+          }
+
+          var sliderMdownHandler, sliderMmoveHandler;
+          $sliderHandle.bind('mousedown', sliderMdownHandler = function( mdEvt ){
+            var handleOffset = mdEvt.target === $sliderHandle[0] ? mdEvt.offsetY : 0;
+            sliding = true;
+
+            startZooming();
+            $sliderHandle.addClass("active");
+
+            var lastMove = 0;
+            windowBind('mousemove', sliderMmoveHandler = function( mmEvt ){
+              var now = +new Date;
+
+              // throttle the zooms every 10 ms so we don't call zoom too often and cause lag
+              if( now > lastMove + 10 ){
+                lastMove = now;
+              } else {
+                return false;
+              }
+
+              setSliderFromMouse(mmEvt, handleOffset);
+
+              return false;
+            });
+
+            // unbind when
+            windowBind('mouseup', function(){
+              windowUnbind('mousemove', sliderMmoveHandler);
+              sliding = false;
+
+              $sliderHandle.removeClass("active");
+              endZooming();
+            });
+
+            return false;
+          });
+
+          $slider.bind('mousedown', function(e){
+            if( e.target !== $sliderHandle[0] ){
+              sliderMdownHandler(e);
+              setSliderFromMouse(e);
+            }
+          });
+
+          function positionSliderFromZoom(){
+            var z = cyRef.zoom();
+            var zmin = options.minZoom;
+            var zmax = options.maxZoom;
+
+            // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+            var x = Math.log(zmin) / Math.log(zmax);
+            var p = Math.log(z) / Math.log(zmax);
+            var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction
+
+            var min = sliderPadding;
+            var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding;
+            var top = percent * ( max - min );
+
+            // constrain to slider bounds
+            if( top < min ){ top = min }
+            if( top > max ){ top = max }
+
+            // move the handle
+            $sliderHandle.css('top', top);
+          }
+
+          positionSliderFromZoom();
+
+          cyOn('zoom', function(){
+            if( !sliding ){
+              positionSliderFromZoom();
+            }
+          });
+
+          // set the position of the zoom=1 tick
+          (function(){
+            var z = 1;
+            var zmin = options.minZoom;
+            var zmax = options.maxZoom;
+
+            // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative
+            var x = Math.log(zmin) / Math.log(zmax);
+            var p = Math.log(z) / Math.log(zmax);
+            var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction
+
+            if( percent > 1 || percent < 0 ){
+              $noZoomTick.hide();
+              return;
+            }
+
+            var min = sliderPadding;
+            var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding;
+            var top = percent * ( max - min );
+
+            // constrain to slider bounds
+            if( top < min ){ top = min }
+            if( top > max ){ top = max }
+
+            $noZoomTick.css('top', top);
+          })();
+
+          // set up zoom in/out buttons
+          /////////////////////////////
+
+          function bindButton($button, factor){
+            var zoomInterval;
+
+            $button.bind("mousedown", function(e){
+              e.preventDefault();
+              e.stopPropagation();
+
+              if( e.button != 0 ){
+                return;
+              }
+
+              var doZoom = function(){
+                var zoom = cyRef.zoom();
+                var lvl = cyRef.zoom() * factor;
+
+                if( lvl < options.minZoom ){
+                  lvl = options.minZoom;
+                }
+
+                if( lvl > options.maxZoom ){
+                  lvl = options.maxZoom;
+                }
+
+                if( (lvl == options.maxZoom && zoom == options.maxZoom) ||
+                  (lvl == options.minZoom && zoom == options.minZoom)
+                ){
+                  return;
+                }
+
+                zoomTo(lvl);
+              };
+
+              startZooming();
+              doZoom();
+              zoomInterval = setInterval(doZoom, options.zoomDelay);
+
+              return false;
+            });
+
+            windowBind("mouseup blur", function(){
+              clearInterval(zoomInterval);
+              endZooming();
+            });
+          }
+
+          bindButton( $zoomIn, (1 + options.zoomFactor) );
+          bindButton( $zoomOut, (1 - options.zoomFactor) );
+
+          $reset.bind("mousedown", function(e){
+            if( e.button != 0 ){
+              return;
+            }
+
+            var elesToFit = options.fitSelector?cyRef.elements(options.fitSelector):cyRef.elements();
+
+            if( elesToFit.size() === 0 ){
+              cyRef.reset();
+            } else {
+              var animateOnFit = typeof options.animateOnFit === 'function' ? options.animateOnFit.call() : options.animateOnFit;
+              if(animateOnFit){
+                cyRef.animate({
+                  fit: {
+                    eles: elesToFit,
+                    padding: options.fitPadding
+                  }
+                }, {
+                  duration: options.fitAnimationDuration
+                });
+              }
+              else{
+                cyRef.fit( elesToFit, options.fitPadding );
+              }
+
+            }
+
+            return false;
+          });
+
+
+
+        });
+      }
+    };
+
+    if( functions[fn] ){
+      return functions[fn].apply(this, Array.prototype.slice.call( arguments, 1 ));
+    } else if( typeof fn == 'object' || !fn ) {
+      return functions.init.apply( this, arguments );
+    } else {
+      $.error("No such function `"+ fn +"` for jquery.cytoscapePanzoom");
+    }
+
+    return $(this);
+  };
+
+
+  if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module
+    module.exports = function( cytoscape, jquery ){
+      register( cytoscape, jquery || require('jquery') );
+    }
+  } else if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module
+    define('cytoscape-panzoom', function(){
+      return register;
+    });
+  }
+
+  if( typeof cytoscape !== 'undefined' && typeof jQuery !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape)
+    register( cytoscape, jQuery );
+  }
+
+})();