UNPKG

mouse-selection

Version:

A mouse frame selection plugin using JavaScript

349 lines (348 loc) 13.9 kB
"use strict"; exports.__esModule = true; function isDOMType(value) { return isDOM(value); } function isDocument(value) { return (value === null || value === void 0 ? void 0 : value.nodeName) === "#document"; } /** * 缩放rect */ 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 }; } var rectangleElementInlineStyle = "position: absolute;pointer-events: none;border: 1px solid rgb(45, 140, 240);background: rgba(45, 140, 240, 0.2);"; var getInitCustomRect = function () { return ({ left: 0, top: 0, width: 0, height: 0, right: 0, bottom: 0 }); }; var MouseSelection = /** @class */ (function () { function MouseSelection(domOrConfig, config) { var _this = this; this.domRect = getInitCustomRect(); this.selectionPagePositionRect = getInitCustomRect(); this.selectionDOMPositionRect = getInitCustomRect(); // 用于标记鼠标点下时的坐标 this.startX = 0; this.startY = 0; // 是否有缩放 this.scale = 1.0; // 当前是否在框选 this.moving = false; // 矩形框选元素类名 this.RectangleElementClassName = "frame-selection-rectangle-element"; /** * @description mousedown事件回调 * @param event 鼠标事件对象 */ this._selectStart = function (event) { var _a, _b, _c, _d; var nodeList = document.querySelectorAll(_this.config.stopSelector); var isStopNode = findNode(event.target, Array.from(nodeList)); if (_this.config.stopSelector && isStopNode) { return; } if ((_a = _this.config) === null || _a === void 0 ? void 0 : _a.stopPropagation) { event.stopPropagation(); } // 如果不是鼠标左键按下不操作 if (event.button !== 0) { return; } // 如果设置了disabled钩子函数,并且返回值为true,不操作 if (((_b = _this.config) === null || _b === void 0 ? void 0 : _b.disabled) && ((_c = _this.config) === null || _c === void 0 ? void 0 : _c.disabled())) { return; } _this.rectangleElement = _this._createRectangleElement(); _this.moving = true; // 设置所作用的DOM的定位及尺寸信息 _this.domRect = _this._getDOMRect(_this.targetDom); // 鼠标点下时距离作用DOM的偏移,需要考虑滚动,还需要考虑缩放 var x = (event.pageX + _this.wrapDOM.scrollLeft - window.pageXOffset) / _this.scale; var y = (event.pageY + _this.wrapDOM.scrollTop - window.pageYOffset) / _this.scale; // 显示矩形框选元素 _this._setRectangleElementStyle("display", "block"); // 设置起始点坐标 _this._setStartPosition(x - 2, y - 2); // 更新矩形框选元素 _this.selectionPagePositionRect = _this.getSelectionPagePosition(x, y); _this.selectionDOMPositionRect = _this.getSelectionDOMPosition(_this.selectionPagePositionRect); _this._updateRectangleElementStyle(_this.selectionDOMPositionRect); var callback = (_d = _this.config) === null || _d === void 0 ? void 0 : _d.onMousedown; callback && callback(event); document.addEventListener("mouseup", _this._selectEnd); document.addEventListener("mousemove", _this._selecting); }; /** * @description mousemove事件回调 * @param event 鼠标事件对象 */ this._selecting = function (event) { var _a; if (!_this.moving) { return; } // 鼠标当前距离作用DOM的偏移,需要考虑滚动, 还需要考虑缩放 var x = (event.pageX + _this.wrapDOM.scrollLeft - window.pageXOffset) / _this.scale; var y = (event.pageY + _this.wrapDOM.scrollTop - window.pageYOffset) / _this.scale; _this.selectionPagePositionRect = _this.getSelectionPagePosition(x, y); var refitedMouseEvent = event; _this.selectionDOMPositionRect = _this.getSelectionDOMPosition(_this.selectionPagePositionRect); refitedMouseEvent.selectionDOMRect = JSON.parse(JSON.stringify(_this.selectionDOMPositionRect)); _this._updateRectangleElementStyle(_this.selectionDOMPositionRect); var callback = (_a = _this .config) === null || _a === void 0 ? void 0 : _a.onMousemove; callback && callback(refitedMouseEvent); }; /** * @description mouseup事件回调 * @param event 鼠标事件对象 */ this._selectEnd = function (event) { var _a; document.removeEventListener("mousemove", _this._selecting); document.removeEventListener("mouseup", _this._selectEnd); _this._setRectangleElementStyle("display", "none"); _this.moving = false; var callback = (_a = _this.config) === null || _a === void 0 ? void 0 : _a.onMouseup; callback && callback(event); }; var 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 = this.config.scale || 1.0; // 默认无缩放 this._setWrapDomPositionStyle(); this._addMousedownListener(this.targetDom); } /** * @description 获取框选元素以作用DOM为准的偏移和尺寸信息 * @param left 距离页面左侧距离 * @param top 距离页面顶部距离 * @param width 宽度 * @param height 高度 */ MouseSelection.prototype.getSelectionPagePosition = function (x, y) { var domRect = this.domRect; x = x - 2; y = y - 2; var left = Math.max(domRect.left, Math.min(this.startX, x)); var top = Math.max(domRect.top, Math.min(this.startY, y)); var width = Math.max(this.startX, Math.min(x, this.wrapDOM.scrollWidth + domRect.left - 2)) - left; var height = Math.max(this.startY, Math.min(y, this.wrapDOM.scrollHeight + domRect.top - 2)) - top; return { left: left, top: top, width: width, height: height, right: left + width, bottom: top + height }; }; /** * @description 获取矩形框选元素以传入的DOM为准的偏移和尺寸信息 * @param selectionPagePositionRect getSelectionPagePosition返回的值 */ MouseSelection.prototype.getSelectionDOMPosition = function (selectionPagePositionRect) { var left = selectionPagePositionRect.left, top = selectionPagePositionRect.top, width = selectionPagePositionRect.width, height = selectionPagePositionRect.height, right = selectionPagePositionRect.right, bottom = selectionPagePositionRect.bottom; var _a = this.domRect, DOMLeft = _a.left, DOMTop = _a.top; return { left: left - DOMLeft, top: top - DOMTop, width: width, height: height, right: right - DOMLeft, bottom: bottom - DOMTop }; }; /** * @description 工具方法,传入一个包含left/top/width/height字段的对象,返回这个参数描述的矩形是否与框选矩形相交 * @param positionSizeMap {left,top,width,height} 要判断的 */ MouseSelection.prototype.isInTheSelection = function (_a) { var left = _a.left, top = _a.top, width = _a.width, height = _a.height; var _b = this.selectionDOMPositionRect, x = _b.left, y = _b.top, w = _b.width, h = _b.height; return left + width > x && x + w > left && top + height > y && y + h > top; }; /** * @description 注销方法 */ MouseSelection.prototype.destroy = function () { 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; }; /** * @description 如果未明确设置notSetWrapPosition为true,则给作用容器加position: relative属性 */ MouseSelection.prototype._setWrapDomPositionStyle = function () { var _a; if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.notSetWrapPosition) { return; } var position = getComputedStyle(this.wrapDOM).position; if (position === "static") { this.wrapDOM.style.position = "relative"; } }; /** * @description 在document.body中创建矩形框选元素 * 不管事件绑定到哪个DOM,矩形框选元素都添加到document.body * @returns 矩形框选元素 */ MouseSelection.prototype._createRectangleElement = function () { var _this = this; var _a, _b; var ele = Array.from(this.wrapDOM.children).find(function (node) { return Array.from(node.classList).includes(_this.RectangleElementClassName); }); if (ele) { this.wrapDOM.removeChild(ele); } ele = document.createElement("div"); var customClassName = (_a = this.config) === null || _a === void 0 ? void 0 : _a.className; ele.className = this.RectangleElementClassName + (customClassName ? " " + customClassName : ""); ele.style.cssText = rectangleElementInlineStyle + ("z-index: " + (((_b = this.config) === null || _b === void 0 ? void 0 : _b.zIndex) || 99999999)); this.wrapDOM.appendChild(ele); return ele; }; /** * @description 设置鼠标按下时起始坐标 * @param x * @param y */ MouseSelection.prototype._setStartPosition = function (x, y) { this.startX = x; this.startY = y; }; /** * @description 绑定mousedown事件 * @param dom 要绑定事件的dom */ MouseSelection.prototype._addMousedownListener = function (dom) { dom.addEventListener("mousedown", this._selectStart); }; /** * @description 解绑mousedown事件 * @param dom 要解绑事件的dom */ MouseSelection.prototype._removeMousedownListener = function (dom) { dom === null || dom === void 0 ? void 0 : dom.removeEventListener("mousedown", this._selectStart); }; /** * @description 获取DOM的Rect信息,如果是document,只返回6个值 * @param dom 要获取Rect信息的dom */ MouseSelection.prototype._getDOMRect = function (dom) { var domRect = isDocument(dom) ? { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight, right: window.innerWidth, bottom: window.innerHeight } : dom.getBoundingClientRect(); return scaleRect(domRect, 1 / this.scale); }; /** * @description 设置矩形框选元素样式 * @param props CSS属性名 * @param value CSS属性值 */ MouseSelection.prototype._setRectangleElementStyle = function (props, value) { this.rectangleElement.style[props] = value; }; /** * @description 更新矩形框选元素样式 * @param currentX 当前鼠标event.pageX值 * @param currentY 当前鼠标event.pageY值 */ MouseSelection.prototype._updateRectangleElementStyle = function (rect) { var left = rect.left, top = rect.top, width = rect.width, height = rect.height; this._setRectangleElementStyle("left", left + "px"); this._setRectangleElementStyle("top", top + "px"); this._setRectangleElementStyle("width", width + "px"); this._setRectangleElementStyle("height", height + "px"); }; return MouseSelection; }()); /** * @description 判断一个值是否是DOM对象 * @param object 要判断的值 * @returns {boolean} */ function isDOM(object) { if (!object || typeof object !== "object") { return false; } if (typeof HTMLElement === "function") { return object instanceof HTMLElement || object instanceof HTMLDocument; } else { return (object && typeof object === "object" && object.nodeType && typeof object.nodeName === "string"); } } /** * @description 判断当前点击的元素是否是给定的元素,或其父级是否是给定的元素 * @param target 当前鼠标点中的节点 * @param dom 要找的节点 */ function findNode(target, nodeList) { if (nodeList.some(function (node) { return target === node; })) { return true; } else { if (target.parentNode) { return findNode(target.parentNode, nodeList); } else { return false; } } } exports["default"] = MouseSelection;