路线地图缩小时密集节点图标不再偏离(批 20)
节点很多又很密集时,地图缩小后有些图标位置会偏离很远: 排布器原来按「屏幕像素中心距」判碰撞,缩小时多真实坐标挤在几像素内, 被固定甩开 56px(低 zoom 下等于数公里),图标明显偏离真实位置。 - makePlacer 碰撞判定从「屏幕像素距离」改为「仅经纬度完全相同(posKey 一致)才偏移」 - 坐标不同但屏幕挨着的密集节点一律零偏移、留在真实位置(不再甩飞) - 往返(同中点)仍沿线段错开,保留去重;调用处传入真实坐标 pos - 补 _page20.php / _map20.js 密集簇+缩小回归,并更新批 14/渲染检查相关断言
This commit is contained in:
@@ -193,17 +193,16 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
window.__routeMap = map;
|
window.__routeMap = map;
|
||||||
var overlays = []; // 当前画上去的所有覆盖物;地理编码补点后整体重画
|
var overlays = []; // 当前画上去的所有覆盖物;地理编码补点后整体重画
|
||||||
|
|
||||||
/* ── 防重合(批 15 改法)────────────────────────────────────
|
/* ── 防重合(批 15 改法,批 20 收紧)─────────────────────────
|
||||||
两类重合,治法不同:
|
只处理「经纬度完全相同」的重合,且只挪图标、不挪线、不改数据:
|
||||||
① 往返(A→B 与 B→A 是同一段):**线就让它重合** —— 把两段线左右错开画成
|
① 往返(A→B 与 B→A 是同一段):两段线重合(本就该重合),但两枚图标会
|
||||||
双向车道,偏移量大、看着像画错了;真正的诉求只是「两枚图标别叠在一起」。
|
叠在同一中点 → 沿这条线**前后排开**,看上去就是同一条路上跑了两趟。
|
||||||
所以只把图标沿这条线**前后排开**,看上去就是同一条路上跑了两趟。
|
② 坐标不同、只是屏幕上挨着的密集节点(缩小时尤甚):**不再让开**,
|
||||||
② 距离很近的地点(相差几公里):坐标不同,但"看全国"的缩放级别下像素位置
|
一律留在真实经纬度上。批 20 之前按屏幕像素距离判碰撞、把挨着的标记
|
||||||
几乎一致 → 也各自沿自己那条线让开。
|
各甩 56px(低 zoom 下等于数公里),导致缩小时图标明显偏离真实位置。
|
||||||
位移方向一律取**线段本身的屏幕方向**(不是固定往右挪),线段太短装不下时
|
判定从「屏幕像素中心距」改为「posKey 经纬度字符串是否相同」:只有
|
||||||
才退到法线、再退到水平。判定仍按**屏幕像素**:坐标不同但屏幕上挨着的情况,
|
完全相同的坐标才偏移,否则零偏移。位移方向取线段屏幕方向,太短则退法线、再水平。
|
||||||
比坐标字符串没用(批 14 实测「中央大街/松花江」坐标差几公里照样叠 34px)。
|
错开只改「怎么画」,不改数据 —— inPath / prevEnd 仍用原始坐标。 */
|
||||||
注意:错开只改「怎么画」,不改数据 —— inPath / prevEnd 仍用原始坐标。 */
|
|
||||||
var MARK_W = 46; // 碰撞判定:圆标直径 40 + 6px 间隙(按中心距判,见下面的排布器)
|
var MARK_W = 46; // 碰撞判定:圆标直径 40 + 6px 间隙(按中心距判,见下面的排布器)
|
||||||
var STEP = MARK_W + 10; // 让开一步 = 56px(圆标净间隙 16px,两枚挨着也分得清)
|
var STEP = MARK_W + 10; // 让开一步 = 56px(圆标净间隙 16px,两枚挨着也分得清)
|
||||||
|
|
||||||
@@ -243,32 +242,29 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
return d;
|
return d;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/** 贪心排布:撞上了就沿**这段线**的方向让开(图标仍排在这条线上),
|
/** 排布:只有「经纬度完全相同」的标记才偏移(批 20 收紧)。
|
||||||
线太短装不下再走法线、最后水平兜底。返回像素偏移 {x, y}。 */
|
坐标不同 → 一律零偏移,留在真实位置,不再按屏幕像素甩开。
|
||||||
|
同坐标重复(如往返中点)沿这段线前后排开,线太短走法线、再水平兜底。 */
|
||||||
function makePlacer() {
|
function makePlacer() {
|
||||||
var placed = []; // 已占用的屏幕坐标(容器像素)
|
var seen = {}; // posKey(realCoord) -> 已在该坐标放置的标记数
|
||||||
/* 图标是圆的(直径 40),按**中心距**判碰撞比按矩形准:
|
|
||||||
斜着挪 52px 时 x 只差 31、y 只差 42,矩形判定会说「还重叠」,
|
|
||||||
于是白挪一步(两枚图标被拉到 104px 远,看着像没关系)。 */
|
|
||||||
function hit(x, y) {
|
|
||||||
for (var j = 0; j < placed.length; j++) {
|
|
||||||
var q = placed[j];
|
|
||||||
if (Math.hypot(x - q.x, y - q.y) < MARK_W) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
place: function (base, dir) {
|
place: function (dir, pos) {
|
||||||
/* 沿线最多挪到快到端点为止 —— 挪出线段就不再是「在这条线上」了 */
|
var key = posKey(pos);
|
||||||
|
var n = seen[key] || 0;
|
||||||
|
if (n === 0) { // 该坐标第一枚:原地放,不偏移
|
||||||
|
seen[key] = 1;
|
||||||
|
return { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
/* 同坐标重复:沿这段线让开(图标仍排在这条线上) */
|
||||||
var maxAlong = Math.max(0, dir.len * 0.45 - MARK_W / 2);
|
var maxAlong = Math.max(0, dir.len * 0.45 - MARK_W / 2);
|
||||||
var cand = [{ x: 0, y: 0 }];
|
var cand = [];
|
||||||
var k, step, sg;
|
var k, step, sg;
|
||||||
for (k = 1; k <= 4; k++) { // ① 沿线前后交替(首选)
|
for (k = 1; k <= 4; k++) { // ① 沿线前后交替(首选)
|
||||||
step = Math.ceil(k / 2) * STEP;
|
step = Math.ceil(k / 2) * STEP;
|
||||||
sg = (k % 2 === 1) ? 1 : -1;
|
sg = (k % 2 === 1) ? 1 : -1;
|
||||||
if (step <= maxAlong) cand.push({ x: dir.x * step * sg, y: dir.y * step * sg });
|
if (step <= maxAlong) cand.push({ x: dir.x * step * sg, y: dir.y * step * sg });
|
||||||
}
|
}
|
||||||
for (k = 1; k <= 4; k++) { // ② 线太短:改走法线(少量)
|
for (k = 1; k <= 4; k++) { // ② 线太短:改走法线
|
||||||
step = Math.ceil(k / 2) * STEP;
|
step = Math.ceil(k / 2) * STEP;
|
||||||
sg = (k % 2 === 1) ? 1 : -1;
|
sg = (k % 2 === 1) ? 1 : -1;
|
||||||
cand.push({ x: -dir.y * step * sg, y: dir.x * step * sg });
|
cand.push({ x: -dir.y * step * sg, y: dir.x * step * sg });
|
||||||
@@ -278,17 +274,13 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
sg = (k % 2 === 1) ? 1 : -1;
|
sg = (k % 2 === 1) ? 1 : -1;
|
||||||
cand.push({ x: step * sg, y: 0 });
|
cand.push({ x: step * sg, y: 0 });
|
||||||
}
|
}
|
||||||
/* cand[0] 是「原地不动」,一样要先判它:跳过去从 cand[1] 开始挑,
|
/* 第 n 次重复取第 n 个候选(跳过 cand[0]=原地),顺着线铺开;
|
||||||
第一枚标记也会被无谓地挪开一步(两枚本来该挨着 52px 的变成 104px)。 */
|
候选用尽就取最后一个,总比乱飞好 */
|
||||||
var pick = null;
|
var pick = cand.length ? cand[Math.min(n, cand.length - 1)] : { x: 0, y: 0 };
|
||||||
for (var i = 0; i < cand.length; i++) {
|
seen[key] = n + 1;
|
||||||
if (!hit(base.x + cand[i].x, base.y + cand[i].y)) { pick = cand[i]; break; }
|
|
||||||
}
|
|
||||||
if (!pick) pick = cand[0]; // 全都撞:退回原地,总比乱飞好
|
|
||||||
placed.push({ x: base.x + pick.x, y: base.y + pick.y });
|
|
||||||
return pick;
|
return pick;
|
||||||
},
|
},
|
||||||
reset: function () { placed = []; },
|
reset: function () { seen = {}; },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +296,7 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
var hopPath = []; // 节点之间:上一站到达地 → 下一站出发地(虚线)
|
var hopPath = []; // 节点之间:上一站到达地 → 下一站出发地(虚线)
|
||||||
var prevEnd = null;
|
var prevEnd = null;
|
||||||
var segDir = makeSegDir(); // 线段在屏幕上的方向:图标沿它排队
|
var segDir = makeSegDir(); // 线段在屏幕上的方向:图标沿它排队
|
||||||
var placer = makePlacer(); // 标记按屏幕像素排布,撞上就挪开
|
var placer = makePlacer(); // 标记排布:仅同坐标才偏移,否则留真实位置(批 20)
|
||||||
var dotSeen = {}; // 到达地红点:同一点位只画一个
|
var dotSeen = {}; // 到达地红点:同一点位只画一个
|
||||||
|
|
||||||
route.forEach(function (n, i) {
|
route.forEach(function (n, i) {
|
||||||
@@ -325,19 +317,14 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
都不剩(批 11 上线后踩的坑,光秃秃地图就是它)。 */
|
都不剩(批 11 上线后踩的坑,光秃秃地图就是它)。 */
|
||||||
var pos = markerPos(n);
|
var pos = markerPos(n);
|
||||||
if (pos) {
|
if (pos) {
|
||||||
/* 先问地图「这个经纬度现在在屏幕哪个像素上」,再和已放的标记比距离:
|
/* 只把「经纬度完全相同」的标记(如往返中点)沿各自线段错开;
|
||||||
坐标不同但屏幕位置挨着(几公里的两个点、或往返的中点)都要挪开 */
|
坐标不同则一律留在真实位置,不再按屏幕像素甩开 —— 否则节点
|
||||||
var base = null;
|
密集、缩小时多枚标记会被甩出 56px(低 zoom 下=数公里),
|
||||||
try {
|
图标明显偏离真实坐标(批 20)。 */
|
||||||
base = map.lngLatToContainer(new AMap.LngLat(pos[0], pos[1]));
|
|
||||||
} catch (e) {
|
|
||||||
base = null;
|
|
||||||
}
|
|
||||||
/* 有整段线就沿这条线让开(前后排成一列),只有一头时退化成水平 */
|
|
||||||
var dir = (s && en)
|
var dir = (s && en)
|
||||||
? segDir([s.lng, s.lat], [en.lng, en.lat])
|
? segDir([s.lng, s.lat], [en.lng, en.lat])
|
||||||
: { x: 1, y: 0, len: 0 };
|
: { x: 1, y: 0, len: 0 };
|
||||||
var off = base ? placer.place(base, dir) : { x: 0, y: 0 };
|
var off = placer.place(dir, pos);
|
||||||
|
|
||||||
var html ='<div class="route-marker" title="' + n.title.replace(/"/g, '"') + '">'
|
var html ='<div class="route-marker" title="' + n.title.replace(/"/g, '"') + '">'
|
||||||
+ (n.img
|
+ (n.img
|
||||||
@@ -351,7 +338,7 @@ require dirname(__DIR__) . '/comments/_block.php';
|
|||||||
anchor: 'center',
|
anchor: 'center',
|
||||||
map: map,
|
map: map,
|
||||||
};
|
};
|
||||||
/* 撞上了就沿这条线挪开 —— 用像素偏移,谁也不挡谁 */
|
/* 同坐标的标记才沿这条线挪开 —— 用像素偏移,谁也不挡谁 */
|
||||||
if (off.x !== 0 || off.y !== 0) {
|
if (off.x !== 0 || off.y !== 0) {
|
||||||
opts.offset = new AMap.Pixel(off.x, off.y);
|
opts.offset = new AMap.Pixel(off.x, off.y);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user