|
|
- let Hammer = require('../../module/hammer');
- let hammerUtil = require('../../hammerUtil');
-
- let util = require('../../util');
-
- /**
- * Create the main frame for the Network.
- * This function is executed once when a Network object is created. The frame
- * contains a canvas, and this canvas contains all objects like the axis and
- * nodes.
- * @private
- */
- class Canvas {
- constructor(body) {
- this.body = body;
- this.pixelRatio = 1;
-
- this.options = {};
- this.defaultOptions = {
- width:'100%',
- height:'100%'
- }
- util.extend(this.options, this.defaultOptions);
-
- // bind the events
- this.body.emitter.once("resize", (obj) => {
- if (obj.width !== 0) {
- this.body.view.translation.x = obj.width * 0.5;
- }
- if (obj.height !== 0) {
- this.body.view.translation.y = obj.height * 0.5;
- }
- });
- this.body.emitter.on("destroy", () => this.hammer.destroy());
-
- // automatically adapt to a changing size of the browser.
- window.onresize = () => {this.setSize(); this.body.emitter.emit("_redraw");};
- }
-
- setOptions(options) {
- if (options !== undefined) {
- if (options.width !== undefined) {this.options.width = this._prepareValue(options.width );}
- if (options.height!== undefined) {this.options.height= this._prepareValue(options.height);}
- }
- }
-
- _prepareValue(value) {
- if (typeof value === 'number') {
- return value + 'px';
- }
- else if (typeof value === 'string') {
- if (value.indexOf('%') !== -1 || value.indexOf('px') !== -1) {
- return value;
- }
- else if (value.indexOf('%') === -1) {
- return value + 'px';
- }
- }
- throw new Error('Could not use the value supplie for width or height:' + value);
- }
-
-
- /**
- * Create the HTML
- */
- _create() {
- // remove all elements from the container element.
- while (this.body.container.hasChildNodes()) {
- this.body.container.removeChild(this.body.container.firstChild);
- }
-
- this.frame = document.createElement('div');
- this.frame.className = 'vis-network';
- this.frame.style.position = 'relative';
- this.frame.style.overflow = 'hidden';
- this.frame.tabIndex = 900; // tab index is required for keycharm to bind keystrokes to the div instead of the window
-
- //////////////////////////////////////////////////////////////////
-
- this.frame.canvas = document.createElement("canvas");
- this.frame.canvas.style.position = 'relative';
- this.frame.appendChild(this.frame.canvas);
-
- if (!this.frame.canvas.getContext) {
- let noCanvas = document.createElement( 'DIV' );
- noCanvas.style.color = 'red';
- noCanvas.style.fontWeight = 'bold' ;
- noCanvas.style.padding = '10px';
- noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
- this.frame.canvas.appendChild(noCanvas);
- }
- else {
- let ctx = this.frame.canvas.getContext("2d");
- this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio ||
- ctx.mozBackingStorePixelRatio ||
- ctx.msBackingStorePixelRatio ||
- ctx.oBackingStorePixelRatio ||
- ctx.backingStorePixelRatio || 1);
-
- this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
- }
-
- // add the frame to the container element
- this.body.container.appendChild(this.frame);
-
- this.body.view.scale = 1;
- this.body.view.translation = {x: 0.5 * this.frame.canvas.clientWidth,y: 0.5 * this.frame.canvas.clientHeight};
-
- this._bindHammer();
- }
-
-
- /**
- * This function binds hammer, it can be repeated over and over due to the uniqueness check.
- * @private
- */
- _bindHammer() {
- if (this.hammer !== undefined) {
- this.hammer.destroy();
- }
- this.drag = {};
- this.pinch = {};
-
- // init hammer
- this.hammer = new Hammer(this.frame.canvas);
- this.hammer.get('pinch').set({enable: true});
-
- hammerUtil.onTouch(this.hammer, (event) => {this.body.eventListeners.onTouch(event)});
- this.hammer.on('tap', (event) => {this.body.eventListeners.onTap(event)});
- this.hammer.on('doubletap', (event) => {this.body.eventListeners.onDoubleTap(event)});
- this.hammer.on('press', (event) => {this.body.eventListeners.onHold(event)});
- this.hammer.on('panstart', (event) => {this.body.eventListeners.onDragStart(event)});
- this.hammer.on('panmove', (event) => {this.body.eventListeners.onDrag(event)});
- this.hammer.on('panend', (event) => {this.body.eventListeners.onDragEnd(event)});
- this.hammer.on('pinch', (event) => {this.body.eventListeners.onPinch(event)});
-
- // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
- this.frame.canvas.addEventListener('mousewheel', (event) => {this.body.eventListeners.onMouseWheel(event)});
- this.frame.canvas.addEventListener('DOMMouseScroll', (event) => {this.body.eventListeners.onMouseWheel(event)});
-
- this.frame.canvas.addEventListener('mousemove', (event) => {this.body.eventListeners.onMouseMove(event)});
- this.frame.canvas.addEventListener('contextmenu', (event) => {this.body.eventListeners.onContext(event)});
-
- this.hammerFrame = new Hammer(this.frame);
- hammerUtil.onRelease(this.hammerFrame, (event) => {this.body.eventListeners.onRelease(event)});
- }
-
-
- /**
- * Set a new size for the network
- * @param {string} width Width in pixels or percentage (for example '800px'
- * or '50%')
- * @param {string} height Height in pixels or percentage (for example '400px'
- * or '30%')
- */
- setSize(width = this.options.width, height = this.options.height) {
- width = this._prepareValue(width);
- height= this._prepareValue(height);
-
- let emitEvent = false;
- let oldWidth = this.frame.canvas.width;
- let oldHeight = this.frame.canvas.height;
-
- if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
- this.frame.style.width = width;
- this.frame.style.height = height;
-
- this.frame.canvas.style.width = '100%';
- this.frame.canvas.style.height = '100%';
-
- this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio;
- this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio;
-
- this.options.width = width;
- this.options.height = height;
-
- emitEvent = true;
- }
- else {
- // this would adapt the width of the canvas to the width from 100% if and only if
- // there is a change.
-
- if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) {
- this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio;
- emitEvent = true;
- }
- if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) {
- this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio;
- emitEvent = true;
- }
- }
-
- if (emitEvent === true) {
- this.body.emitter.emit('resize', {width:this.frame.canvas.width / this.pixelRatio, height:this.frame.canvas.height / this.pixelRatio, oldWidth: oldWidth / this.pixelRatio, oldHeight: oldHeight / this.pixelRatio});
- }
- };
-
-
- /**
- * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
- * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
- * @param {number} x
- * @returns {number}
- * @private
- */
- _XconvertDOMtoCanvas(x) {
- return (x - this.body.view.translation.x) / this.body.view.scale;
- }
-
- /**
- * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
- * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
- * @param {number} x
- * @returns {number}
- * @private
- */
- _XconvertCanvasToDOM(x) {
- return x * this.body.view.scale + this.body.view.translation.x;
- }
-
- /**
- * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
- * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
- * @param {number} y
- * @returns {number}
- * @private
- */
- _YconvertDOMtoCanvas(y) {
- return (y - this.body.view.translation.y) / this.body.view.scale;
- }
-
- /**
- * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
- * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
- * @param {number} y
- * @returns {number}
- * @private
- */
- _YconvertCanvasToDOM(y) {
- return y * this.body.view.scale + this.body.view.translation.y;
- }
-
-
- /**
- *
- * @param {object} pos = {x: number, y: number}
- * @returns {{x: number, y: number}}
- * @constructor
- */
- canvasToDOM (pos) {
- return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)};
- }
-
- /**
- *
- * @param {object} pos = {x: number, y: number}
- * @returns {{x: number, y: number}}
- * @constructor
- */
- DOMtoCanvas (pos) {
- return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)};
- }
-
- }
-
- export default Canvas;
|