vue-frame-selection
Version:
vue-frame-selection for vue2 and vue3
422 lines (421 loc) • 13.9 kB
JavaScript
import Vue from "vue";
function isDOMType(value) {
return isDOM(value);
}
function isDocument(value) {
return (value == null ? void 0 : value.nodeName) === "#document";
}
function scaleRect(rect, scale) {
if (scale === 1) {
return rect;
}
return {
left: rect.left * scale,
top: rect.top * scale,
width: rect.width * scale,
height: rect.height * scale,
right: rect.right * scale,
bottom: rect.bottom * scale
};
}
const rectangleElementInlineStyle = "position: absolute;pointer-events: none;border: 1px solid rgb(45, 140, 240);background: rgba(45, 140, 240, 0.2);display:none;";
const getInitCustomRect = () => ({
left: 0,
top: 0,
width: 0,
height: 0,
right: 0,
bottom: 0
});
class MouseSelection {
constructor(domOrConfig, config) {
var _a;
this.domRect = getInitCustomRect();
this.selectionPagePositionRect = getInitCustomRect();
this.selectionDOMPositionRect = getInitCustomRect();
this.startX = 0;
this.startY = 0;
this.scale = 1;
this.moving = false;
this.RectangleElementClassName = "frame-selection-rectangle-element";
this._selectStart = (event) => {
var _a2, _b, _c, _d, _e, _f;
const nodeList = this.targetDom.querySelectorAll(this.config.stopSelector);
const isStopNode = findNode(event.target, Array.from(nodeList));
if (this.config.stopSelector && isStopNode) {
return;
}
if ((_a2 = this.config) == null ? void 0 : _a2.stopPropagation) {
event.stopPropagation();
}
if (event.button !== 0) {
return;
}
if (((_b = this.config) == null ? void 0 : _b.disabled) && ((_c = this.config) == null ? void 0 : _c.disabled())) {
return;
}
this.rectangleElement = this._createRectangleElement();
this.moving = true;
this.domRect = this._getDOMRect(this.targetDom);
const x = (event.pageX + ((_d = this.wrapDOM) == null ? void 0 : _d.scrollLeft) - window.pageXOffset) / this.scale;
const y = (event.pageY + ((_e = this.wrapDOM) == null ? void 0 : _e.scrollTop) - window.pageYOffset) / this.scale;
this._setStartPosition(x - 2, y - 2);
this.selectionPagePositionRect = this.getSelectionPagePosition(x, y);
this.selectionDOMPositionRect = this.getSelectionDOMPosition(this.selectionPagePositionRect);
this._updateRectangleElementStyle(this.selectionDOMPositionRect);
const callback = (_f = this.config) == null ? void 0 : _f.onMousedown;
callback && callback(event);
document.addEventListener("mouseup", this._selectEnd);
document.addEventListener("mousemove", this._selecting);
};
this._selecting = (event) => {
var _a2, _b, _c;
if (!this.moving) {
return;
}
const x = (event.pageX + ((_a2 = this.wrapDOM) == null ? void 0 : _a2.scrollLeft) - window.pageXOffset) / this.scale;
const y = (event.pageY + ((_b = this.wrapDOM) == null ? void 0 : _b.scrollTop) - window.pageYOffset) / this.scale;
this.selectionPagePositionRect = this.getSelectionPagePosition(x, y);
this._setRectangleElementStyle("display", "block");
const refitedMouseEvent = event;
this.selectionDOMPositionRect = this.getSelectionDOMPosition(this.selectionPagePositionRect);
refitedMouseEvent.selectionDOMRect = JSON.parse(JSON.stringify(this.selectionDOMPositionRect));
this._updateRectangleElementStyle(this.selectionDOMPositionRect);
const callback = (_c = this.config) == null ? void 0 : _c.onMousemove;
callback && callback(refitedMouseEvent);
};
this._selectEnd = (event) => {
var _a2;
document.removeEventListener("mousemove", this._selecting);
document.removeEventListener("mouseup", this._selectEnd);
this._setRectangleElementStyle("display", "none");
this.moving = false;
const callback = (_a2 = this.config) == null ? void 0 : _a2.onMouseup;
callback && callback(event);
};
let dom = document;
this.config = config;
if (isDOMType(domOrConfig)) {
dom = domOrConfig;
} else if (domOrConfig) {
this.config = domOrConfig;
}
this.targetDom = dom;
if (isDocument(this.targetDom)) {
this.wrapDOM = document.body;
} else {
this.wrapDOM = this.targetDom;
}
this.scale = ((_a = this.config) == null ? void 0 : _a.scale) || 1;
this._setWrapDomPositionStyle();
this._addMousedownListener(this.targetDom);
}
getSelectionPagePosition(x, y) {
var _a, _b;
const domRect = this.domRect;
x = x - 2;
y = y - 2;
const left = Math.max(domRect.left, Math.min(this.startX, x));
const top = Math.max(domRect.top, Math.min(this.startY, y));
const width = Math.max(this.startX, Math.min(x, ((_a = this.wrapDOM) == null ? void 0 : _a.scrollWidth) + domRect.left - 2)) - left;
const height = Math.max(this.startY, Math.min(y, ((_b = this.wrapDOM) == null ? void 0 : _b.scrollHeight) + domRect.top - 2)) - top;
return {
left,
top,
width,
height,
right: left + width,
bottom: top + height
};
}
getSelectionDOMPosition(selectionPagePositionRect) {
const { left, top, width, height, right, bottom } = selectionPagePositionRect;
const { left: DOMLeft, top: DOMTop } = this.domRect;
return {
left: left - DOMLeft,
top: top - DOMTop,
width,
height,
right: right - DOMLeft,
bottom: bottom - DOMTop
};
}
isInTheSelection({ left, top, width, height }) {
const {
left: x,
top: y,
width: w,
height: h
} = this.selectionDOMPositionRect;
return left + width > x && x + w > left && top + height > y && y + h > top;
}
destroy() {
this.rectangleElement && this.wrapDOM.removeChild(this.rectangleElement);
this._removeMousedownListener(this.targetDom);
this.rectangleElement = null;
this.targetDom = null;
this.domRect = null;
this.selectionPagePositionRect = null;
this.selectionDOMPositionRect = null;
this.startX = null;
this.startY = null;
this.moving = null;
this.wrapDOM = null;
}
_setWrapDomPositionStyle() {
var _a;
if ((_a = this.config) == null ? void 0 : _a.notSetWrapPosition) {
return;
}
const position = getComputedStyle(this.wrapDOM).position;
if (position === "static") {
this.wrapDOM.style.position = "relative";
}
}
_createRectangleElement() {
var _a, _b, _c, _d, _e;
let ele = Array.from((_a = this.wrapDOM) == null ? void 0 : _a.children).find((node) => Array.from(node.classList).includes(this.RectangleElementClassName));
if (ele) {
(_b = this.wrapDOM) == null ? void 0 : _b.removeChild(ele);
}
ele = document.createElement("div");
const customClassName = (_c = this.config) == null ? void 0 : _c.className;
ele.className = this.RectangleElementClassName + (customClassName ? ` ${customClassName}` : "");
ele.style.cssText = rectangleElementInlineStyle + `z-index: ${((_d = this.config) == null ? void 0 : _d.zIndex) || 99999999}`;
(_e = this.wrapDOM) == null ? void 0 : _e.appendChild(ele);
return ele;
}
_setStartPosition(x, y) {
this.startX = x;
this.startY = y;
}
_addMousedownListener(dom) {
dom == null ? void 0 : dom.addEventListener("mousedown", this._selectStart);
}
_removeMousedownListener(dom) {
dom == null ? void 0 : dom.removeEventListener("mousedown", this._selectStart);
}
_getDOMRect(dom) {
const domRect = isDocument(dom) ? {
left: 0,
top: 0,
width: window.innerWidth,
height: window.innerHeight,
right: window.innerWidth,
bottom: window.innerHeight
} : dom == null ? void 0 : dom.getBoundingClientRect();
return scaleRect(domRect, 1 / this.scale);
}
_setRectangleElementStyle(props, value) {
this.rectangleElement.style[props] = value;
}
_updateRectangleElementStyle(rect) {
const { left, top, width, height } = rect;
this._setRectangleElementStyle("left", `${left}px`);
this._setRectangleElementStyle("top", `${top}px`);
this._setRectangleElementStyle("width", `${width}px`);
this._setRectangleElementStyle("height", `${height}px`);
}
}
function isDOM(object) {
if (!object || typeof object !== "object") {
return false;
}
if (typeof HTMLElement === "function") {
return object instanceof HTMLElement || object instanceof Document;
} else {
return object && typeof object === "object" && object.nodeType && typeof object.nodeName === "string";
}
}
function findNode(target, nodeList) {
if (nodeList.some((node) => target === node)) {
return true;
} else {
if (target.parentNode) {
return findNode(target.parentNode, nodeList);
} else {
return false;
}
}
}
var __vue2_script$1 = Vue.extend({
name: "FrameSelectionGroup",
componentName: "SomFrameSelectionGroup",
provide() {
return {
SomFrameSelection: this
};
},
props: {
className: {
type: [String]
},
scale: {
type: [Number]
},
zIndex: {
type: [Number]
},
disabled: {
type: [Boolean]
},
stopPropagation: {
type: [Boolean]
},
stopSelector: {
type: [String]
},
notSetWrapPosition: {
type: [Boolean]
}
},
data() {
const fields = [];
const selection = null;
return {
selection,
fields
};
},
computed: {
cacheDoms() {
return this.fields.map((x) => x.$refs.dom);
}
},
methods: {
isInTheSelection(rect) {
if (this.selection) {
return this.selection.isInTheSelection(rect);
}
},
getInnerBoxRectList() {
return this.cacheDoms.map((dom) => {
return {
left: dom.offsetLeft,
top: dom.offsetTop,
width: dom.offsetWidth,
height: dom.offsetHeight
};
});
}
},
mounted() {
this.selection = new MouseSelection(this.$refs.wrap, {
onMousedown: (e) => {
this.$emit("mousedown", e);
},
onMousemove: (e) => {
this.$emit("mousemove", e);
},
onMouseup: (e) => {
this.$emit("mouseup", e);
},
className: this.className,
disabled: () => {
return this.disabled;
},
stopSelector: this.stopSelector,
stopPropagation: this.stopPropagation,
notSetWrapPosition: this.notSetWrapPosition,
scale: this.scale,
zIndex: this.zIndex
});
}
});
var render$1 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c("div", { ref: "wrap", staticClass: "som-frame-selection-group-wrapper" }, [_vm._t("default")], 2);
};
var staticRenderFns$1 = [];
function normalizeComponent(scriptExports, render2, staticRenderFns2, functionalTemplate, injectStyles, scopeId, moduleIdentifier, shadowMode) {
var options = typeof scriptExports === "function" ? scriptExports.options : scriptExports;
if (render2) {
options.render = render2;
options.staticRenderFns = staticRenderFns2;
options._compiled = true;
}
if (functionalTemplate) {
options.functional = true;
}
if (scopeId) {
options._scopeId = "data-v-" + scopeId;
}
var hook;
if (moduleIdentifier) {
hook = function(context) {
context = context || this.$vnode && this.$vnode.ssrContext || this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext;
if (!context && typeof __VUE_SSR_CONTEXT__ !== "undefined") {
context = __VUE_SSR_CONTEXT__;
}
if (injectStyles) {
injectStyles.call(this, context);
}
if (context && context._registeredComponents) {
context._registeredComponents.add(moduleIdentifier);
}
};
options._ssrRegister = hook;
} else if (injectStyles) {
hook = shadowMode ? function() {
injectStyles.call(this, (options.functional ? this.parent : this).$root.$options.shadowRoot);
} : injectStyles;
}
if (hook) {
if (options.functional) {
options._injectStyles = hook;
var originalRender = options.render;
options.render = function renderWithStyleInjection(h, context) {
hook.call(context);
return originalRender(h, context);
};
} else {
var existing = options.beforeCreate;
options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
}
}
return {
exports: scriptExports,
options
};
}
const __cssModules$1 = {};
var __component__$1 = /* @__PURE__ */ normalizeComponent(__vue2_script$1, render$1, staticRenderFns$1, false, __vue2_injectStyles$1, null, null, null);
function __vue2_injectStyles$1(context) {
for (let o in __cssModules$1) {
this[o] = __cssModules$1[o];
}
}
var group = /* @__PURE__ */ function() {
return __component__$1.exports;
}();
var __vue2_script = Vue.extend({
name: "FrameSelectionItem",
componentName: "SomFrameSelectionItem",
inject: ["SomFrameSelection"],
mounted() {
this.SomFrameSelection.fields.push(this);
},
beforeDestroy() {
this.SomFrameSelection.fields.splice(this.SomFrameSelection.fields.indexOf(this), 1);
}
});
var render = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c("div", { ref: "dom", staticClass: "som-frame-selection-inner-box" }, [_vm._t("default")], 2);
};
var staticRenderFns = [];
const __cssModules = {};
var __component__ = /* @__PURE__ */ normalizeComponent(__vue2_script, render, staticRenderFns, false, __vue2_injectStyles, null, null, null);
function __vue2_injectStyles(context) {
for (let o in __cssModules) {
this[o] = __cssModules[o];
}
}
var item = /* @__PURE__ */ function() {
return __component__.exports;
}();
export { group as FrameSelectionGroup, item as FrameSelectionItem, MouseSelection };