/** * Created by Alex on 26-Feb-15. */ var Hammer = require('../../module/hammer'); class Canvas { /** * 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 */ constructor(body, options) { this.body = body; this.setOptions(options); this.translation = {x: 0, y: 0}; this.scale = 1.0; this.body.emitter.on("_setScale", (scale) => {this.scale = scale}); this.body.emitter.on("_setTranslation", (translation) => {this.translation.x = translation.x; this.translation.y = translation.y;}); this.body.emitter.once("resize", (obj) => {this.translation.x = obj.width * 0.5; this.translation.y = obj.height * 0.5; this.body.emitter.emit("_setTranslation", this.translation)}); this.pixelRatio = 1; // 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-frame'; this.frame.style.position = 'relative'; this.frame.style.overflow = 'hidden'; this.frame.tabIndex = 900; ////////////////////////////////////////////////////////////////// this.frame.canvas = document.createElement("canvas"); this.frame.canvas.style.position = 'relative'; this.frame.appendChild(this.frame.canvas); if (!this.frame.canvas.getContext) { var 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 { var ctx = this.frame.canvas.getContext("2d"); this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1); //this.pixelRatio = Math.max(1,this.pixelRatio); // this is to account for browser zooming out. The pixel ratio is ment to switch between 1 and 2 for HD screens. 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.emitter.emit("_setScale", 1);; this.body.emitter.emit("_setTranslation", {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() { var me = this; if (this.hammer !== undefined) { this.hammer.dispose(); } this.drag = {}; this.pinch = {}; this.hammer = Hammer(this.frame.canvas, { prevent_default: true }); this.hammer.on('tap', me.body.eventListeners.onTap ); this.hammer.on('doubletap', me.body.eventListeners.onDoubleTap ); this.hammer.on('hold', me.body.eventListeners.onHold ); this.hammer.on('touch', me.body.eventListeners.onTouch ); this.hammer.on('dragstart', me.body.eventListeners.onDragStart ); this.hammer.on('drag', me.body.eventListeners.onDrag ); this.hammer.on('dragend', me.body.eventListeners.onDragEnd ); if (this.options.zoomable == true) { this.hammer.on('mousewheel', me.body.eventListeners.onMouseWheel.bind(me)); this.hammer.on('DOMMouseScroll', me.body.eventListeners.onMouseWheel.bind(me)); // for FF this.hammer.on('pinch', me.body.eventListeners.onPinch.bind(me) ); } this.hammer.on('mousemove', me.body.eventListeners.onMouseMove.bind(me) ); this.hammerFrame = Hammer(this.frame, { prevent_default: true }); this.hammerFrame.on('release', me.body.eventListeners.onRelease.bind(me) ); } setOptions(options = {}) { this.options = options; } /** * 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, height) { var emitEvent = false; var oldWidth = this.frame.canvas.width; var 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.translation.x) / this.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.scale + this.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.translation.y) / this.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.scale + this.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 {Canvas};