UNPKG

react-sigma-conglei

Version:

Lightweight but powerful library for drawing network graphs built on top of dunnock/react-sigma

1,733 lines (1,492 loc) 274 kB
var Sigma = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 81); /******/ }) /************************************************************************/ /******/ (Array(34).concat([ /* 34 */ /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(undefined) { 'use strict'; if (typeof sigma === 'undefined') throw 'sigma is not declared'; // Initialize packages: sigma.utils.pkg('sigma.captors'); /** * The user inputs default captor. It deals with mouse events, keyboards * events and touch events. * * @param {DOMElement} target The DOM element where the listeners will be * bound. * @param {camera} camera The camera related to the target. * @param {configurable} settings The settings function. * @return {sigma.captor} The fresh new captor instance. */ sigma.captors.mouse = function(target, camera, settings) { var _self = this, _target = target, _camera = camera, _settings = settings, // CAMERA MANAGEMENT: // ****************** // The camera position when the user starts dragging: _startCameraX, _startCameraY, _startCameraAngle, // The latest stage position: _lastCameraX, _lastCameraY, _lastCameraAngle, _lastCameraRatio, // MOUSE MANAGEMENT: // ***************** // The mouse position when the user starts dragging: _startMouseX, _startMouseY, _isMouseDown, _isMoving, _hasDragged, _downStartTime, _movingTimeoutId; sigma.classes.dispatcher.extend(this); sigma.utils.doubleClick(_target, 'click', _doubleClickHandler); _target.addEventListener('DOMMouseScroll', _wheelHandler, false); _target.addEventListener('mousewheel', _wheelHandler, false); _target.addEventListener('mousemove', _moveHandler, false); _target.addEventListener('mousedown', _downHandler, false); _target.addEventListener('click', _clickHandler, false); _target.addEventListener('mouseout', _outHandler, false); document.addEventListener('mouseup', _upHandler, false); /** * This method unbinds every handlers that makes the captor work. */ this.kill = function() { sigma.utils.unbindDoubleClick(_target, 'click'); _target.removeEventListener('DOMMouseScroll', _wheelHandler); _target.removeEventListener('mousewheel', _wheelHandler); _target.removeEventListener('mousemove', _moveHandler); _target.removeEventListener('mousedown', _downHandler); _target.removeEventListener('click', _clickHandler); _target.removeEventListener('mouseout', _outHandler); document.removeEventListener('mouseup', _upHandler); }; // MOUSE EVENTS: // ************* /** * The handler listening to the 'move' mouse event. It will effectively * drag the graph. * * @param {event} e A mouse event. */ function _moveHandler(e) { var x, y, pos; // Dispatch event: if (_settings('mouseEnabled')) { _self.dispatchEvent('mousemove', sigma.utils.mouseCoords(e)); if (_isMouseDown) { _isMoving = true; _hasDragged = true; if (_movingTimeoutId) clearTimeout(_movingTimeoutId); _movingTimeoutId = setTimeout(function() { _isMoving = false; }, _settings('dragTimeout')); sigma.misc.animation.killAll(_camera); _camera.isMoving = true; pos = _camera.cameraPosition( sigma.utils.getX(e) - _startMouseX, sigma.utils.getY(e) - _startMouseY, true ); x = _startCameraX - pos.x; y = _startCameraY - pos.y; if (x !== _camera.x || y !== _camera.y) { _lastCameraX = _camera.x; _lastCameraY = _camera.y; _camera.goTo({ x: x, y: y }); } if (e.preventDefault) e.preventDefault(); else e.returnValue = false; e.stopPropagation(); return false; } } } /** * The handler listening to the 'up' mouse event. It will stop dragging the * graph. * * @param {event} e A mouse event. */ function _upHandler(e) { if (_settings('mouseEnabled') && _isMouseDown) { _isMouseDown = false; if (_movingTimeoutId) clearTimeout(_movingTimeoutId); _camera.isMoving = false; var x = sigma.utils.getX(e), y = sigma.utils.getY(e); if (_isMoving) { sigma.misc.animation.killAll(_camera); sigma.misc.animation.camera( _camera, { x: _camera.x + _settings('mouseInertiaRatio') * (_camera.x - _lastCameraX), y: _camera.y + _settings('mouseInertiaRatio') * (_camera.y - _lastCameraY) }, { easing: 'quadraticOut', duration: _settings('mouseInertiaDuration') } ); } else if ( _startMouseX !== x || _startMouseY !== y ) _camera.goTo({ x: _camera.x, y: _camera.y }); _self.dispatchEvent('mouseup', sigma.utils.mouseCoords(e)); // Update _isMoving flag: _isMoving = false; } } /** * The handler listening to the 'down' mouse event. It will start observing * the mouse position for dragging the graph. * * @param {event} e A mouse event. */ function _downHandler(e) { if (_settings('mouseEnabled')) { _startCameraX = _camera.x; _startCameraY = _camera.y; _lastCameraX = _camera.x; _lastCameraY = _camera.y; _startMouseX = sigma.utils.getX(e); _startMouseY = sigma.utils.getY(e); _hasDragged = false; _downStartTime = (new Date()).getTime(); switch (e.which) { case 2: // Middle mouse button pressed // Do nothing. break; case 3: // Right mouse button pressed _self.dispatchEvent('rightclick', sigma.utils.mouseCoords(e, _startMouseX, _startMouseY)); break; // case 1: default: // Left mouse button pressed _isMouseDown = true; _self.dispatchEvent('mousedown', sigma.utils.mouseCoords(e, _startMouseX, _startMouseY)); } } } /** * The handler listening to the 'out' mouse event. It will just redispatch * the event. * * @param {event} e A mouse event. */ function _outHandler(e) { if (_settings('mouseEnabled')) _self.dispatchEvent('mouseout'); } /** * The handler listening to the 'click' mouse event. It will redispatch the * click event, but with normalized X and Y coordinates. * * @param {event} e A mouse event. */ function _clickHandler(e) { if (_settings('mouseEnabled')) { var event = sigma.utils.mouseCoords(e); event.isDragging = (((new Date()).getTime() - _downStartTime) > 100) && _hasDragged; _self.dispatchEvent('click', event); } if (e.preventDefault) e.preventDefault(); else e.returnValue = false; e.stopPropagation(); return false; } /** * The handler listening to the double click custom event. It will * basically zoom into the graph. * * @param {event} e A mouse event. */ function _doubleClickHandler(e) { var pos, ratio, animation; if (_settings('mouseEnabled')) { ratio = 1 / _settings('doubleClickZoomingRatio'); _self.dispatchEvent('doubleclick', sigma.utils.mouseCoords(e, _startMouseX, _startMouseY)); if (_settings('doubleClickEnabled')) { pos = _camera.cameraPosition( sigma.utils.getX(e) - sigma.utils.getCenter(e).x, sigma.utils.getY(e) - sigma.utils.getCenter(e).y, true ); animation = { duration: _settings('doubleClickZoomDuration') }; sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); } if (e.preventDefault) e.preventDefault(); else e.returnValue = false; e.stopPropagation(); return false; } } /** * The handler listening to the 'wheel' mouse event. It will basically zoom * in or not into the graph. * * @param {event} e A mouse event. */ function _wheelHandler(e) { var pos, ratio, animation, wheelDelta = sigma.utils.getDelta(e); if (_settings('mouseEnabled') && _settings('mouseWheelEnabled') && wheelDelta !== 0) { ratio = wheelDelta > 0 ? 1 / _settings('zoomingRatio') : _settings('zoomingRatio'); pos = _camera.cameraPosition( sigma.utils.getX(e) - sigma.utils.getCenter(e).x, sigma.utils.getY(e) - sigma.utils.getCenter(e).y, true ); animation = { duration: _settings('mouseZoomDuration') }; sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); if (e.preventDefault) e.preventDefault(); else e.returnValue = false; e.stopPropagation(); return false; } } }; }).call(this); }.call(window)); /***/ }), /* 35 */ /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(undefined) { 'use strict'; if (typeof sigma === 'undefined') throw 'sigma is not declared'; // Initialize packages: sigma.utils.pkg('sigma.captors'); /** * The user inputs default captor. It deals with mouse events, keyboards * events and touch events. * * @param {DOMElement} target The DOM element where the listeners will be * bound. * @param {camera} camera The camera related to the target. * @param {configurable} settings The settings function. * @return {sigma.captor} The fresh new captor instance. */ sigma.captors.touch = function(target, camera, settings) { var _self = this, _target = target, _camera = camera, _settings = settings, // CAMERA MANAGEMENT: // ****************** // The camera position when the user starts dragging: _startCameraX, _startCameraY, _startCameraAngle, _startCameraRatio, // The latest stage position: _lastCameraX, _lastCameraY, _lastCameraAngle, _lastCameraRatio, // TOUCH MANAGEMENT: // ***************** // Touches that are down: _downTouches = [], _startTouchX0, _startTouchY0, _startTouchX1, _startTouchY1, _startTouchAngle, _startTouchDistance, _touchMode, _isMoving, _doubleTap, _movingTimeoutId; sigma.classes.dispatcher.extend(this); sigma.utils.doubleClick(_target, 'touchstart', _doubleTapHandler); _target.addEventListener('touchstart', _handleStart, false); _target.addEventListener('touchend', _handleLeave, false); _target.addEventListener('touchcancel', _handleLeave, false); _target.addEventListener('touchleave', _handleLeave, false); _target.addEventListener('touchmove', _handleMove, false); function position(e) { var offset = sigma.utils.getOffset(_target); return { x: e.pageX - offset.left, y: e.pageY - offset.top }; } /** * This method unbinds every handlers that makes the captor work. */ this.kill = function() { sigma.utils.unbindDoubleClick(_target, 'touchstart'); _target.addEventListener('touchstart', _handleStart); _target.addEventListener('touchend', _handleLeave); _target.addEventListener('touchcancel', _handleLeave); _target.addEventListener('touchleave', _handleLeave); _target.addEventListener('touchmove', _handleMove); }; // TOUCH EVENTS: // ************* /** * The handler listening to the 'touchstart' event. It will set the touch * mode ("_touchMode") and start observing the user touch moves. * * @param {event} e A touch event. */ function _handleStart(e) { if (_settings('touchEnabled')) { var x0, x1, y0, y1, pos0, pos1; _downTouches = e.touches; switch (_downTouches.length) { case 1: _camera.isMoving = true; _touchMode = 1; _startCameraX = _camera.x; _startCameraY = _camera.y; _lastCameraX = _camera.x; _lastCameraY = _camera.y; pos0 = position(_downTouches[0]); _startTouchX0 = pos0.x; _startTouchY0 = pos0.y; break; case 2: _camera.isMoving = true; _touchMode = 2; pos0 = position(_downTouches[0]); pos1 = position(_downTouches[1]); x0 = pos0.x; y0 = pos0.y; x1 = pos1.x; y1 = pos1.y; _lastCameraX = _camera.x; _lastCameraY = _camera.y; _startCameraAngle = _camera.angle; _startCameraRatio = _camera.ratio; _startCameraX = _camera.x; _startCameraY = _camera.y; _startTouchX0 = x0; _startTouchY0 = y0; _startTouchX1 = x1; _startTouchY1 = y1; _startTouchAngle = Math.atan2( _startTouchY1 - _startTouchY0, _startTouchX1 - _startTouchX0 ); _startTouchDistance = Math.sqrt( (_startTouchY1 - _startTouchY0) * (_startTouchY1 - _startTouchY0) + (_startTouchX1 - _startTouchX0) * (_startTouchX1 - _startTouchX0) ); e.preventDefault(); return false; } } } /** * The handler listening to the 'touchend', 'touchcancel' and 'touchleave' * event. It will update the touch mode if there are still at least one * finger, and stop dragging else. * * @param {event} e A touch event. */ function _handleLeave(e) { if (_settings('touchEnabled')) { _downTouches = e.touches; var inertiaRatio = _settings('touchInertiaRatio'); if (_movingTimeoutId) { _isMoving = false; clearTimeout(_movingTimeoutId); } switch (_touchMode) { case 2: if (e.touches.length === 1) { _handleStart(e); e.preventDefault(); break; } /* falls through */ case 1: _camera.isMoving = false; _self.dispatchEvent('stopDrag'); if (_isMoving) { _doubleTap = false; sigma.misc.animation.camera( _camera, { x: _camera.x + inertiaRatio * (_camera.x - _lastCameraX), y: _camera.y + inertiaRatio * (_camera.y - _lastCameraY) }, { easing: 'quadraticOut', duration: _settings('touchInertiaDuration') } ); } _isMoving = false; _touchMode = 0; break; } } } /** * The handler listening to the 'touchmove' event. It will effectively drag * the graph, and eventually zooms and turn it if the user is using two * fingers. * * @param {event} e A touch event. */ function _handleMove(e) { if (!_doubleTap && _settings('touchEnabled')) { var x0, x1, y0, y1, cos, sin, end, pos0, pos1, diff, start, dAngle, dRatio, newStageX, newStageY, newStageRatio, newStageAngle; _downTouches = e.touches; _isMoving = true; if (_movingTimeoutId) clearTimeout(_movingTimeoutId); _movingTimeoutId = setTimeout(function() { _isMoving = false; }, _settings('dragTimeout')); switch (_touchMode) { case 1: pos0 = position(_downTouches[0]); x0 = pos0.x; y0 = pos0.y; diff = _camera.cameraPosition( x0 - _startTouchX0, y0 - _startTouchY0, true ); newStageX = _startCameraX - diff.x; newStageY = _startCameraY - diff.y; if (newStageX !== _camera.x || newStageY !== _camera.y) { _lastCameraX = _camera.x; _lastCameraY = _camera.y; _camera.goTo({ x: newStageX, y: newStageY }); _self.dispatchEvent('mousemove', sigma.utils.mouseCoords(e, pos0.x, pos0.y)); _self.dispatchEvent('drag'); } break; case 2: pos0 = position(_downTouches[0]); pos1 = position(_downTouches[1]); x0 = pos0.x; y0 = pos0.y; x1 = pos1.x; y1 = pos1.y; start = _camera.cameraPosition( (_startTouchX0 + _startTouchX1) / 2 - sigma.utils.getCenter(e).x, (_startTouchY0 + _startTouchY1) / 2 - sigma.utils.getCenter(e).y, true ); end = _camera.cameraPosition( (x0 + x1) / 2 - sigma.utils.getCenter(e).x, (y0 + y1) / 2 - sigma.utils.getCenter(e).y, true ); dAngle = Math.atan2(y1 - y0, x1 - x0) - _startTouchAngle; dRatio = Math.sqrt( (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0) ) / _startTouchDistance; // Translation: x0 = start.x; y0 = start.y; // Homothetic transformation: newStageRatio = _startCameraRatio / dRatio; x0 = x0 * dRatio; y0 = y0 * dRatio; // Rotation: newStageAngle = _startCameraAngle - dAngle; cos = Math.cos(-dAngle); sin = Math.sin(-dAngle); x1 = x0 * cos + y0 * sin; y1 = y0 * cos - x0 * sin; x0 = x1; y0 = y1; // Finalize: newStageX = x0 - end.x + _startCameraX; newStageY = y0 - end.y + _startCameraY; if ( newStageRatio !== _camera.ratio || newStageAngle !== _camera.angle || newStageX !== _camera.x || newStageY !== _camera.y ) { _lastCameraX = _camera.x; _lastCameraY = _camera.y; _lastCameraAngle = _camera.angle; _lastCameraRatio = _camera.ratio; _camera.goTo({ x: newStageX, y: newStageY, angle: newStageAngle, ratio: newStageRatio }); _self.dispatchEvent('drag'); } break; } e.preventDefault(); return false; } } /** * The handler listening to the double tap custom event. It will * basically zoom into the graph. * * @param {event} e A touch event. */ function _doubleTapHandler(e) { var pos, ratio, animation; if (e.touches && e.touches.length === 1 && _settings('touchEnabled')) { _doubleTap = true; ratio = 1 / _settings('doubleClickZoomingRatio'); pos = position(e.touches[0]); _self.dispatchEvent('doubleclick', sigma.utils.mouseCoords(e, pos.x, pos.y)); if (_settings('doubleClickEnabled')) { pos = _camera.cameraPosition( pos.x - sigma.utils.getCenter(e).x, pos.y - sigma.utils.getCenter(e).y, true ); animation = { duration: _settings('doubleClickZoomDuration'), onComplete: function() { _doubleTap = false; } }; sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); } if (e.preventDefault) e.preventDefault(); else e.returnValue = false; e.stopPropagation(); return false; } } }; }).call(this); }.call(window)); /***/ }), /* 36 */ /***/ (function(module, exports) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(undefined) { 'use strict'; if (typeof sigma === 'undefined') throw 'sigma is not declared'; sigma.utils.pkg('sigma.classes'); /** * The camera constructor. It just initializes its attributes and methods. * * @param {string} id The id. * @param {sigma.classes.graph} graph The graph. * @param {configurable} settings The settings function. * @param {?object} options Eventually some overriding options. * @return {camera} Returns the fresh new camera instance. */ sigma.classes.camera = function(id, graph, settings, options) { sigma.classes.dispatcher.extend(this); Object.defineProperty(this, 'graph', { value: graph }); Object.defineProperty(this, 'id', { value: id }); Object.defineProperty(this, 'readPrefix', { value: 'read_cam' + id + ':' }); Object.defineProperty(this, 'prefix', { value: 'cam' + id + ':' }); this.x = 0; this.y = 0; this.ratio = 1; this.angle = 0; this.isAnimated = false; this.settings = (typeof options === 'object' && options) ? settings.embedObject(options) : settings; }; /** * Updates the camera position. * * @param {object} coordinates The new coordinates object. * @return {camera} Returns the camera. */ sigma.classes.camera.prototype.goTo = function(coordinates) { if (!this.settings('enableCamera')) return this; var i, l, c = coordinates || {}, keys = ['x', 'y', 'ratio', 'angle']; for (i = 0, l = keys.length; i < l; i++) if (c[keys[i]] !== undefined) { if (typeof c[keys[i]] === 'number' && !isNaN(c[keys[i]])) this[keys[i]] = c[keys[i]]; else throw 'Value for "' + keys[i] + '" is not a number.'; } this.dispatchEvent('coordinatesUpdated'); return this; }; /** * This method takes a graph and computes for each node and edges its * coordinates relatively to the center of the camera. Basically, it will * compute the coordinates that will be used by the graphic renderers. * * Since it should be possible to use different cameras and different * renderers, it is possible to specify a prefix to put before the new * coordinates (to get something like "node.camera1_x") * * @param {?string} read The prefix of the coordinates to read. * @param {?string} write The prefix of the coordinates to write. * @param {?object} options Eventually an object of options. Those can be: * - A restricted nodes array. * - A restricted edges array. * - A width. * - A height. * @return {camera} Returns the camera. */ sigma.classes.camera.prototype.applyView = function(read, write, options) { options = options || {}; write = write !== undefined ? write : this.prefix; read = read !== undefined ? read : this.readPrefix; var nodes = options.nodes || this.graph.nodes(), edges = options.edges || this.graph.edges(); var i, l, node, relCos = Math.cos(this.angle) / this.ratio, relSin = Math.sin(this.angle) / this.ratio, nodeRatio = Math.pow(this.ratio, this.settings('nodesPowRatio')), edgeRatio = Math.pow(this.ratio, this.settings('edgesPowRatio')), xOffset = (options.width || 0) / 2 - this.x * relCos - this.y * relSin, yOffset = (options.height || 0) / 2 - this.y * relCos + this.x * relSin; for (i = 0, l = nodes.length; i < l; i++) { node = nodes[i]; node[write + 'x'] = (node[read + 'x'] || 0) * relCos + (node[read + 'y'] || 0) * relSin + xOffset; node[write + 'y'] = (node[read + 'y'] || 0) * relCos - (node[read + 'x'] || 0) * relSin + yOffset; node[write + 'size'] = (node[read + 'size'] || 0) / nodeRatio; } for (i = 0, l = edges.length; i < l; i++) { edges[i][write + 'size'] = (edges[i][read + 'size'] || 0) / edgeRatio; } return this; }; /** * This function converts the coordinates of a point from the frame of the * camera to the frame of the graph. * * @param {number} x The X coordinate of the point in the frame of the * camera. * @param {number} y The Y coordinate of the point in the frame of the * camera. * @return {object} The point coordinates in the frame of the graph. */ sigma.classes.camera.prototype.graphPosition = function(x, y, vector) { var X = 0, Y = 0, cos = Math.cos(this.angle), sin = Math.sin(this.angle); // Revert the origin differential vector: if (!vector) { X = - (this.x * cos + this.y * sin) / this.ratio; Y = - (this.y * cos - this.x * sin) / this.ratio; } return { x: (x * cos + y * sin) / this.ratio + X, y: (y * cos - x * sin) / this.ratio + Y }; }; /** * This function converts the coordinates of a point from the frame of the * graph to the frame of the camera. * * @param {number} x The X coordinate of the point in the frame of the * graph. * @param {number} y The Y coordinate of the point in the frame of the * graph. * @return {object} The point coordinates in the frame of the camera. */ sigma.classes.camera.prototype.cameraPosition = function(x, y, vector) { var X = 0, Y = 0, cos = Math.cos(this.angle), sin = Math.sin(this.angle); // Revert the origin differential vector: if (!vector) { X = - (this.x * cos + this.y * sin) / this.ratio; Y = - (this.y * cos - this.x * sin) / this.ratio; } return { x: ((x - X) * cos - (y - Y) * sin) * this.ratio, y: ((y - Y) * cos + (x - X) * sin) * this.ratio }; }; /** * This method returns the transformation matrix of the camera. This is * especially useful to apply the camera view directly in shaders, in case of * WebGL rendering. * * @return {array} The transformation matrix. */ sigma.classes.camera.prototype.getMatrix = function() { var scale = sigma.utils.matrices.scale(1 / this.ratio), rotation = sigma.utils.matrices.rotation(this.angle), translation = sigma.utils.matrices.translation(-this.x, -this.y), matrix = sigma.utils.matrices.multiply( translation, sigma.utils.matrices.multiply( rotation, scale ) ); return matrix; }; /** * Taking a width and a height as parameters, this method returns the * coordinates of the rectangle representing the camera on screen, in the * graph's referentiel. * * To keep displaying labels of nodes going out of the screen, the method * keeps a margin around the screen in the returned rectangle. * * @param {number} width The width of the screen. * @param {number} height The height of the screen. * @return {object} The rectangle as x1, y1, x2 and y2, representing * two opposite points. */ sigma.classes.camera.prototype.getRectangle = function(width, height) { var widthVect = this.cameraPosition(width, 0, true), heightVect = this.cameraPosition(0, height, true), centerVect = this.cameraPosition(width / 2, height / 2, true), marginX = this.cameraPosition(width / 4, 0, true).x, marginY = this.cameraPosition(0, height / 4, true).y; return { x1: this.x - centerVect.x - marginX, y1: this.y - centerVect.y - marginY, x2: this.x - centerVect.x + marginX + widthVect.x, y2: this.y - centerVect.y - marginY + widthVect.y, height: Math.sqrt( Math.pow(heightVect.x, 2) + Math.pow(heightVect.y + 2 * marginY, 2) ) }; }; }).call(this); }.call(window)); /***/ }), /* 37 */ /***/ (function(module, exports, __webpack_require__) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function() { 'use strict'; /** * This utils aims to facilitate the manipulation of each instance setting. * Using a function instead of an object brings two main advantages: First, * it will be easier in the future to catch settings updates through a * function than an object. Second, giving it a full object will "merge" it * to the settings object properly, keeping us to have to always add a loop. * * @return {configurable} The "settings" function. */ var configurable = function() { var i, l, data = {}, datas = Array.prototype.slice.call(arguments, 0); /** * The method to use to set or get any property of this instance. * * @param {string|object} a1 If it is a string and if a2 is undefined, * then it will return the corresponding * property. If it is a string and if a2 is * set, then it will set a2 as the property * corresponding to a1, and return this. If * it is an object, then each pair string + * object(or any other type) will be set as a * property. * @param {*?} a2 The new property corresponding to a1 if a1 * is a string. * @return {*|configurable} Returns itself or the corresponding * property. * * Polymorphism: * ************* * Here are some basic use examples: * * > settings = new configurable(); * > settings('mySetting', 42); * > settings('mySetting'); // Logs: 42 * > settings('mySetting', 123); * > settings('mySetting'); // Logs: 123 * > settings({mySetting: 456}); * > settings('mySetting'); // Logs: 456 * * Also, it is possible to use the function as a fallback: * > settings({mySetting: 'abc'}, 'mySetting'); // Logs: 'abc' * > settings({hisSetting: 'abc'}, 'mySetting'); // Logs: 456 */ var settings = function(a1, a2) { var o, i, l, k; if (arguments.length === 1 && typeof a1 === 'string') { if (data[a1] !== undefined) return data[a1]; for (i = 0, l = datas.length; i < l; i++) if (datas[i][a1] !== undefined) return datas[i][a1]; return undefined; } else if (typeof a1 === 'object' && typeof a2 === 'string') { return (a1 || {})[a2] !== undefined ? a1[a2] : settings(a2); } else { o = (typeof a1 === 'object' && a2 === undefined) ? a1 : {}; if (typeof a1 === 'string') o[a1] = a2; for (i = 0, k = Object.keys(o), l = k.length; i < l; i++) data[k[i]] = o[k[i]]; return this; } }; /** * This method returns a new configurable function, with new objects * * @param {object*} Any number of objects to search in. * @return {function} Returns the function. Check its documentation to know * more about how it works. */ settings.embedObjects = function() { var args = datas.concat( data ).concat( Array.prototype.splice.call(arguments, 0) ); return configurable.apply({}, args); }; // Initialize for (i = 0, l = arguments.length; i < l; i++) settings(arguments[i]); return settings; }; /** * EXPORT: * ******* */ if (typeof this.sigma !== 'undefined') { this.sigma.classes = this.sigma.classes || {}; this.sigma.classes.configurable = configurable; } else if (true) { if (typeof module !== 'undefined' && module.exports) exports = module.exports = configurable; exports.configurable = configurable; } else this.configurable = configurable; }).call(this); }.call(window)); /***/ }), /* 38 */ /***/ (function(module, exports, __webpack_require__) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function() { 'use strict'; /** * Dispatcher constructor. * * @return {dispatcher} The new dispatcher instance. */ var dispatcher = function() { Object.defineProperty(this, '_handlers', { value: {} }); }; /** * Will execute the handler everytime that the indicated event (or the * indicated events) will be triggered. * * @param {string} events The name of the event (or the events * separated by spaces). * @param {function(Object)} handler The handler to bind. * @return {dispatcher} Returns the instance itself. */ dispatcher.prototype.bind = function(events, handler) { var i, l, event, eArray; if ( arguments.length === 1 && typeof arguments[0] === 'object' ) for (events in arguments[0]) this.bind(events, arguments[0][events]); else if ( arguments.length === 2 && typeof arguments[1] === 'function' ) { eArray = typeof events === 'string' ? events.split(' ') : events; for (i = 0, l = eArray.length; i !== l; i += 1) { event = eArray[i]; // Check that event is not '': if (!event) continue; if (!this._handlers[event]) this._handlers[event] = []; // Using an object instead of directly the handler will make possible // later to add flags this._handlers[event].push({ handler: handler }); } } else throw 'bind: Wrong arguments.'; return this; }; /** * Removes the handler from a specified event (or specified events). * * @param {?string} events The name of the event (or the events * separated by spaces). If undefined, * then all handlers are removed. * @param {?function(object)} handler The handler to unbind. If undefined, * each handler bound to the event or the * events will be removed. * @return {dispatcher} Returns the instance itself. */ dispatcher.prototype.unbind = function(events, handler) { var i, n, j, m, k, a, event, eArray = typeof events === 'string' ? events.split(' ') : events; if (!arguments.length) { for (k in this._handlers) delete this._handlers[k]; return this; } if (handler) { for (i = 0, n = eArray.length; i !== n; i += 1) { event = eArray[i]; if (this._handlers[event]) { a = []; for (j = 0, m = this._handlers[event].length; j !== m; j += 1) if (this._handlers[event][j].handler !== handler) a.push(this._handlers[event][j]); this._handlers[event] = a; } if (this._handlers[event] && this._handlers[event].length === 0) delete this._handlers[event]; } } else for (i = 0, n = eArray.length; i !== n; i += 1) delete this._handlers[eArray[i]]; return this; }; /** * Executes each handler bound to the event * * @param {string} events The name of the event (or the events separated * by spaces). * @param {?object} data The content of the event (optional). * @return {dispatcher} Returns the instance itself. */ dispatcher.prototype.dispatchEvent = function(events, data) { var i, n, j, m, a, event, eventName, self = this, eArray = typeof events === 'string' ? events.split(' ') : events; data = data === undefined ? {} : data; for (i = 0, n = eArray.length; i !== n; i += 1) { eventName = eArray[i]; if (this._handlers[eventName]) { event = self.getEvent(eventName, data); a = []; for (j = 0, m = this._handlers[eventName].length; j !== m; j += 1) { this._handlers[eventName][j].handler(event); if (!this._handlers[eventName][j].one) a.push(this._handlers[eventName][j]); } this._handlers[eventName] = a; } } return this; }; /** * Return an event object. * * @param {string} events The name of the event. * @param {?object} data The content of the event (optional). * @return {object} Returns the instance itself. */ dispatcher.prototype.getEvent = function(event, data) { return { type: event, data: data || {}, target: this }; }; /** * A useful function to deal with inheritance. It will make the target * inherit the prototype of the class dispatcher as well as its constructor. * * @param {object} target The target. */ dispatcher.extend = function(target, args) { var k; for (k in dispatcher.prototype) if (dispatcher.prototype.hasOwnProperty(k)) target[k] = dispatcher.prototype[k]; dispatcher.apply(target, args); }; /** * EXPORT: * ******* */ if (typeof this.sigma !== 'undefined') { this.sigma.classes = this.sigma.classes || {}; this.sigma.classes.dispatcher = dispatcher; } else if (true) { if (typeof module !== 'undefined' && module.exports) exports = module.exports = dispatcher; exports.dispatcher = dispatcher; } else this.dispatcher = dispatcher; }).call(this); }.call(window)); /***/ }), /* 39 */ /***/ (function(module, exports, __webpack_require__) { /*** IMPORTS FROM imports-loader ***/ (function() { ;(function(undefined) { 'use strict'; /** * Sigma Quadtree Module for edges * =============================== * * Author: Sébastien Heymann, * from the quad of Guillaume Plique (Yomguithereal) * Version: 0.2 */ /** * Quad Geometric Operations * ------------------------- * * A useful batch of geometric operations used by the quadtree. */ var _geom = { /** * Transforms a graph node with x, y and size into an * axis-aligned square. * * @param {object} A graph node with at least a point (x, y) and a size. * @return {object} A square: two points (x1, y1), (x2, y2) and height. */ pointToSquare: function(n) { return { x1: n.x - n.size, y1: n.y - n.size, x2: n.x + n.size, y2: n.y - n.size, height: n.size * 2 }; }, /** * Transforms a graph edge with x1, y1, x2, y2 and size into an * axis-aligned square. * * @param {object} A graph edge with at least two points * (x1, y1), (x2, y2) and a size. * @return {object} A square: two points (x1, y1), (x2, y2) and height. */ lineToSquare: function(e) { if (e.y1 < e.y2) { // (e.x1, e.y1) on top if (e.x1 < e.x2) { // (e.x1, e.y1) on left return { x1: e.x1 - e.size, y1: e.y1 - e.size, x2: e.x2 + e.size, y2: e.y1 - e.size, height: e.y2 - e.y1 + e.size * 2 }; } // (e.x1, e.y1) on right return { x1: e.x2 - e.size, y1: e.y1 - e.size, x2: e.x1 + e.size, y2: e.y1 - e.size, height: e.y2 - e.y1 + e.size * 2 }; } // (e.x2, e.y2) on top if (e.x1 < e.x2) { // (e.x1, e.y1) on left return { x1: e.x1 - e.size, y1: e.y2 - e.size, x2: e.x2 + e.size, y2: e.y2 - e.size, height: e.y1 - e.y2 + e.size * 2 }; } // (e.x2, e.y2) on right return { x1: e.x2 - e.size, y1: e.y2 - e.size, x2: e.x1 + e.size, y2: e.y2 - e.size, height: e.y1 - e.y2 + e.size * 2 }; }, /** * Transforms a graph edge of type 'curve' with x1, y1, x2, y2, * control point and size into an axis-aligned square. * * @param {object} e A graph edge with at least two points * (x1, y1), (x2, y2) and a size. * @param {object} cp A control point (x,y). * @return {object} A square: two points (x1, y1), (x2, y2) and height. */ quadraticCurveToSquare: function(e, cp) { var pt = sigma.utils.getPointOnQuadraticCurve( 0.5, e.x1, e.y1, e.x2, e.y2, cp.x, cp.y ); // Bounding box of the two points and the point at the middle of the // curve: var minX = Math.min(e.x1, e.x2, pt.x), maxX = Math.max(e.x1, e.x2, pt.x), minY = Math.min(e.y1, e.y2, pt.y), maxY = Math.max(e.y1, e.y2, pt.y); return { x1: minX - e.size, y1: minY - e.size, x2: maxX + e.size, y2: minY - e.size, height: maxY - minY + e.size * 2 }; }, /** * Transforms a graph self loop into an axis-aligned square. * * @param {object} n A graph node with a point (x, y) and a size. * @return {object} A square: two points (x1, y1), (x2, y2) and height. */ selfLoopToSquare: function(n) { // Fitting to the curve is too costly, we compute a larger bounding box // using the control points: var cp = sigma.utils.getSelfLoopControlPoints(n.x, n.y, n.size); // Bounding box of the point and the two control points: var minX = Math.min(n.x, cp.x1, cp.x2), maxX = Math.max(n.x, cp.x1, cp.x2), minY = Math.min(n.y, cp.y1, cp.y2), maxY = Math.max(n.y, cp.y1, cp.y2); return { x1: minX - n.size, y1: minY - n.size, x2: maxX + n.size, y2: minY - n.size, height: maxY - minY + n.size * 2 }; }, /** * Checks whether a rectangle is axis-aligned. * * @param {object} A rectangle defined by two points * (x1, y1) and (x2, y2). * @return {boolean} True if the rectangle is axis-aligned. */ isAxisAligned: function(r) { return r.x1 === r.x2 || r.y1 === r.y2; }, /** * Compute top points of an axis-aligned rectangle. This is useful in * cases when the rectangle has been rotated (left, right or bottom up) and * later operations need to know the top points. * * @param {object} An axis-aligned rectangle defined by two points * (x1, y1), (x2, y2) and height. * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height. */ axisAlignedTopPoints: function(r) { // Basic if (r.y1 === r.y2 && r.x1 < r.x2) return r; // Rotated to right if (r.x1 === r.x2 && r.y2 > r.y1) return { x1: r.x1 - r.height, y1: r.y1, x2: r.x1, y2: r.y1, height: r.height }; // Rotated to left if (r.x1 === r.x2 && r.y2 < r.y1) return { x1: r.x1, y1: r.y2, x2: r.x2 + r.height, y2: r.y2, height: r.height }; // Bottom's up return { x1: r.x2, y1: r.y1 - r.height, x2: r.x1, y2: r.y1 - r.height, height: r.height }; }, /** * Get coordinates of a rectangle's lower left corner from its top points. * * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). * @return {object} Coordinates of the corner (x, y). */ lowerLeftCoor: function(r) { var width = ( Math.sqrt( Math.pow(r.x2 - r.x1, 2) + Math.pow(r.y2 - r.y1, 2) ) ); return { x: r.x1 - (r.y2 - r.y1) * r.height / width, y: r.y1 + (r.x2 - r.x1) * r.height / width }; }, /** * Get coordinates of a rectangle's lower right corner from its top points * and its lower left corner. * * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). * @param {object} A corner's coordinates (x, y). * @return {object} Coordinates of the corner (x, y). */ lowerRightCoor: function(r, llc) { return { x: llc.x - r.x1 + r.x2, y: llc.y - r.y1 + r.y2 }; }, /** * Get the coordinates of all the corners of a rectangle from its top point. * * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). * @return {array} An array of the four corners' coordinates (x, y). */ rectangleCorners: function(r) { var llc = this.lowerLeftCoor(r), lrc = this.lowerRightCoor(r, llc); return [ {x: r.x1, y: r.y1}, {x: r.x2, y: r.y2}, {x: llc.x, y: llc.y}, {x: lrc.x, y: lrc.y} ]; }, /** * Split a square defined by its boundaries into four. * * @param {object} Boundaries of the square (x, y, width, height). * @return {array} An array containing the four new squares, themselves * defined by an array of their four corners (x, y). */ splitSquare: function(b) { return [ [ {x: b.x, y: b.y}, {x: b.x + b.width / 2, y: b.y}, {x: b.x, y: b.y + b.height / 2}, {x: b.x + b.width / 2, y: b.y + b.height / 2} ], [ {x: b.x + b.width / 2, y: b.y}, {x: b.x + b.width, y: b.y}, {x: b.x + b.width / 2, y: b.y + b.height / 2}, {x: b.x + b.width, y: b.y + b.height / 2} ], [ {x: b.x, y: b.y + b.height / 2}, {x: b.x + b.width / 2, y: b.y + b.height / 2}, {x: b.x, y: b.y + b.height}, {x: b.x + b.width / 2, y: b.y + b.height} ], [ {x: b.x + b.width / 2, y: b.y + b.height / 2}, {x: b.x + b.width, y: b.y + b.height / 2}, {x: b.