sigmajs-react
Version:
Lightweight but powerful library for drawing network graphs built on top of SigmaJS
476 lines (414 loc) • 18.1 kB
JavaScript
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 = 91);
/******/ })
/************************************************************************/
/******/ ({
/***/ 28:
/***/ (function(module, exports) {
/*** IMPORTS FROM imports-loader ***/
(function () {
;(function (undefined) {
'use strict';
var shapes = [];
var register = function register(name, drawShape, drawBorder) {
shapes.push({
'name': name,
'drawShape': drawShape,
'drawBorder': drawBorder
});
};
var enumerateShapes = function enumerateShapes() {
return shapes;
};
/**
* For the standard closed shapes - the shape fill and border are drawn the
* same, with some minor differences for fill and border. To facilitate this we
* create the generic draw functions, that take a shape drawing func and
* return a shape-renderer/border-renderer
* ----------
*/
var genericDrawShape = function genericDrawShape(shapeFunc) {
return function (node, x, y, size, color, context) {
context.fillStyle = color;
context.beginPath();
shapeFunc(node, x, y, size, context);
context.closePath();
context.fill();
};
};
var genericDrawBorder = function genericDrawBorder(shapeFunc) {
return function (node, x, y, size, color, context) {
context.strokeStyle = color;
context.lineWidth = size / 5;
context.beginPath();
shapeFunc(node, x, y, size, context);
context.closePath();
context.stroke();
};
};
/**
* We now proced to use the generics to define our standard shape/border
* drawers: square, diamond, equilateral (polygon), and star
* ----------
*/
var drawSquare = function drawSquare(node, x, y, size, context) {
var rotate = Math.PI * 45 / 180; // 45 deg rotation of a diamond shape
context.moveTo(x + size * Math.sin(rotate), y - size * Math.cos(rotate)); // first point on outer radius, dwangle 'rotate'
for (var i = 1; i < 4; i++) {
context.lineTo(x + Math.sin(rotate + 2 * Math.PI * i / 4) * size, y - Math.cos(rotate + 2 * Math.PI * i / 4) * size);
}
};
register("square", genericDrawShape(drawSquare), genericDrawBorder(drawSquare));
var drawCircle = function drawCircle(node, x, y, size, context) {
context.arc(x, y, size, 0, Math.PI * 2, true);
};
register("circle", genericDrawShape(drawCircle), genericDrawBorder(drawCircle));
var drawDiamond = function drawDiamond(node, x, y, size, context) {
context.moveTo(x - size, y);
context.lineTo(x, y - size);
context.lineTo(x + size, y);
context.lineTo(x, y + size);
};
register("diamond", genericDrawShape(drawDiamond), genericDrawBorder(drawDiamond));
var drawCross = function drawCross(node, x, y, size, context) {
var lineWeight = node.cross && node.cross.lineWeight || 5;
context.moveTo(x - size, y - lineWeight);
context.lineTo(x - size, y + lineWeight);
context.lineTo(x - lineWeight, y + lineWeight);
context.lineTo(x - lineWeight, y + size);
context.lineTo(x + lineWeight, y + size);
context.lineTo(x + lineWeight, y + lineWeight);
context.lineTo(x + size, y + lineWeight);
context.lineTo(x + size, y - lineWeight);
context.lineTo(x + lineWeight, y - lineWeight);
context.lineTo(x + lineWeight, y - size);
context.lineTo(x - lineWeight, y - size);
context.lineTo(x - lineWeight, y - lineWeight);
};
register("cross", genericDrawShape(drawCross), genericDrawBorder(drawCross));
var drawEquilateral = function drawEquilateral(node, x, y, size, context) {
var pcount = node.equilateral && node.equilateral.numPoints || 5;
var rotate = (node.equilateral && node.equilateral.rotate || 0) * Math.PI / 180;
var radius = size;
context.moveTo(x + radius * Math.sin(rotate), y - radius * Math.cos(rotate)); // first point on outer radius, angle 'rotate'
for (var i = 1; i < pcount; i++) {
context.lineTo(x + Math.sin(rotate + 2 * Math.PI * i / pcount) * radius, y - Math.cos(rotate + 2 * Math.PI * i / pcount) * radius);
}
};
register("equilateral", genericDrawShape(drawEquilateral), genericDrawBorder(drawEquilateral));
var starShape = function starShape(node, x, y, size, context) {
var pcount = node.star && node.star.numPoints || 5,
inRatio = node.star && node.star.innerRatio || 0.5,
outR = size,
inR = size * inRatio,
angleOffset = Math.PI / pcount;
context.moveTo(x, y - size); // first point on outer radius, top
for (var i = 0; i < pcount; i++) {
context.lineTo(x + Math.sin(angleOffset + 2 * Math.PI * i / pcount) * inR, y - Math.cos(angleOffset + 2 * Math.PI * i / pcount) * inR);
context.lineTo(x + Math.sin(2 * Math.PI * (i + 1) / pcount) * outR, y - Math.cos(2 * Math.PI * (i + 1) / pcount) * outR);
}
};
register("star", genericDrawShape(starShape), genericDrawBorder(starShape));
/**
* An example of a non standard shape (pacman). Here we WILL NOT use the
* genericDraw functions, but rather register a full custom node renderer for
* fill, and skip the border renderer which is irrelevant for this shape
* ----------
*/
var drawPacman = function drawPacman(node, x, y, size, color, context) {
context.fillStyle = 'yellow';
context.beginPath();
context.arc(x, y, size, 1.25 * Math.PI, 0, false);
context.arc(x, y, size, 0, 0.75 * Math.PI, false);
context.lineTo(x, y);
context.closePath();
context.fill();
context.fillStyle = 'white';
context.strokeStyle = 'black';
context.beginPath();
context.arc(x + size / 3, y - size / 3, size / 4, 0, 2 * Math.PI, false);
context.closePath();
context.fill();
context.stroke();
context.fillStyle = 'black';
context.beginPath();
context.arc(x + 4 * size / 9, y - size / 3, size / 8, 0, 2 * Math.PI, false);
context.closePath();
context.fill();
};
register("pacman", drawPacman, null);
/**
* Exporting
* ----------
*/
this.ShapeLibrary = {
// Functions
enumerate: enumerateShapes,
// add: addShape,
// Version
version: '0.1'
};
}).call(window);
}).call(window);
/***/ }),
/***/ 29:
/***/ (function(module, exports) {
/*** IMPORTS FROM imports-loader ***/
(function () {
;(function (undefined) {
'use strict';
if (typeof sigma === 'undefined') throw 'sigma is not declared';
if (typeof ShapeLibrary === 'undefined') throw 'ShapeLibrary is not declared';
// Initialize package:
sigma.utils.pkg('sigma.canvas.nodes');
sigma.utils.pkg('sigma.svg.nodes');
var sigInst = undefined;
var imgCache = {};
var initPlugin = function initPlugin(inst) {
sigInst = inst;
};
var drawImage = function drawImage(node, x, y, size, context) {
if (sigInst && node.image && node.image.url) {
var url = node.image.url;
var ih = node.image.h || 1; // 1 is arbitrary, anyway only the ratio counts
var iw = node.image.w || 1;
var scale = node.image.scale || 1;
var clip = node.image.clip || 1;
// create new IMG or get from imgCache
var image = imgCache[url];
if (!image) {
image = document.createElement('IMG');
image.src = url;
image.status = 'loading';
image.onerror = function () {
console.log("error loading", url);
image.status = 'error';
};
image.onload = function () {
// TODO see how we redraw on load
// need to provide the siginst as a parameter to the library
console.log("redraw on image load", url);
image.status = 'ok';
sigInst.refresh();
};
imgCache[url] = image;
}
// calculate position and draw
var xratio = iw < ih ? iw / ih : 1;
var yratio = ih < iw ? ih / iw : 1;
var r = size * scale;
// Draw the clipping disc:
context.save(); // enter clipping mode
context.beginPath();
context.arc(x, y, size * clip, 0, Math.PI * 2, true);
context.closePath();
context.clip();
if (image.status === 'ok') {
// Draw the actual image
context.drawImage(image, x + Math.sin(-3.142 / 4) * r * xratio, y - Math.cos(-3.142 / 4) * r * yratio, r * xratio * 2 * Math.sin(-3.142 / 4) * -1, r * yratio * 2 * Math.cos(-3.142 / 4));
}
context.restore(); // exit clipping mode
}
};
var drawSVGImage = function drawSVGImage(node, group, settings) {
if (sigInst && node.image && node.image.url) {
var clipCircle = document.createElementNS(settings('xmlns'), 'circle'),
clipPath = document.createElementNS(settings('xmlns'), 'clipPath'),
clipPathId = settings('classPrefix') + '-clip-path-' + node.id,
def = document.createElementNS(settings('xmlns'), 'defs'),
image = document.createElementNS(settings('xmlns'), 'image'),
url = node.image.url;
clipPath.setAttributeNS(null, 'id', clipPathId);
clipPath.appendChild(clipCircle);
def.appendChild(clipPath);
// angular's base tag will change the relative fragment id, so
// #<clipPathId> doesn't work
// HACKHACK: IE <=9 does not respect the HTML base element in SVG.
// They don't need the current URL in the clip path reference.
var absolutePath = /MSIE [5-9]/.test(navigator.userAgent) ? "" : document.location.href;
// To fix cases where an anchor tag was used
absolutePath = absolutePath.split("#")[0];
image.setAttributeNS(null, 'class', settings('classPrefix') + '-node-image');
image.setAttributeNS(null, 'clip-path', 'url(' + absolutePath + '#' + clipPathId + ')');
image.setAttributeNS(null, 'pointer-events', 'none');
image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', node.image.url);
group.appendChild(def);
group.appendChild(image);
}
};
var register = function register(name, drawShape, drawBorder) {
sigma.canvas.nodes[name] = function (node, context, settings) {
var args = arguments,
prefix = settings('prefix') || '',
size = node[prefix + 'size'],
color = node.color || settings('defaultNodeColor'),
borderColor = node.borderColor || color,
x = node[prefix + 'x'],
y = node[prefix + 'y'];
context.save();
if (drawShape) {
drawShape(node, x, y, size, color, context);
}
if (drawBorder) {
drawBorder(node, x, y, size, borderColor, context);
}
drawImage(node, x, y, size, context);
context.restore();
};
sigma.svg.nodes[name] = {
create: function create(node, settings) {
var group = document.createElementNS(settings('xmlns'), 'g'),
circle = document.createElementNS(settings('xmlns'), 'circle');
group.setAttributeNS(null, 'class', settings('classPrefix') + '-node-group');
group.setAttributeNS(null, 'data-node-id', node.id);
// Defining the node's circle
circle.setAttributeNS(null, 'data-node-id', node.id);
circle.setAttributeNS(null, 'class', settings('classPrefix') + '-node');
circle.setAttributeNS(null, 'fill', node.color || settings('defaultNodeColor'));
group.appendChild(circle);
drawSVGImage(node, group, settings);
return group;
},
update: function update(node, group, settings) {
var classPrefix = settings('classPrefix'),
clip = node.image.clip || 1,
// 1 is arbitrary, anyway only the ratio counts
ih = node.image.h || 1,
iw = node.image.w || 1,
prefix = settings('prefix') || '',
scale = node.image.scale || 1,
size = node[prefix + 'size'],
x = node[prefix + 'x'],
y = node[prefix + 'y'];
var r = scale * size,
xratio = iw < ih ? iw / ih : 1,
yratio = ih < iw ? ih / iw : 1;
for (var i = 0, childNodes = group.childNodes; i < childNodes.length; i++) {
var className = childNodes[i].getAttribute('class');
switch (className) {
case classPrefix + '-node':
childNodes[i].setAttributeNS(null, 'cx', x);
childNodes[i].setAttributeNS(null, 'cy', y);
childNodes[i].setAttributeNS(null, 'r', size);
// // Updating only if not freestyle
if (!settings('freeStyle')) {
childNodes[i].setAttributeNS(null, 'fill', node.color || settings('defaultNodeColor'));
}
break;
case classPrefix + '-node-image':
childNodes[i].setAttributeNS(null, 'x', x + Math.sin(-3.142 / 4) * r * xratio);
childNodes[i].setAttributeNS(null, 'y', y - Math.cos(-3.142 / 4) * r * yratio);
childNodes[i].setAttributeNS(null, 'width', r * xratio * 2 * Math.sin(-3.142 / 4) * -1);
childNodes[i].setAttributeNS(null, 'height', r * yratio * 2 * Math.cos(-3.142 / 4));
break;
default:
// no class name, must be the clip-path
var clipPath = childNodes[i].firstChild;
if (clipPath != null) {
var clipPathId = classPrefix + '-clip-path-' + node.id;
if (clipPath.getAttribute('id') === clipPathId) {
clipPath.firstChild.setAttributeNS(null, 'cx', x);
clipPath.firstChild.setAttributeNS(null, 'cy', y);
clipPath.firstChild.setAttributeNS(null, 'r', clip * size);
}
}
break;
}
}
// showing
group.style.display = '';
}
};
};
ShapeLibrary.enumerate().forEach(function (shape) {
register(shape.name, shape.drawShape, shape.drawBorder);
});
/**
* Exporting
* ----------
*/
this.CustomShapes = {
// Functions
init: initPlugin,
// add pre-cache images
// Version
version: '0.1'
};
}).call(window);
}).call(window);
/***/ }),
/***/ 91:
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_sigma_react_plugins_sigma_renderers_customShapes_shape_library_js__ = __webpack_require__(28);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_sigma_react_plugins_sigma_renderers_customShapes_shape_library_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_sigma_react_plugins_sigma_renderers_customShapes_shape_library_js__);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_renderers_customShapes_sigma_renderers_customShapes_js__ = __webpack_require__(29);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_renderers_customShapes_sigma_renderers_customShapes_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_renderers_customShapes_sigma_renderers_customShapes_js__);
/***/ })
/******/ });