123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- import { Matrix4, Vector3 } from "three";
- import { Container } from "../packages";
- import { openShapeDrag } from "../shared";
- import mitt from "mitt";
- export type CameraQueryPluginProps = {
- move?: boolean;
- wheel?: boolean;
- bound?: number[];
- padding?: number | number[];
- size?: number[];
- };
- export class CameraQueryPlugin {
- bound: number[];
- padding: number[];
- tree: Container;
- props: Omit<CameraQueryPluginProps, "bound">;
- cameraMat: Matrix4;
- clipMat: Matrix4 = new Matrix4();
- bus = mitt<{ cameraChange: number[] }>();
- constructor(props: CameraQueryPluginProps = {}) {
- this.props = props;
- this.props.move = props.move || false;
- this.props.wheel = props.wheel || false;
- this.cameraMat = new Matrix4();
- if (props.size) {
- this.setSize(props.size[0], props.size[1]);
- }
- if (props.bound) {
- this.setBound(props.bound, props.padding);
- }
- }
- private dragDestory?: () => void;
- disableMove() {
- this.props.move = false;
- this.dragDestory && this.dragDestory();
- }
- enableMove() {
- this.disableMove();
- this.props.move = true;
- if (!this.tree) return;
- const { stage } = this.tree;
- this.dragDestory = openShapeDrag(
- stage,
- {
- readyHandler: () => this.cameraMat.clone(),
- moveHandler: (move, initMat) => {
- const mat = this.clipMat.clone().multiply(initMat).invert();
- const v2 = new Vector3(move[0], move[1], 0).applyMatrix4(mat);
- this.move([v2.x, v2.y], initMat);
- },
- },
- false
- );
- }
- private wheelDestory?: () => void;
- disableWheel() {
- this.props.wheel = false;
- this.wheelDestory && this.wheelDestory();
- }
- enableWheel() {
- this.disableWheel();
- this.props.wheel = true;
- if (!this.tree) return;
- const {
- config: { dom },
- } = this.tree;
- const whellHandler = (ev: WheelEvent) => {
- const scale = 1 - ev.deltaY / 1000;
- const center = new Vector3(ev.offsetX, ev.offsetY, 0).applyMatrix4(
- this.clipMat.clone().multiply(this.cameraMat).invert()
- );
- this.scale([center.x, center.y], scale);
- };
- dom.addEventListener("wheel", whellHandler);
- this.wheelDestory = () => dom.removeEventListener("wheel", whellHandler);
- }
- move(movePosition: number[], initMat = this.cameraMat) {
- this.mutMat(
- new Matrix4().setPosition(movePosition[0], movePosition[1], 0),
- initMat
- );
- }
- scale(center: number[], scale: number, initMat = this.cameraMat) {
- this.mutMat(
- new Matrix4()
- .makeTranslation(center[0], center[1], 0)
- .multiply(
- new Matrix4()
- .makeScale(scale, scale, 1)
- .multiply(new Matrix4().makeTranslation(-center[0], -center[1], 0))
- ),
- initMat
- );
- }
- rotate(center: number[], angleRad: number, initMat = this.cameraMat) {
- this.mutMat(
- new Matrix4()
- .makeTranslation(center[0], center[1], 0)
- .multiply(
- new Matrix4()
- .makeRotationAxis(new Vector3(0, 0, 1), angleRad)
- .multiply(new Matrix4().makeTranslation(-center[0], -center[1], 0))
- ),
- initMat
- );
- }
- mutMat(mat: number[] | Matrix4, initMat = this.cameraMat) {
- if (mat instanceof Matrix4) {
- initMat = initMat.clone().multiply(mat);
- } else {
- initMat = initMat.multiply(new Matrix4().fromArray(mat));
- }
- this.setCameraMat(initMat);
- this.bus.emit("cameraChange", this.cameraMat.toArray());
- }
- setCameraMat(mat: number[] | Matrix4) {
- if (mat instanceof Matrix4) {
- this.cameraMat = mat;
- } else {
- this.cameraMat.fromArray(mat);
- }
- this.update();
- }
- autoBound(padding?: number | number[], stageNames = [".adsord-point"]) {
- const positions = stageNames.flatMap((item) =>
- this.tree.stage.find(item).map((s) => {
- return s.position();
- })
- );
- if (positions.length < 2) return;
- const bound = [
- Number.MAX_VALUE,
- Number.MAX_VALUE,
- -Number.MAX_VALUE,
- -Number.MAX_VALUE,
- ];
- for (const position of positions) {
- bound[0] = Math.min(bound[0], position.x);
- bound[1] = Math.min(bound[1], position.y);
- bound[2] = Math.max(bound[2], position.x);
- bound[3] = Math.max(bound[3], position.y);
- }
- this.setBound(bound, padding);
- }
- setBound(bound: number[], padding?: number | number[]) {
- padding = !Array.isArray(padding) ? [padding || 0, padding || 0] : padding;
- if (padding.length === 1) {
- padding.push(padding[0]);
- }
- const realWidth = bound[2] - bound[0];
- const realHeight = bound[3] - bound[1];
- const screenWidth = this.tree.stage.width();
- const screenHeight = this.tree.stage.height();
- // testPoint(this.tree.stage, [
- // [bound[0], bound[1]],
- // [bound[2], bound[3]],
- // ]);
- // 计算包含padding的新屏幕尺寸
- const effectiveWidth = this.tree.stage.width() - padding[0] * 2;
- const effectiveHeight = this.tree.stage.height() - padding[1] * 2;
- // 计算缩放比例
- const scaleX = effectiveWidth / realWidth;
- const scaleY = effectiveHeight / realHeight;
- const scale = Math.min(scaleX, scaleY); // 选择较小的比例以保持内容比例
- const offsetX = (screenWidth - realWidth * scale) / 2 - bound[0] * scale;
- const offsetY = (screenHeight - realHeight * scale) / 2 - bound[1] * scale;
- // 创建矩阵并应用缩放
- const matrix = new Matrix4()
- .scale(new Vector3(scale, scale, 1))
- .setPosition(offsetX, offsetY, 0);
- this.bound = bound;
- this.padding = padding;
- this.clipMat = matrix;
- this.update();
- }
- setSize(width: number, height: number) {
- this.tree.stage.width(width);
- this.tree.stage.height(height);
- if (this.bound) {
- this.setBound(this.bound, this.padding);
- }
- }
- setTree(tree: Container) {
- this.tree = tree;
- if (this.props.move) {
- this.enableMove();
- }
- if (this.props.wheel) {
- this.enableWheel();
- }
- }
- update() {
- this.tree.updateViewMat(this.clipMat.clone().multiply(this.cameraMat));
- }
- }
|