Sigma.js 7.56 KB
Newer Older
James Laver's avatar
James Laver committed
1 2
'use strict';

3 4
import Graph from 'graphology';
import Sigma from 'sigma';
5 6
//import { takeScreenshot } from '../../src/external-deps/sigmajs-screenshot.js';
import takeScreenshot from '../../src/external-deps/sigmajs-screenshot-with-canvas.js';
7 8
import CircleNodeProgram from 'sigma/rendering/webgl/programs/node.fast';
import ContourCircleNodeProgram from '../../src/external-deps/sigmajs-circle-with-contour.js';
9
import TriangleNodeProgram from '../../src/external-deps/sigmajs-triangle.js';
10
import ContourTriangleNodeProgram from '../../src/external-deps/sigmajs-triangle-with-contour.js';
11 12
import SquareNodeProgram from '../../src/external-deps/sigmajs-square.js';
import ContourSquareNodeProgram from '../../src/external-deps/sigmajs-square-with-contour.js';
13 14
import DiamondNodeProgram from '../../src/external-deps/sigmajs-diamond.js';
import ContourDiamondNodeProgram from '../../src/external-deps/sigmajs-diamond-with-contour.js';
15

16 17
let sigma = Sigma.Sigma;
console.log('imported sigma', Sigma);
James Laver's avatar
James Laver committed
18

James Laver's avatar
James Laver committed
19
if (typeof window !== 'undefined') {
20
  window.sigma = Sigma;
James Laver's avatar
James Laver committed
21 22
}

23 24 25 26 27 28
/*import('sigma/plugins/garg.js').then((module) => {
  let CustomShapes = module.init(sigma, window).customShapes;
  CustomShapes.init();
  });
  */
//import('sigma/src/utils/sigma.utils.js').then((module) => { module.init(sigma) });
29

30
// Black circle around a node
31
/*
32
(function() {
33
  let originalDef = sigma.canvas.nodes.def;
34 35

  sigma.canvas.nodes.def = (node, context, settings) => {
36
    let prefix = settings('prefix') || '';
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

    originalDef(node, context, settings);

    context.strokeStyle = '#000';
    context.lineWidth = 1;
    context.beginPath();
    context.arc(
      node[prefix + 'x'],
      node[prefix + 'y'],
      node[prefix + 'size'],
      0,
      Math.PI * 2,
      true
    );
    context.stroke();
  }
})()
54
*/
55

56
/*
57
sigma.canvas.nodes.selected = (node, context, settings) => {
58 59 60 61 62 63 64
  // hack
  // We need to temporarily set node.type to 'def'. This is for 2 reasons
  // 1. Make it render as a normal node
  // 2. Avoid infinite recursion (hovers.def calls node renderer and we would end up here back
  //    again with node.type = 'hovered')
  node.type = 'def';
  sigma.canvas.hovers.def(node, context, settings);
65
  node.type = 'selected';
66
  //console.log('hovers, settings:', settings);
67 68
  };
*/
69

70
//CustomShapes.init();
71

72
let sigmaMouseSelector = function(sigma, options) {
73
  const distance = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
74

75
  let mouseSelector = () => {
76
    const _self = this;
77 78 79 80
    const _s = sigma;
    const captor = sigma.mouseCaptor;
    const _container = captor.container;
    const _context = _container.getContext('2d');
81 82 83 84 85 86 87 88 89

    const unbindAll = () => {
      // TODO Maybe not needed if sigma is killed and we did bind to
      // mouse captor instead of the canvas?

      // _container.onclick = null;
      // _container.onmousemove = null;
      // _container.onmousedown = null;
      // _container.onmouseup = null;
90 91
    }

92 93 94 95 96 97
    const bindAll = () => {
      captor.on('mousemove', mouseMove);
      captor.on('click', onClick);
      captor.on('wheel', onWheel);

      sigma.on('kill', () => unbindAll());
98 99
    }

100 101 102 103 104 105 106 107 108 109 110 111
    const onWheel = (e) => {
      const shiftPressed = e.original.shiftKey;
      // zoom in has e.delta > 0 (around 0.44)
      // zoom out has e.delta < 0 (around -0.44)
      if(shiftPressed) {
        // TODO Fix this so that the canvas is not zoomed.
        console.log('[onWheel] e', e);
        e.original.preventDefault();
        e.original.stopPropagation();
        sigma.emit('shiftWheel', {
          delta: e.delta
        });
112
      }
113 114
    }

115
    // Responsible for rendering the selector properly
116
    const mouseMove = (e) => {
117
      const size = sigma.settings['mouseSelectorSize'] || 3;
118 119 120 121 122
      _context.clearRect(0, 0, _context.canvas.width, _context.canvas.height);

      _context.fillStyle = 'rgba(91, 192, 222, 0.7)';
      _context.beginPath();
      _context.arc(
123 124
        e.x,
        e.y,
125 126 127 128 129 130 131 132 133 134
        size,
        0,
        Math.PI * 2,
        true
      );
      _context.closePath();
      _context.fill();
    }

    const onClick = (e) => {
135
      const size = sigma.settings['mouseSelectorSize'] || 3;
136 137 138
      let nodeIds = [];
      for(let nodeId in sigma.nodeDataCache) {
        let data = sigma.nodeDataCache[nodeId];
139
        let position = sigma.framedGraphToViewport(data);
140
        // TODO Either distance or node is clicked directly
141
        if(distance(e.x, e.y, position.x, position.y) <= size) {
142
          nodeIds.push(nodeId);
143 144
        }
      }
145 146 147 148 149 150
      // handle node click when our selector doesn't cover it's center
      // (e.g. large nodes)
      const nodeAtPosition = sigma.getNodeAtPosition(e);
      if((nodeAtPosition && (nodeIds.indexOf(nodeAtPosition) == -1))) {
        nodeIds.push(nodeAtPosition);
      }
151 152
      sigma.emit('clickNodes', {
        nodeIds: nodeIds
153
        //captor: e.data
154 155 156
      })
      _clickPositionX = null;
      _clickPositionY = null;
157 158

      return false;
159 160
    }

161
    bindAll();
162
  }
163 164

  mouseSelector();
165 166 167 168

  // sigma.on('clickNode', (e) => {
  //   console.log('clickNode', e);
  // })
169 170
}

