@realsee/dnalogel
Version:
398 lines (397 loc) • 18.8 kB
JavaScript
var R = Object.defineProperty, O = Object.defineProperties;
var X = Object.getOwnPropertyDescriptors;
var N = Object.getOwnPropertySymbols;
var Y = Object.prototype.hasOwnProperty, B = Object.prototype.propertyIsEnumerable;
var M = (l, h, e) => h in l ? R(l, h, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[h] = e, P = (l, h) => {
for (var e in h || (h = {}))
Y.call(h, e) && M(l, e, h[e]);
if (N)
for (var e of N(h))
B.call(h, e) && M(l, e, h[e]);
return l;
}, T = (l, h) => O(l, X(h));
var i = (l, h, e) => (M(l, typeof h != "symbol" ? h + "" : h, e), e);
import { PointSelectorHelper as C } from "./utils/PointSelectorHelper.js";
import { isTouchDevice as k } from "../../isTouchDevice.js";
import * as o from "three";
import { Subscribe as j } from "../../Subscribe.js";
import { getIntersectByRaycaster as A, getVirtualIntersectByRaycaster as G } from "../../five/getPosition.js";
import { getRaycasterByNdcPosition as W } from "../../five/getRaycasterByNdcPosition.js";
import { CURSOR_NOT_ALLOW_URL as V } from "./utils/contents.js";
import { rayOnLine as g } from "../../../Sculpt/utils/three/rayOnLine.js";
import { THREERaycaster as z } from "../core/Raycaster.js";
const _ = new o.Vector3(), w = () => !1;
class se extends j {
constructor(e, t) {
var u, d, n, f, y;
super();
i(this, "_cursorError", !1);
i(this, "actionIfNoIntersection", "virtualPoint");
i(this, "plane");
/**
* @description 结果区别:vertical: 射线和模型的交点在plane上的投影点;onlyPlane: 不论射线和模型是否有交点,都为射线和plane的焦点;onlyVirtual: 仅当射线和模型没有交点时,为射线和plane的焦点
*/
i(this, "planeMode", "onlyVirtual");
i(this, "pointSelectorHelper");
i(this, "five");
/** @deprecated directly use `pointSelector.on/off` instead */
i(this, "hook", this);
/**
* @description 吸附功能总开关,方便临时的一键开启/关闭
*/
i(this, "adhereEnabled", !0);
/**
* @description 吸附半径
*/
i(this, "adhereRadius", 0.1);
/**
* @description 吸附面
*/
i(this, "adherePlane", []);
/**
* @description 吸附线
*/
i(this, "adhereLine", []);
i(this, "_outOfFive", !1);
i(this, "_enabled", !1);
i(this, "mode");
/** 长按屏幕的动作触发后为true,手指抬起后为false */
i(this, "pressDown", !1);
/** 一组吸附的点,光标靠近这些点时,会将helper以及放大镜的位置设置为这些点 */
i(this, "adherePoints");
/** 有值时表明处于按压检查阶段 */
i(this, "setPressDown");
i(this, "lastFiveHelperVisible");
i(this, "lastIntersection");
i(this, "mousePosition");
i(this, "_mouseDownInfo");
i(this, "_touchStartInfo");
i(this, "config", {});
/**
* @description: 主动触发一次选点
* @return: select 是否成功
*/
i(this, "select", (e) => {
e && this.updatePointSelectorHelperIntersect(e);
const t = this.emit("wantsSelect", this.position);
return t || (this.pointSelectorHelper.hide(), this.emit("select", this.position), console.debug(this.position)), !t;
});
i(this, "onKeyDown", (e) => {
e.key === "Shift" && (this.adhereEnabled = !1);
});
i(this, "onKeyUp", (e) => {
e.key === "Shift" && (this.adhereEnabled = !0);
});
i(this, "onMouseWheel", (e) => {
this.updateByMousePosition(e);
const t = () => this.updateByMousePosition();
this.five.off("render.prepare", t), this.five.on("render.prepare", t), setTimeout(() => {
this.five.off("render.prepare", t);
}, 200);
});
/**
* @description: 鼠标进入five canvas时
*/
i(this, "onEnter", () => {
this.cursorError || this.pointSelectorHelper.show(), this.outOfFive = !1;
});
/**
* @description: 鼠标进入five canvas时
*/
i(this, "onMouseEnter", () => {
this.onEnter(), this.emit("intersectionUpdate", this.position);
});
/**
* @description: 鼠标离开five canvas时
*/
i(this, "onMouseLeave", () => {
this.pointSelectorHelper.hide(), this.outOfFive = !0, this.emit("intersectionUpdate", void 0);
});
i(this, "onMouseDown", (e) => {
this._mouseDownInfo = {
clientX: e.clientX,
clientY: e.clientY,
timestamp: performance.now()
};
});
i(this, "onMouseUp", (e) => {
if (!this._mouseDownInfo)
return;
const { clientX: t, clientY: s, timestamp: c } = this._mouseDownInfo;
Math.abs(e.clientX - t) < 2 && Math.abs(e.clientY - s) < 2 && performance.now() - c < 500 ? this.select() : this._mouseDownInfo = null;
});
i(this, "onTouchStart", (e) => {
this._touchStartInfo = {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY,
timestamp: performance.now()
}, this.setPressDown = setTimeout(() => {
if (this.setPressDown = void 0, this.mousePosition = {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY
}, !this.mouseNdcPosition)
return;
const t = this.updateByNdcPosition(this.mouseNdcPosition);
this.pressDown = t;
}, 200);
});
i(this, "onTouchMove", (e) => {
if (this.setPressDown) {
let t = !1;
if (this._touchStartInfo) {
const { clientX: s, clientY: c } = this._touchStartInfo;
(Math.abs(e.touches[0].clientX - s) > 2 || Math.abs(e.touches[0].clientY - c) > 2) && (t = !0);
}
t && (clearTimeout(this.setPressDown), this.setPressDown = void 0);
return;
}
if (this.pressDown) {
if (this.mousePosition = {
clientX: e.touches[0].clientX,
clientY: e.touches[0].clientY
}, !this.mouseNdcPosition)
return;
this.updateByNdcPosition(this.mouseNdcPosition);
}
});
i(this, "onTouchEnd", (e) => {
if (this.setPressDown) {
clearTimeout(this.setPressDown), this.setPressDown = void 0;
return;
}
this.pressDown && (setTimeout(() => {
this.pressDown = !1;
}, 100), this.select());
});
i(this, "updateByMousePosition", (e) => {
if (this.five.getElement()) {
if (!e || (e == null ? void 0 : e.buttons) !== 0) {
this.pointSelectorHelper.hide();
return;
} else
this.pointSelectorHelper.show();
e && (this.mousePosition = {
clientX: e.clientX,
clientY: e.clientY
}), this.updateByNdcPosition(this.mouseNdcPosition);
}
});
/**
* @description: 根据鼠标位置计算焦点位置并更新
*/
i(this, "updateByNdcPosition", (e) => {
var c, u, d;
const t = W(this.five, e);
this.config.hitFilter && (t.hitFilter = this.config.hitFilter);
let s = A(this.five, t);
if (s) {
if (this.plane && this.planeMode === "vertical" && (s = T(P({}, s), {
point: this.plane.projectPoint(s.point, new o.Vector3()),
face: new o.Face3(0, 0, 0, this.plane.normal.clone()),
originalPoint: s.point.clone()
})), this.plane && this.planeMode === "onlyPlane") {
const n = t.ray.intersectPlane(this.plane, _);
if (!n)
return !1;
s = {
distance: this.five.camera.position.distanceTo(n),
point: n.clone(),
originalPoint: s.point.clone(),
face: new o.Face3(0, 0, 0, this.plane.normal.clone()),
raycaster: t
};
}
return this.updatePointSelectorHelperIntersect(s), this.lastIntersection = s, !0;
}
if (this.plane) {
const n = t.ray.intersectPlane(this.plane, _);
if (n) {
const f = {
distance: this.five.camera.position.distanceTo(n),
point: n.clone(),
object: new o.Object3D(),
face: new o.Face3(0, 0, 0, this.plane.normal.clone()),
raycaster: t,
isVirtual: !0
};
return this.updatePointSelectorHelperIntersect(f), !0;
}
}
if (this.actionIfNoIntersection === "lastPoint")
return this.updatePointSelectorHelperIntersect(this.lastIntersection), !0;
if (this.actionIfNoIntersection === "virtualPoint") {
const n = G(t, (c = this.lastIntersection) == null ? void 0 : c.distance);
return n.face = new o.Face3(0, 0, 0, (d = (u = this.lastIntersection) == null ? void 0 : u.face) == null ? void 0 : d.normal), n.isVirtual = !0, this.lastIntersection = n, this.updatePointSelectorHelperIntersect(n), !0;
} else if (this.actionIfNoIntersection === "disable")
return this.updatePointSelectorHelperIntersect(null), !1;
});
/**
* @description: 更新 pointSelectorHelper 的焦点位置
*/
i(this, "updatePointSelectorHelperIntersect", (e) => {
var s, c, u, d, n, f, y, L;
if (!e) {
this.pointSelectorHelper.hide(), this.pointSelectorHelper.position = e, this.emit("intersectionUpdate", e), this.five.getElement().style.cursor = V;
return;
}
this.onEnter(), this.cursorError || (this.five.getElement().style.cursor = "");
const t = P({}, e);
if (this.adhereEnabled && this.mouseNdcPosition && this.five.renderer) {
const I = {
x: this.mouseNdcPosition.x,
y: 1 - this.mouseNdcPosition.y
}, H = this.five.renderer.getSize(new o.Vector2());
if (this.adhereEnabled && typeof this.adherePoints == "function" && typeof this.adhereRadius == "number") {
for (const r of this.adherePlane) {
const a = r.distanceToPoint(e.point);
let p = r.projectPoint(e.point, new o.Vector3());
(!this.plane || this.plane.distanceToPoint(p) < 0.01) && (p = (c = (s = this.plane) == null ? void 0 : s.projectPoint(p, new o.Vector3())) != null ? c : p, a < this.adhereRadius && (t.point = p.clone(), t.adherePoint = p.clone(), this.plane || (t.face = new o.Face3(0, 0, 0, r.normal.clone())), t.isAdsorbed = !0));
}
for (const r of this.adhereLine) {
let a = r.closestPointToPoint(e.point, !1, new o.Vector3());
if (a.distanceTo(e.point) < this.adhereRadius)
(!this.plane || this.plane.distanceToPoint(a) < 0.01) && (a = (d = (u = this.plane) == null ? void 0 : u.projectPoint(a, new o.Vector3())) != null ? d : a, t.point = a.clone(), t.adhereLine = r.clone(), t.isAdsorbed = !0);
else {
const p = g({
raycaster: new z(this.five.camera.position, e.point.clone().sub(this.five.camera.position).normalize()),
line: r,
clampToLine: !1
}), v = p.clone().project(this.five.camera);
if (v.z <= 1) {
const b = {
x: (v.x + 1) / 2,
y: (1 - v.y) / 2
}, S = {
x: Math.abs(b.x - I.x) * H.width,
y: Math.abs(b.y - I.y) * H.height
};
let m = p.clone();
S.x < 10 && S.y < 10 && (!this.plane || this.plane.distanceToPoint(m) < 0.01) && (m = (f = (n = this.plane) == null ? void 0 : n.projectPoint(m, new o.Vector3())) != null ? f : m, t.point = m.clone(), t.adhereLine = r.clone(), t.isAdsorbed = !0);
}
}
}
for (const r of this.adherePoints({ intersection: e, pointSelectorInstance: this })) {
const a = r instanceof o.Face3 ? new o.Vector3(r.a, r.b, r.c) : r;
if (a.IsAlwaysVisible = r.IsAlwaysVisible, this.plane && this.plane.distanceToPoint(a) > 0.01)
continue;
if (a.distanceTo(e.point) < this.adhereRadius) {
t.point = (L = (y = this.plane) == null ? void 0 : y.projectPoint(a, new o.Vector3())) != null ? L : a.clone(), !this.plane && r instanceof o.Face3 && (t.face = r), t.isAdsorbed = !0;
break;
} else {
const v = a.clone().project(this.five.camera);
if (v.z > 1)
continue;
const b = this.five.renderer.getSize(new o.Vector2()), S = {
x: (v.x + 1) / 2,
y: (1 - v.y) / 2
}, m = {
x: Math.abs(S.x - I.x) * b.width,
y: Math.abs(S.y - I.y) * b.height
};
if (m.x < 10 && m.y < 10) {
let E = !1;
if (a.IsAlwaysVisible)
E = !0;
else {
const D = new o.Raycaster();
D.setFromCamera(a.clone(), this.five.camera);
const F = this.five.model.intersectRaycaster(D)[0], x = 0.1, U = this.five.camera.position.distanceTo(a);
F && F.distance < U + x && (E = !0);
}
if (E) {
t.point = a.clone(), !this.plane && r instanceof o.Face3 && (t.face = r), t.isAdsorbed = !0;
break;
}
}
}
}
}
}
this.pointSelectorHelper.updateWithIntersect(t, { emitEvent: !1 }), this.emit("intersectionUpdate", t);
});
i(this, "mousePositionToNdcPosition", (e) => {
const t = this.five.getElement();
if (!t)
return null;
const { top: s, left: c, width: u, height: d } = t.getBoundingClientRect(), { clientX: n, clientY: f } = e;
return {
x: (n - c) / u,
y: 1 - (f - s) / d
};
});
i(this, "onFiveWantsPanGesture", () => {
if (this.pressDown)
return !1;
});
i(this, "renderScreenCenter", () => {
this.updateByNdcPosition({ x: 0.5, y: 0.5 });
});
i(this, "emitIntersectionUpdate", (e) => {
this.emit("intersectionUpdate", e);
});
this.five = e, this.config = P(P({}, this.config), t), this.actionIfNoIntersection = (d = (u = t == null ? void 0 : t.actionIfNoIntersection) != null ? u : t == null ? void 0 : t.actionIfNoModelUnderMouse) != null ? d : "virtualPoint";
const s = (n = t == null ? void 0 : t.mode) != null ? n : "auto";
s === "auto" ? this.mode = k ? "fixed" : "cursor" : this.mode = s;
const c = {
autoFixPCPosition: this.mode === "cursor",
initialPosition: this.mode === "fixed" ? { left: "35%", top: "20%" } : void 0
};
this.pointSelectorHelper = new C(this.five, T(P({}, t == null ? void 0 : t.helper), {
magnifierParams: P(P({}, c), (f = t == null ? void 0 : t.helper) == null ? void 0 : f.magnifierParams),
skipPanorama: (y = t == null ? void 0 : t.skipPanorama) != null ? y : !1
})), this.pointSelectorHelper.hide();
}
get position() {
if (!this.outOfFive)
return this.pointSelectorHelper.position;
}
/**
* @description: 不在 five canvas 上时为 true
*/
get outOfFive() {
return this._outOfFive;
}
get enabled() {
return this._enabled;
}
get cursorError() {
return this._cursorError;
}
set cursorError(e) {
this._cursorError = e, this.five.getElement().style.cursor = e ? V : "", e ? this.pointSelectorHelper.hide() : this.pointSelectorHelper.show();
}
set outOfFive(e) {
this._outOfFive = e;
}
set enabled(e) {
this._enabled = e;
}
get mouseNdcPosition() {
return this.mousePosition ? this.mousePositionToNdcPosition(this.mousePosition) : null;
}
enable() {
if (this.enabled)
return;
this.enabled = !0, this.outOfFive = !1, this.pointSelectorHelper.enable(), this.pointSelectorHelper.hide();
const e = this.five.getElement();
if (!e)
throw new Error("five element not found");
this.mode === "cursor" ? (this.five.on("wantsMoveToPano", w), this.five.on("wantsChangeMode", w), this.five.on("wantsTapGesture", w), e.addEventListener("touchstart", this.onTouchStart, { passive: !0 }), e.addEventListener("touchmove", this.onTouchMove), e.addEventListener("touchend", this.onTouchEnd), e.addEventListener("mousedown", this.onMouseDown), e.addEventListener("mouseup", this.onMouseUp), e.addEventListener("mousemove", this.updateByMousePosition), e.addEventListener("wheel", this.onMouseWheel), e.addEventListener("mouseenter", this.onMouseEnter), e.addEventListener("mouseout", this.onMouseLeave), this.five.on("wantsPanGesture", this.onFiveWantsPanGesture)) : this.mode === "fixed" && (this.five.on("panoArrived", this.renderScreenCenter), this.five.on("panGesture", this.renderScreenCenter), this.five.on("interiaPan", this.renderScreenCenter), this.renderScreenCenter(), this.pointSelectorHelper.show()), document.addEventListener("keydown", this.onKeyDown), document.addEventListener("keyup", this.onKeyUp), this.pointSelectorHelper.hooks.on("intersectionUpdate", this.emitIntersectionUpdate), this.lastFiveHelperVisible = this.five.helperVisible, this.five.helperVisible = !1, this.emit("enable");
}
disable() {
if (!this.enabled)
return;
this.enabled = !1, this.adherePoints = null, this.adhereLine = [], this.adherePlane = [], this.plane = void 0, this.pointSelectorHelper.disable(), this.five.getElement().style.cursor = "";
const e = this.five.getElement();
this.five.off("wantsPanGesture", this.onFiveWantsPanGesture), this.five.off("wantsMoveToPano", w), this.five.off("wantsChangeMode", w), this.five.off("wantsTapGesture", w), this.five.helperVisible = this.lastFiveHelperVisible, e == null || e.removeEventListener("touchstart", this.onTouchStart), e == null || e.removeEventListener("touchmove", this.onTouchMove), e == null || e.removeEventListener("touchend", this.onTouchEnd), e == null || e.removeEventListener("mousedown", this.onMouseDown), e == null || e.removeEventListener("mouseup", this.onMouseUp), e == null || e.removeEventListener("mousemove", this.updateByMousePosition), e == null || e.removeEventListener("wheel", this.onMouseWheel), e == null || e.removeEventListener("mouseenter", this.onMouseEnter), e == null || e.removeEventListener("mouseout", this.onMouseLeave), this.five.off("panoArrived", this.renderScreenCenter), this.five.off("panGesture", this.renderScreenCenter), this.five.off("interiaPan", this.renderScreenCenter), document.removeEventListener("keydown", this.onKeyDown), document.removeEventListener("keyup", this.onKeyUp), this.pointSelectorHelper.hooks.off("intersectionUpdate", this.emitIntersectionUpdate), this.emit("disable");
}
dispose() {
this.disable(), this.pointSelectorHelper.dispose();
}
setAdherePoints(e, t) {
e ? typeof e == "function" ? this.adherePoints = e : this.adherePoints = () => e : this.adherePoints = null;
}
}
export {
se as PointSelector
};