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..6d7a1007 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1937,34 +1937,51 @@ Graph3d.prototype._onMouseDown = function(event) { Graph3d.prototype._onMouseMove = function (event) { event = event || window.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 camera = this.camera, + offset = camera.getOffset(); + var diffX = parseFloat(getMouseX(event)) - this.startMouseX; + var diffY = parseFloat(getMouseY(event)) - this.startMouseY; - var horizontalNew = this.startArmRotation.horizontal + diffX / 200; - var verticalNew = this.startArmRotation.vertical + diffY / 200; + var scale = this.frame.clientWidth * 0.6; - var snapAngle = 4; // degrees - var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + var offXNew = offset.x - ((diffX / scale) * this.camera.armLength) * 0.1; + var offYNew = offset.y + ((diffY / scale) * this.camera.armLength) * 0.1; - // 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; - } + this.camera.setOffset(offXNew, offYNew); + } else { - // 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; + // calculate change in mouse position + var diffX = parseFloat(getMouseX(event)) - this.startMouseX; + var diffY = parseFloat(getMouseY(event)) - this.startMouseY; + + 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; + } + this.camera.setArmRotation(horizontalNew, verticalNew); } - this.camera.setArmRotation(horizontalNew, verticalNew); this.redraw(); // fire a cameraPositionChange event