首页地图引线加箭头指向真实位置(批 23)
① 被扇开的卡片,引线改成「从卡片指向真实坐标」:箭头画在真实位置那一端 (marker-end + SVG marker),终点退开 DOT_R+2 px 免得盖住圆点。活动多了 也能一眼看出这张卡片归哪个点 —— 这是用户「活动特别多会不会乱」的核心诉求。 ② 箭头 marker 的 id 逐枚唯一(home-arrow-<下标>):每枚标记的 content 各自 带一份 <defs>,同页 id 重名会指向先出现的那份,属隐患。 验证:本地全链新增 10c2「首页地图密集活动排布」步骤 —— 密集夹具 (8 个活动:东北簇 3 + 长三角簇 3 + 孤立三亚/成都)断言卡片两两不叠、 都在地图容器内、扇开的都有箭头且箭头落点离自己真实坐标 <= 8px、marker id 不重名、孤立的两枚原地不动、密集下仍可点进活动;_map16 亦加两条箭头断言。 部署哨兵新增批 23 段 4 条(数代码形式字面量,防注释打挂)。
This commit is contained in:
@@ -1338,6 +1338,8 @@ video.video-thumb.video-thumb-mini {
|
|||||||
.home-pin svg { position: absolute; left: 0; top: 0; overflow: visible; }
|
.home-pin svg { position: absolute; left: 0; top: 0; overflow: visible; }
|
||||||
.home-pin-line { stroke: #8aa0b8; stroke-width: 1.5; }
|
.home-pin-line { stroke: #8aa0b8; stroke-width: 1.5; }
|
||||||
.home-pin-dot { fill: #3b82f6; }
|
.home-pin-dot { fill: #3b82f6; }
|
||||||
|
/* 引线末端的箭头(指向真实位置那个圆点)—— 活动多了也分得清哪张卡片归哪个点 */
|
||||||
|
.home-arrow { fill: #8aa0b8; }
|
||||||
.home-card {
|
.home-card {
|
||||||
position: absolute; transform: translate(-50%, -50%);
|
position: absolute; transform: translate(-50%, -50%);
|
||||||
display: flex; align-items: center; gap: 7px;
|
display: flex; align-items: center; gap: 7px;
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ foreach ($activities as $a) {
|
|||||||
var CARD_W = 186, CARD_H = 58; // 卡片名义尺寸(按中心距判碰用)
|
var CARD_W = 186, CARD_H = 58; // 卡片名义尺寸(按中心距判碰用)
|
||||||
var CLUSTER_DIST = 110; // 中心距小于它 → 归为同簇(要扇开)
|
var CLUSTER_DIST = 110; // 中心距小于它 → 归为同簇(要扇开)
|
||||||
var CANVAS = 600, C = CANVAS / 2; // 每枚标记的 content 画布(真实位置在画布中心)
|
var CANVAS = 600, C = CANVAS / 2; // 每枚标记的 content 画布(真实位置在画布中心)
|
||||||
|
var DOT_R = 3; // 真实位置那个小圆点的半径(引线箭头要给它让位)
|
||||||
|
|
||||||
function shortTitle(t) {
|
function shortTitle(t) {
|
||||||
return (t && t.length > 10) ? t.slice(0, 10) + '…' : (t || '');
|
return (t && t.length > 10) ? t.slice(0, 10) + '…' : (t || '');
|
||||||
@@ -181,8 +182,11 @@ foreach ($activities as $a) {
|
|||||||
if (s.memberCount > names.length) t += ' 等 ' + s.memberCount + ' 人';
|
if (s.memberCount > names.length) t += ' 等 ' + s.memberCount + ' 人';
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
function cardHtml(s, dx, dy) {
|
function cardHtml(s, dx, dy, idx) {
|
||||||
var moved = Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5;
|
var moved = Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5;
|
||||||
|
/* 箭头 marker 的 id 必须逐枚唯一:每枚标记的 content 都自带一份 <defs>,
|
||||||
|
同页里 id 重名会指向先出现的那份(虽然样子一样,但属于隐患)。 */
|
||||||
|
var arrowId = 'home-arrow-' + (idx || 0);
|
||||||
var inner = s.img
|
var inner = s.img
|
||||||
? '<img src="' + esc(s.img) + '" alt="">'
|
? '<img src="' + esc(s.img) + '" alt="">'
|
||||||
: '<span>📍</span>';
|
: '<span>📍</span>';
|
||||||
@@ -194,9 +198,19 @@ foreach ($activities as $a) {
|
|||||||
var html = '<div class="home-pin">'
|
var html = '<div class="home-pin">'
|
||||||
+ '<svg width="' + CANVAS + '" height="' + CANVAS + '">';
|
+ '<svg width="' + CANVAS + '" height="' + CANVAS + '">';
|
||||||
if (moved) {
|
if (moved) {
|
||||||
html += '<line class="home-pin-line" x1="' + C + '" y1="' + C + '"'
|
/* 引线**从卡片指向真实位置**:箭头画在真实位置那一端(marker-end),
|
||||||
+ ' x2="' + (C + dx) + '" y2="' + (C + dy) + '"/>'
|
活动多了也能一眼看出这张卡片归哪个点;终点退开 DOT_R+2 px,
|
||||||
+ '<circle class="home-pin-dot" cx="' + C + '" cy="' + C + '" r="3"/>';
|
免得箭头盖住圆心那个小圆点。 */
|
||||||
|
var len = Math.hypot(dx, dy) || 1;
|
||||||
|
var gap = DOT_R + 2;
|
||||||
|
var ex = C + dx / len * gap, ey = C + dy / len * gap;
|
||||||
|
html += '<defs><marker id="' + arrowId + '" viewBox="0 0 10 10"'
|
||||||
|
+ ' refX="9" refY="5" markerWidth="9" markerHeight="9"'
|
||||||
|
+ ' markerUnits="userSpaceOnUse" orient="auto">'
|
||||||
|
+ '<path class="home-arrow" d="M0,1 L10,5 L0,9 z"/></marker></defs>'
|
||||||
|
+ '<line class="home-pin-line" x1="' + (C + dx) + '" y1="' + (C + dy) + '"'
|
||||||
|
+ ' x2="' + ex + '" y2="' + ey + '" marker-end="url(#' + arrowId + ')"/>'
|
||||||
|
+ '<circle class="home-pin-dot" cx="' + C + '" cy="' + C + '" r="' + DOT_R + '"/>';
|
||||||
}
|
}
|
||||||
html += '</svg>'
|
html += '</svg>'
|
||||||
+ '<div class="home-card" style="left:' + (C + dx) + 'px;top:' + (C + dy) + 'px;"'
|
+ '<div class="home-card" style="left:' + (C + dx) + 'px;top:' + (C + dy) + 'px;"'
|
||||||
@@ -210,12 +224,12 @@ foreach ($activities as $a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var markers = []; // { mk: AMap.Marker, spot: spot }
|
var markers = []; // { mk: AMap.Marker, spot: spot }
|
||||||
spots.forEach(function (s) {
|
spots.forEach(function (s, si) {
|
||||||
/* ⚠️ position 必须是 [lng, lat] 数组:传 {lng,lat} 裸对象会让 AMap 抛错,
|
/* ⚠️ position 必须是 [lng, lat] 数组:传 {lng,lat} 裸对象会让 AMap 抛错,
|
||||||
整个绘制循环当场中断(批 11 的「光秃秃地图」就是它)。 */
|
整个绘制循环当场中断(批 11 的「光秃秃地图」就是它)。 */
|
||||||
var mk = new AMap.Marker({
|
var mk = new AMap.Marker({
|
||||||
position: [s.lng, s.lat],
|
position: [s.lng, s.lat],
|
||||||
content: cardHtml(s, 0, 0),
|
content: cardHtml(s, 0, 0, si),
|
||||||
anchor: 'center',
|
anchor: 'center',
|
||||||
map: map,
|
map: map,
|
||||||
});
|
});
|
||||||
@@ -251,14 +265,14 @@ foreach ($activities as $a) {
|
|||||||
卡片被甩到容器外、被上方的标签栏挡住,点不到。) */
|
卡片被甩到容器外、被上方的标签栏挡住,点不到。) */
|
||||||
function relayout() {
|
function relayout() {
|
||||||
var items = [];
|
var items = [];
|
||||||
markers.forEach(function (m) {
|
markers.forEach(function (m, mi) {
|
||||||
var base = null;
|
var base = null;
|
||||||
try {
|
try {
|
||||||
base = map.lngLatToContainer(new AMap.LngLat(m.spot.lng, m.spot.lat));
|
base = map.lngLatToContainer(new AMap.LngLat(m.spot.lng, m.spot.lat));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
base = null;
|
base = null;
|
||||||
}
|
}
|
||||||
items.push({ mk: m.mk, spot: m.spot, base: base, dx: 0, dy: 0 });
|
items.push({ mk: m.mk, spot: m.spot, base: base, dx: 0, dy: 0, idx: mi });
|
||||||
});
|
});
|
||||||
|
|
||||||
/* 并查集:中心距 < CLUSTER_DIST 的归为同簇 */
|
/* 并查集:中心距 < CLUSTER_DIST 的归为同簇 */
|
||||||
@@ -352,7 +366,7 @@ foreach ($activities as $a) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
items.forEach(function (it) {
|
items.forEach(function (it) {
|
||||||
if (it.base) it.mk.setContent(cardHtml(it.spot, it.dx, it.dy));
|
if (it.base) it.mk.setContent(cardHtml(it.spot, it.dx, it.dy, it.idx));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
relayout();
|
relayout();
|
||||||
|
|||||||
Reference in New Issue
Block a user