UNPKG

@vtx/cs-map

Version:

React components for Vortex

250 lines (228 loc) 10.5 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = _default; var _react = _interopRequireWildcard(require("react")); var _ahooks = require("ahooks"); var _useProps2 = _interopRequireDefault(require("../use-props")); require("./style"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _default(props) { var children = props.children, _props$show = props.show, show = _props$show === void 0 ? true : _props$show, _props$avoid = props.avoid, avoid = _props$avoid === void 0 ? true : _props$avoid; var _useProps = (0, _useProps2["default"])(), map = _useProps.map; var domRef = (0, _react.useRef)(); var domElementsRef = (0, _react.useRef)([]); var lastExecutionTimeRef = (0, _react.useRef)(0); // 注册DOM元素 var registerDomElement = (0, _react.useCallback)(function (element) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _options$avoid = options.avoid, avoid = _options$avoid === void 0 ? true : _options$avoid; var id = Math.random().toString(36).substr(2, 9); // 简单ID生成 var elementInfo = { id: id, element: element, avoid: avoid }; domElementsRef.current = [].concat(_toConsumableArray(domElementsRef.current), [elementInfo]); return function () { domElementsRef.current = domElementsRef.current.filter(function (el) { return el.id !== id; }); }; }, []); // 碰撞检测函数 var isColliding = function isColliding(rect1, rect2) { return !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom); }; // 避让处理函数 var handleAvoidance = (0, _react.useCallback)(function () { // 限制执行频率,至少间隔50ms var now = Date.now(); if (now - lastExecutionTimeRef.current < 50) { return; } lastExecutionTimeRef.current = now; if (!avoid) { // 如果避免功能关闭,显示所有元素 domElementsRef.current.forEach(function (_ref) { var element = _ref.element; if (element) { element.style.visibility = 'visible'; } }); return; } // 获取所有DOM元素的位置信息 var allElements = []; domElementsRef.current.forEach(function (_ref2) { var id = _ref2.id, element = _ref2.element, avoid = _ref2.avoid; if (element) { // 不管当前显示状态如何,都参与计算 var rect = element.getBoundingClientRect(); var elementInfo = { id: id, element: element, rect: rect, area: rect.width * rect.height, avoid: avoid }; allElements.push(elementInfo); } }); // 如果元素数量小于2,不需要避让,确保所有元素都显示 if (allElements.length < 2) { allElements.forEach(function (_ref3) { var element = _ref3.element; element.style.visibility = 'visible'; }); return; } // 分离必须显示的元素和可避让的元素 var unavoidableElements = allElements.filter(function (el) { return !el.avoid; }); // avoid=false的元素 var avoidableElements = allElements.filter(function (el) { return el.avoid; }); // avoid=true的元素 // 标记需要隐藏的元素 var toHide = new Set(); // 检查所有元素之间的碰撞 // 1. 必须显示的元素优先,与所有其他元素比较 var _iterator = _createForOfIteratorHelper(unavoidableElements), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var unavoidable = _step.value; // 必须显示的元素与可避让元素碰撞时,隐藏可避让元素 var _iterator2 = _createForOfIteratorHelper(avoidableElements), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var avoidable = _step2.value; if (isColliding(unavoidable.rect, avoidable.rect)) { toHide.add(avoidable.id); } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } // 2. 可避让元素之间按面积排序,面积大的优先显示 } catch (err) { _iterator.e(err); } finally { _iterator.f(); } avoidableElements.sort(function (a, b) { return b.area - a.area; }); // 3. 检查所有可避让元素之间的碰撞关系 for (var i = 0; i < avoidableElements.length; i++) { // 如果当前元素已经被标记为隐藏,则跳过 if (toHide.has(avoidableElements[i].id)) continue; // 检查与所有后续元素的碰撞 for (var j = i + 1; j < avoidableElements.length; j++) { // 如果比较的元素已经被标记为隐藏,则跳过 if (toHide.has(avoidableElements[j].id)) continue; if (isColliding(avoidableElements[i].rect, avoidableElements[j].rect)) { // 隐藏面积较小的元素(即j位置的元素) toHide.add(avoidableElements[j].id); } } } // 应用显示/隐藏 allElements.forEach(function (_ref4) { var id = _ref4.id, element = _ref4.element, elementAvoid = _ref4.avoid; if (!elementAvoid) { // avoid=false的元素始终显示 element.style.visibility = 'visible'; } else { // avoid=true的元素根据碰撞检测结果决定显示或隐藏 element.style.visibility = toHide.has(id) ? 'hidden' : 'visible'; } }); }, [avoid]); // 控制显示/隐藏 (0, _ahooks.useUpdateEffect)(function () { if (domRef.current) { domRef.current.style.visibility = show ? 'visible' : 'hidden'; } // 当显示状态改变时重新计算避让 if (show && avoid) { setTimeout(handleAvoidance, 10); } }, [show, avoid]); // 监听地图事件 (0, _react.useEffect)(function () { if (!map) return; var avoidanceTimer = null; // 处理地图变化 var handleMapChange = function handleMapChange() { // 清除之前的定时器 if (avoidanceTimer) { clearTimeout(avoidanceTimer); } // 延迟执行避让处理,确保DOM已经更新位置 avoidanceTimer = setTimeout(function () { if (avoid) { handleAvoidance(); } }, 100); }; // 监听地图移动事件 map.camera.moveEnd.addEventListener(handleMapChange); // 初始计算一次 setTimeout(function () { if (avoid) { handleAvoidance(); } }, 200); return function () { if (map && map.camera) { map.camera.moveEnd.removeEventListener(handleMapChange); } if (avoidanceTimer) { clearTimeout(avoidanceTimer); } }; }, [handleAvoidance, avoid]); // 向子组件传递上下文 var childrenWithProps = _react["default"].Children.map(children, function (child) { if (/*#__PURE__*/_react["default"].isValidElement(child)) { return /*#__PURE__*/_react["default"].cloneElement(child, { _registerDomLayer: registerDomElement }); } return child; }); return /*#__PURE__*/_react["default"].createElement("div", { className: "cs-map-dom-layer", ref: domRef, style: { display: show ? 'block' : 'none' } }, childrenWithProps); } //# sourceMappingURL=index.js.map