You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
11 KiB
275 lines
11 KiB
/*!
|
|
* @antv/g-camera-api
|
|
* @description A simple implementation of Camera API.
|
|
* @version 2.0.41
|
|
* @date 7/30/2025, 1:34:37 PM
|
|
* @author AntVis
|
|
* @docs https://g.antv.antgroup.com/
|
|
*/
|
|
import { getAngle, CameraType, deg2rad, createVec3, runtime, Camera } from '@antv/g-lite';
|
|
import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
|
|
import _createClass from '@babel/runtime/helpers/createClass';
|
|
import _callSuper from '@babel/runtime/helpers/callSuper';
|
|
import _inherits from '@babel/runtime/helpers/inherits';
|
|
import { isString, isNumber } from '@antv/util';
|
|
import { quat, mat4, vec3 } from 'gl-matrix';
|
|
|
|
/**
|
|
* Provides camera action & animation.
|
|
*/
|
|
var AdvancedCamera = /*#__PURE__*/function (_Camera) {
|
|
function AdvancedCamera() {
|
|
var _this;
|
|
_classCallCheck(this, AdvancedCamera);
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
_this = _callSuper(this, AdvancedCamera, [].concat(args));
|
|
/**
|
|
* switch between multiple landmarks
|
|
*/
|
|
_this.landmarks = [];
|
|
return _this;
|
|
}
|
|
_inherits(AdvancedCamera, _Camera);
|
|
return _createClass(AdvancedCamera, [{
|
|
key: "rotate",
|
|
value:
|
|
/**
|
|
* Changes the azimuth and elevation with respect to the current camera axes
|
|
* @param {Number} azimuth the relative azimuth
|
|
* @param {Number} elevation the relative elevation
|
|
* @param {Number} roll the relative roll
|
|
*/
|
|
function rotate(azimuth, elevation, roll) {
|
|
this.relElevation = getAngle(elevation);
|
|
this.relAzimuth = getAngle(azimuth);
|
|
this.relRoll = getAngle(roll);
|
|
this.elevation += this.relElevation;
|
|
this.azimuth += this.relAzimuth;
|
|
this.roll += this.relRoll;
|
|
if (this.type === CameraType.EXPLORING) {
|
|
var rotX = quat.setAxisAngle(quat.create(), [1, 0, 0], deg2rad((this.rotateWorld ? 1 : -1) * this.relElevation));
|
|
var rotY = quat.setAxisAngle(quat.create(), [0, 1, 0], deg2rad((this.rotateWorld ? 1 : -1) * this.relAzimuth));
|
|
var rotZ = quat.setAxisAngle(quat.create(), [0, 0, 1], deg2rad(this.relRoll));
|
|
var rotQ = quat.multiply(quat.create(), rotY, rotX);
|
|
rotQ = quat.multiply(quat.create(), rotQ, rotZ);
|
|
var rotMatrix = mat4.fromQuat(mat4.create(), rotQ);
|
|
mat4.translate(this.matrix, this.matrix, [0, 0, -this.distance]);
|
|
mat4.multiply(this.matrix, this.matrix, rotMatrix);
|
|
mat4.translate(this.matrix, this.matrix, [0, 0, this.distance]);
|
|
} else {
|
|
if (Math.abs(this.elevation) > 90) {
|
|
return this;
|
|
}
|
|
this.computeMatrix();
|
|
}
|
|
this._getAxes();
|
|
if (this.type === CameraType.ORBITING || this.type === CameraType.EXPLORING) {
|
|
this._getPosition();
|
|
} else if (this.type === CameraType.TRACKING) {
|
|
this._getFocalPoint();
|
|
}
|
|
this._update();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* 沿水平(right) & 垂直(up)平移相机
|
|
*/
|
|
}, {
|
|
key: "pan",
|
|
value: function pan(tx, ty) {
|
|
var coords = createVec3(tx, ty, 0);
|
|
var pos = vec3.clone(this.position);
|
|
vec3.add(pos, pos, vec3.scale(vec3.create(), this.right, coords[0]));
|
|
vec3.add(pos, pos, vec3.scale(vec3.create(), this.up, coords[1]));
|
|
this._setPosition(pos);
|
|
this.triggerUpdate();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* 沿 n 轴移动,当距离视点远时移动速度较快,离视点越近速度越慢
|
|
*/
|
|
}, {
|
|
key: "dolly",
|
|
value: function dolly(value) {
|
|
var n = this.forward;
|
|
var pos = vec3.clone(this.position);
|
|
var step = value * this.dollyingStep;
|
|
var updatedDistance = this.distance + value * this.dollyingStep;
|
|
|
|
// 限制视点距离范围
|
|
step = Math.max(Math.min(updatedDistance, this.maxDistance), this.minDistance) - this.distance;
|
|
pos[0] += step * n[0];
|
|
pos[1] += step * n[1];
|
|
pos[2] += step * n[2];
|
|
this._setPosition(pos);
|
|
if (this.type === CameraType.ORBITING || this.type === CameraType.EXPLORING) {
|
|
// 重新计算视点距离
|
|
this._getDistance();
|
|
} else if (this.type === CameraType.TRACKING) {
|
|
// 保持视距,移动视点位置
|
|
vec3.add(this.focalPoint, pos, this.distanceVector);
|
|
}
|
|
this.triggerUpdate();
|
|
return this;
|
|
}
|
|
}, {
|
|
key: "cancelLandmarkAnimation",
|
|
value: function cancelLandmarkAnimation() {
|
|
if (this.landmarkAnimationID !== undefined) {
|
|
this.canvas.cancelAnimationFrame(this.landmarkAnimationID);
|
|
}
|
|
}
|
|
}, {
|
|
key: "createLandmark",
|
|
value: function createLandmark(name) {
|
|
var _position$, _position$2, _focalPoint$, _focalPoint$2;
|
|
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
var _params$position = params.position,
|
|
position = _params$position === void 0 ? this.position : _params$position,
|
|
_params$focalPoint = params.focalPoint,
|
|
focalPoint = _params$focalPoint === void 0 ? this.focalPoint : _params$focalPoint,
|
|
roll = params.roll,
|
|
zoom = params.zoom;
|
|
var camera = new runtime.CameraContribution();
|
|
camera.setType(this.type, undefined);
|
|
camera.setPosition(position[0], (_position$ = position[1]) !== null && _position$ !== void 0 ? _position$ : this.position[1], (_position$2 = position[2]) !== null && _position$2 !== void 0 ? _position$2 : this.position[2]);
|
|
camera.setFocalPoint(focalPoint[0], (_focalPoint$ = focalPoint[1]) !== null && _focalPoint$ !== void 0 ? _focalPoint$ : this.focalPoint[1], (_focalPoint$2 = focalPoint[2]) !== null && _focalPoint$2 !== void 0 ? _focalPoint$2 : this.focalPoint[2]);
|
|
camera.setRoll(roll !== null && roll !== void 0 ? roll : this.roll);
|
|
camera.setZoom(zoom !== null && zoom !== void 0 ? zoom : this.zoom);
|
|
var landmark = {
|
|
name: name,
|
|
matrix: mat4.clone(camera.getWorldTransform()),
|
|
right: vec3.clone(camera.right),
|
|
up: vec3.clone(camera.up),
|
|
forward: vec3.clone(camera.forward),
|
|
position: vec3.clone(camera.getPosition()),
|
|
focalPoint: vec3.clone(camera.getFocalPoint()),
|
|
distanceVector: vec3.clone(camera.getDistanceVector()),
|
|
distance: camera.getDistance(),
|
|
dollyingStep: camera.getDollyingStep(),
|
|
azimuth: camera.getAzimuth(),
|
|
elevation: camera.getElevation(),
|
|
roll: camera.getRoll(),
|
|
relAzimuth: camera.relAzimuth,
|
|
relElevation: camera.relElevation,
|
|
relRoll: camera.relRoll,
|
|
zoom: camera.getZoom()
|
|
};
|
|
this.landmarks.push(landmark);
|
|
return landmark;
|
|
}
|
|
}, {
|
|
key: "gotoLandmark",
|
|
value: function gotoLandmark(name) {
|
|
var _this2 = this;
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
var landmark = isString(name) ? this.landmarks.find(function (l) {
|
|
return l.name === name;
|
|
}) : name;
|
|
if (landmark) {
|
|
var _ref = isNumber(options) ? {
|
|
duration: options
|
|
} : options,
|
|
_ref$easing = _ref.easing,
|
|
easing = _ref$easing === void 0 ? 'linear' : _ref$easing,
|
|
_ref$duration = _ref.duration,
|
|
duration = _ref$duration === void 0 ? 100 : _ref$duration,
|
|
_ref$easingFunction = _ref.easingFunction,
|
|
easingFunction = _ref$easingFunction === void 0 ? undefined : _ref$easingFunction,
|
|
_ref$onfinish = _ref.onfinish,
|
|
onfinish = _ref$onfinish === void 0 ? undefined : _ref$onfinish,
|
|
_ref$onframe = _ref.onframe,
|
|
onframe = _ref$onframe === void 0 ? undefined : _ref$onframe;
|
|
var epsilon = 0.01;
|
|
|
|
// cancel ongoing animation
|
|
this.cancelLandmarkAnimation();
|
|
var destPosition = landmark.position;
|
|
var destFocalPoint = landmark.focalPoint;
|
|
var destZoom = landmark.zoom;
|
|
var destRoll = landmark.roll;
|
|
var easingFunc = easingFunction || runtime.EasingFunction(easing);
|
|
var timeStart;
|
|
var end = function end() {
|
|
_this2.setFocalPoint(destFocalPoint);
|
|
_this2.setPosition(destPosition);
|
|
_this2.setRoll(destRoll);
|
|
_this2.setZoom(destZoom);
|
|
_this2.computeMatrix();
|
|
_this2.triggerUpdate();
|
|
onfinish === null || onfinish === void 0 || onfinish();
|
|
};
|
|
if (duration === 0) return end();
|
|
var _animate = function animate(timestamp) {
|
|
if (timeStart === undefined) {
|
|
timeStart = timestamp;
|
|
}
|
|
var elapsed = timestamp - timeStart;
|
|
if (elapsed >= duration) {
|
|
end();
|
|
return;
|
|
}
|
|
// use the same ease function in animation system
|
|
var t = easingFunc(elapsed / duration);
|
|
var interFocalPoint = vec3.create();
|
|
var interPosition = vec3.create();
|
|
var interZoom = 1;
|
|
var interRoll = 0;
|
|
vec3.lerp(interFocalPoint, _this2.focalPoint, destFocalPoint, t);
|
|
vec3.lerp(interPosition, _this2.position, destPosition, t);
|
|
interRoll = _this2.roll * (1 - t) + destRoll * t;
|
|
interZoom = _this2.zoom * (1 - t) + destZoom * t;
|
|
_this2.setFocalPoint(interFocalPoint);
|
|
_this2.setPosition(interPosition);
|
|
_this2.setRoll(interRoll);
|
|
_this2.setZoom(interZoom);
|
|
var dist = vec3.dist(interFocalPoint, destFocalPoint) + vec3.dist(interPosition, destPosition);
|
|
if (dist <= epsilon && destZoom === undefined && destRoll === undefined) {
|
|
return end();
|
|
}
|
|
_this2.computeMatrix();
|
|
_this2.triggerUpdate();
|
|
if (elapsed < duration) {
|
|
onframe === null || onframe === void 0 || onframe(t);
|
|
_this2.landmarkAnimationID = _this2.canvas.requestAnimationFrame(_animate);
|
|
}
|
|
};
|
|
this.canvas.requestAnimationFrame(_animate);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the camera to a distance such that the area covered by the bounding box is viewed.
|
|
*/
|
|
// shot(displayObject: DisplayObject) {
|
|
// const aabb = displayObject.getBounds();
|
|
|
|
// if (!AABB.isEmpty(aabb)) {
|
|
// this.setElevation(0);
|
|
// this.setAzimuth(0);
|
|
// this.setRoll(0);
|
|
|
|
// const { halfExtents, center } = aabb;
|
|
// const maxDim = Math.max(halfExtents[0] * 2, halfExtents[1] * 2);
|
|
|
|
// const cc = center.map((c: number) => Math.round(c * 1000) / 1000) as [number, number, number];
|
|
|
|
// if (maxDim !== 0) {
|
|
// const d = (1.5 * maxDim) / Math.tan(this.fov * DEG_2_RAD);
|
|
// this.setPosition([cc[0], cc[1], cc[2] + d]);
|
|
// }
|
|
|
|
// this.setFocalPoint(cc);
|
|
// }
|
|
// }
|
|
}]);
|
|
}(Camera);
|
|
|
|
runtime.CameraContribution = AdvancedCamera;
|
|
|
|
export { AdvancedCamera };
|
|
//# sourceMappingURL=index.esm.js.map
|
|
|