UNPKG

camera-2d-simple

Version:
260 lines (218 loc) 8.29 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('gl-matrix')) : typeof define === 'function' && define.amd ? define(['gl-matrix'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.createCamera2d = factory(global.glMatrix)); }(this, (function (glMatrix) { 'use strict'; var createCamera = function ( initTarget, initDistance, initRotation, initViewCenter, initScaleBounds, initTranslationBounds ) { if ( initTarget === void 0 ) initTarget = [0, 0]; if ( initDistance === void 0 ) initDistance = 1; if ( initRotation === void 0 ) initRotation = 0; if ( initViewCenter === void 0 ) initViewCenter = [0, 0]; if ( initScaleBounds === void 0 ) initScaleBounds = [ [0, Infinity], [0, Infinity] ]; if ( initTranslationBounds === void 0 ) initTranslationBounds = [ [-Infinity, Infinity], [-Infinity, Infinity] ]; // Scratch variables var scratch0 = new Float32Array(16); var scratch1 = new Float32Array(16); var scratch2 = new Float32Array(16); var view = glMatrix.mat4.create(); var viewCenter = initViewCenter.slice(0, 2).concat( [0], [1]); var scaleXBounds = Array.isArray(initScaleBounds[0]) ? [].concat( initScaleBounds[0] ) : [].concat( initScaleBounds ); var scaleYBounds = Array.isArray(initScaleBounds[0]) ? [].concat( initScaleBounds[1] ) : [].concat( initScaleBounds ); var translationXBounds = Array.isArray(initTranslationBounds[0]) ? [].concat( initTranslationBounds[0] ) : [].concat( initTranslationBounds ); var translationYBounds = Array.isArray(initTranslationBounds[0]) ? [].concat( initTranslationBounds[1] ) : [].concat( initTranslationBounds ); var getScaling = function () { return glMatrix.mat4.getScaling(scratch0, view).slice(0, 2); }; var getMinScaling = function () { var scaling = getScaling(); return Math.min(scaling[0], scaling[1]); }; var getMaxScaling = function () { var scaling = getScaling(); return Math.max(scaling[0], scaling[1]); }; var getRotation = function () { return Math.acos(view[0] / getMaxScaling()); }; var getScaleBounds = function () { return [[].concat( scaleXBounds ), [].concat( scaleYBounds )]; }; var getTranslationBounds = function () { return [ [].concat( translationXBounds ), [].concat( translationYBounds ) ]; }; var getDistance = function () { var scaling = getScaling(); return [1 / scaling[0], 1 / scaling[1]]; }; var getMinDistance = function () { return 1 / getMinScaling(); }; var getMaxDistance = function () { return 1 / getMaxScaling(); }; var getTranslation = function () { return glMatrix.mat4.getTranslation(scratch0, view).slice(0, 2); }; var getTarget = function () { return glMatrix.vec4 .transformMat4(scratch0, viewCenter, glMatrix.mat4.invert(scratch2, view)) .slice(0, 2); }; var getView = function () { return view; }; var getViewCenter = function () { return viewCenter.slice(0, 2); }; var lookAt = function (ref, newDistance, newRotation) { if ( ref === void 0 ) ref = []; var x = ref[0]; if ( x === void 0 ) x = 0; var y = ref[1]; if ( y === void 0 ) y = 0; if ( newDistance === void 0 ) newDistance = 1; if ( newRotation === void 0 ) newRotation = 0; // Reset the view view = glMatrix.mat4.create(); translate([-x, -y]); rotate(newRotation); scale(1 / newDistance); }; var translate = function (ref) { if ( ref === void 0 ) ref = []; var x = ref[0]; if ( x === void 0 ) x = 0; var y = ref[1]; if ( y === void 0 ) y = 0; scratch0[0] = x; scratch0[1] = y; scratch0[2] = 0; var t = glMatrix.mat4.fromTranslation(scratch1, scratch0); // Translate about the viewport center // This is identical to `i * t * i * view` where `i` is the identity matrix glMatrix.mat4.multiply(view, t, view); }; var scale = function (d, mousePos) { var isArray = Array.isArray(d); var dx = isArray ? d[0] : d; var dy = isArray ? d[1] : d; if (dx <= 0 || dy <= 0 || (dx === 1 && dy === 1)) { return; } var scaling = getScaling(); var newXScale = scaling[0] * dx; var newYScale = scaling[1] * dy; dx = Math.max(scaleXBounds[0], Math.min(newXScale, scaleXBounds[1])) / scaling[0]; dy = Math.max(scaleYBounds[0], Math.min(newYScale, scaleYBounds[1])) / scaling[1]; if (dx === 1 && dy === 1) { return; } // There is nothing to do scratch0[0] = dx; scratch0[1] = dy; scratch0[2] = 1; var s = glMatrix.mat4.fromScaling(scratch1, scratch0); var scaleCenter = mousePos ? mousePos.concat( [0]) : viewCenter; var a = glMatrix.mat4.fromTranslation(scratch0, scaleCenter); // Translate about the scale center // I.e., the mouse position or the view center glMatrix.mat4.multiply( view, a, glMatrix.mat4.multiply( view, s, glMatrix.mat4.multiply(view, glMatrix.mat4.invert(scratch2, a), view) ) ); }; var rotate = function (rad) { var r = glMatrix.mat4.create(); glMatrix.mat4.fromRotation(r, rad, [0, 0, 1]); // Rotate about the viewport center // This is identical to `i * r * i * view` where `i` is the identity matrix glMatrix.mat4.multiply(view, r, view); }; var setScaleBounds = function (newBounds) { var isArray = Array.isArray(newBounds[0]); scaleXBounds[0] = isArray ? newBounds[0][0] : newBounds[0]; scaleXBounds[1] = isArray ? newBounds[0][1] : newBounds[1]; scaleYBounds[0] = isArray ? newBounds[1][0] : newBounds[0]; scaleYBounds[1] = isArray ? newBounds[1][1] : newBounds[1]; }; var setTranslationBounds = function (newBounds) { var isArray = Array.isArray(newBounds[0]); translationXBounds[0] = isArray ? newBounds[0][0] : newBounds[0]; translationXBounds[1] = isArray ? newBounds[0][1] : newBounds[1]; translationYBounds[0] = isArray ? newBounds[1][0] : newBounds[0]; translationYBounds[1] = isArray ? newBounds[1][1] : newBounds[1]; }; var setView = function (newView) { if (!newView || newView.length < 16) { return; } view = newView; }; var setViewCenter = function (newViewCenter) { viewCenter = newViewCenter.slice(0, 2).concat( [0], [1]); }; var reset = function () { lookAt(initTarget, initDistance, initRotation); }; // Init lookAt(initTarget, initDistance, initRotation); return { get translation() { return getTranslation(); }, get target() { return getTarget(); }, get scaling() { return getScaling(); }, get minScaling() { return getMinScaling(); }, get maxScaling() { return getMaxScaling(); }, get scaleBounds() { return getScaleBounds(); }, get translationBounds() { return getTranslationBounds(); }, get distance() { return getDistance(); }, get minDistance() { return getMinDistance(); }, get maxDistance() { return getMaxDistance(); }, get rotation() { return getRotation(); }, get view() { return getView(); }, get viewCenter() { return getViewCenter(); }, lookAt: lookAt, translate: translate, pan: translate, rotate: rotate, scale: scale, zoom: scale, reset: reset, set: function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; console.warn('`set()` is deprecated. Please use `setView()` instead.'); return setView.apply(void 0, args); }, setScaleBounds: setScaleBounds, setTranslationBounds: setTranslationBounds, setView: setView, setViewCenter: setViewCenter, }; }; return createCamera; })));