@vtx/cs-map
Version:
React components for Vortex
250 lines (228 loc) • 10.5 kB
JavaScript
;
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