diff --git a/lib/graph3d/Camera.js b/lib/graph3d/Camera.js index 1468370e..b06381b4 100644 --- a/lib/graph3d/Camera.js +++ b/lib/graph3d/Camera.js @@ -16,6 +16,8 @@ function Camera() { this.armRotation.horizontal = 0; this.armRotation.vertical = 0; this.armLength = 1.7; + this.cameraOffset = new Point3d(); + this.offsetMultiplier = 0.6; this.cameraLocation = new Point3d(); this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); @@ -23,6 +25,36 @@ function Camera() { this.calculateCameraOrientation(); } +/** + * Set offset camera in camera coordinates + * @param {Number} x offset by camera horisontal + * @param {Number} y offset by camera vertical + */ +Camera.prototype.setOffset = function(x, y) { + var abs = Math.abs, + sign = Math.sign, + mul = this.offsetMultiplier, + border = this.armLength * mul; + + if (abs(x) > border) { + x = sign(x) * border; + } + if (abs(y) > border) { + y = sign(y) * border; + } + this.cameraOffset.x = x; + this.cameraOffset.y = y; + this.calculateCameraOrientation(); +}; + +/** + * Get camera offset by horizontal and vertical + * @return {Point3d} x - horizontal offset, y - vertical offset, z - not used + */ +Camera.prototype.getOffset = function(x, y) { + return this.cameraOffset; +}; + /** * Set the location (origin) of the arm * @param {Number} x Normalized value of x @@ -89,6 +121,7 @@ Camera.prototype.setArmLength = function(length) { if (this.armLength < 0.71) this.armLength = 0.71; if (this.armLength > 5.0) this.armLength = 5.0; + this.setOffset(this.cameraOffset.x, this.cameraOffset.y); this.calculateCameraOrientation(); }; @@ -130,6 +163,17 @@ Camera.prototype.calculateCameraOrientation = function() { this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; this.cameraRotation.y = 0; this.cameraRotation.z = -this.armRotation.horizontal; + + var xa = this.cameraRotation.x; + var ya = this.cameraRotation.y; + var za = this.cameraRotation.z; + var dx = this.cameraOffset.x; + var dy = this.cameraOffset.y; + var sin = Math.sin, cos = Math.cos; + + this.cameraLocation.x = this.cameraLocation.x + dx * cos(za) + dy * - sin(za) * cos(xa); + this.cameraLocation.y = this.cameraLocation.y + dx * sin(za) + dy * cos(za) * cos(xa); + this.cameraLocation.z = this.cameraLocation.z + dy * sin(xa); }; -module.exports = Camera; \ No newline at end of file +module.exports = Camera; diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index a6c47238..61623687 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1888,6 +1888,19 @@ Graph3d.prototype._redrawDataGraph = function() { // End methods for drawing points per graph style. // ----------------------------------------------------------------------------- +/** + * Store startX, startY and startOffset for mouse operations + * + * @param {Event} event The event that occurred + */ +Graph3d.prototype._storeMousePosition = function(event) { + // get mouse position (different code for IE and all other browsers) + this.startMouseX = getMouseX(event); + this.startMouseY = getMouseY(event); + + this._startCameraOffset = this.camera.getOffset(); +}; + /** * Start a moving operation inside the provided parent element @@ -1907,9 +1920,7 @@ Graph3d.prototype._onMouseDown = function(event) { this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); if (!this.leftButtonDown && !this.touchDown) return; - // get mouse position (different code for IE and all other browsers) - this.startMouseX = getMouseX(event); - this.startMouseY = getMouseY(event); + this._storeMousePosition(event); this.startStart = new Date(this.start); this.startEnd = new Date(this.end); @@ -1940,31 +1951,44 @@ Graph3d.prototype._onMouseMove = function (event) { // calculate change in mouse position var diffX = parseFloat(getMouseX(event)) - this.startMouseX; var diffY = parseFloat(getMouseY(event)) - this.startMouseY; + + // move with ctrl or rotate by other + if (event && event.ctrlKey === true) { + // calculate change in mouse position + var scaleX = this.frame.clientWidth * 0.5; + var scaleY = this.frame.clientHeight * 0.5; + + var offXNew = (this._startCameraOffset.x || 0) - ((diffX / scaleX) * this.camera.armLength) * 0.8; + var offYNew = (this._startCameraOffset.y || 0) + ((diffY / scaleY) * this.camera.armLength) * 0.8; + + this.camera.setOffset(offXNew, offYNew); + this._storeMousePosition(event); + } else { + var horizontalNew = this.startArmRotation.horizontal + diffX / 200; + var verticalNew = this.startArmRotation.vertical + diffY / 200; + + var snapAngle = 4; // degrees + var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + + // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... + // the -0.001 is to take care that the vertical axis is always drawn at the left front corner + if (Math.abs(Math.sin(horizontalNew)) < snapValue) { + horizontalNew = Math.round(horizontalNew / Math.PI) * Math.PI - 0.001; + } + if (Math.abs(Math.cos(horizontalNew)) < snapValue) { + horizontalNew = (Math.round(horizontalNew / Math.PI - 0.5) + 0.5) * Math.PI - 0.001; + } - var horizontalNew = this.startArmRotation.horizontal + diffX / 200; - var verticalNew = this.startArmRotation.vertical + diffY / 200; - - var snapAngle = 4; // degrees - var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); - - // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... - // the -0.001 is to take care that the vertical axis is always drawn at the left front corner - if (Math.abs(Math.sin(horizontalNew)) < snapValue) { - horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; - } - if (Math.abs(Math.cos(horizontalNew)) < snapValue) { - horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; - } - - // snap vertically to nice angles - if (Math.abs(Math.sin(verticalNew)) < snapValue) { - verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; - } - if (Math.abs(Math.cos(verticalNew)) < snapValue) { - verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; + // snap vertically to nice angles + if (Math.abs(Math.sin(verticalNew)) < snapValue) { + verticalNew = Math.round(verticalNew / Math.PI) * Math.PI; + } + if (Math.abs(Math.cos(verticalNew)) < snapValue) { + verticalNew = (Math.round(verticalNew / Math.PI - 0.5) + 0.5) * Math.PI; + } + this.camera.setArmRotation(horizontalNew, verticalNew); } - this.camera.setArmRotation(horizontalNew, verticalNew); this.redraw(); // fire a cameraPositionChange event