171
//sigmaMouseSelector(sigma);
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194

function drawLabel(
  context,
  data,
  settings
) {
  if (!data.label) return;

  const size = data.size, //settings.labelSize,
    font = settings.labelFont,
    weight = settings.labelWeight,
    color = settings.labelColor.attribute
      ? data[settings.labelColor.attribute] || settings.labelColor.color || "#000"
      : settings.labelColor.color;

  context.fillStyle = color;
  context.font = `${weight} ${size}px ${font}`;

  context.fillText(data.label, data.x, data.y + size / 3);
}


195
function _sigma(left, right, el, opts) {
James Laver's avatar
James Laver committed
196
  try {
197
    let graph = new Graph();
198
    const settings = {
199
      labelRenderer: drawLabel,
200 201
      nodeProgramClasses: {
        circle: CircleNodeProgram.default,  // TODO why default? It seems that import should be fixed
202 203
        ccircle: ContourCircleNodeProgram,
        triangle: TriangleNodeProgram,
204 205
        ctriangle: ContourTriangleNodeProgram,
        square: SquareNodeProgram,
206 207 208
        csquare: ContourSquareNodeProgram,
        diamond: DiamondNodeProgram,
        cdiamond: ContourDiamondNodeProgram
209 210 211 212
      },
      ...opts.settings
    };
    let s = new sigma(graph, el, settings);
213
    console.log('[_sigma] initializing sigma with el', el, 'opts', opts.settings, 'sigma', s);
214
    console.log('[_sigma] labelRenderedSizeThreshold', opts.settings.labelRenderedSizeThreshold);
215 216
    sigmaMouseSelector(s);
    return right(s);
James Laver's avatar
James Laver committed
217
  } catch(e) {
218
    console.log('[_sigma] error', e);
James Laver's avatar
James Laver committed
219 220 221 222
    return left(e);
  }
}

223
function _addRenderer(left, right, sigma, renderer) {
James Laver's avatar
James Laver committed
224 225 226 227 228 229
  try {
    return right(sigma.addRenderer(renderer));
  } catch(e) {
    return left(e);
  }
}
230
function _bindMouseSelectorPlugin(left, right, sig) {
231 232 233 234 235 236 237
  try {
    return right(sigma.plugins.mouseSelector(sig, sig.renderers[0]));
  } catch(e) {
    console.log('[bindMouseSelectorPlugin] error', e);
    return left(e);
  }
}
238
function _on(sigma, event, handler) { sigma.on(event, handler); }
239

240
function _takeScreenshot(sigma) {
241
  return takeScreenshot(sigma);
242 243
}

244
function _proxySetSettings(window, sigma, settings) {
245 246 247 248 249 250
  var id = sigma.id;

  window.sigma.instances(id).settings(settings);
  window.sigma.instances(id).refresh();
}

251 252 253 254
let dummy = function() {};

let _setSettings = function(g, settings) {
  for(const key in settings) {
255
    //console.log('[setSettings] key', key, settings[key]);
256 257 258 259
    g.setSetting(key, settings[key]);
  }
}

260 261 262 263
let _refresh = function(g) {
  return g.refresh();
}

264 265
export { _sigma,
         _addRenderer,
266 267
         dummy as _bindMouseSelectorPlugin,
         _on,
268
         _takeScreenshot,
269
         _proxySetSettings,
270 271
         _setSettings,
         _refresh };