Use legacy-closer compare style for Karatsu 20nm pages
This commit is contained in:
@@ -18,9 +18,40 @@ Remote: `ssh://git@nas:2222/tei/pbf.git`
|
|||||||
- [`.codex/SESSION_START.md`](/root/sourceserver/pbf/.codex/SESSION_START.md)
|
- [`.codex/SESSION_START.md`](/root/sourceserver/pbf/.codex/SESSION_START.md)
|
||||||
- [`.codex/RESUME_PROMPT.md`](/root/sourceserver/pbf/.codex/RESUME_PROMPT.md)
|
- [`.codex/RESUME_PROMPT.md`](/root/sourceserver/pbf/.codex/RESUME_PROMPT.md)
|
||||||
- 已完成一次新的 delivery 审计,并确认哪条审计线可用
|
- 已完成一次新的 delivery 审计,并确认哪条审计线可用
|
||||||
|
- 已把 `Karatsu 20nm` 的最新展示页和左右对比页切到更贴近旧视觉的 compare style
|
||||||
|
|
||||||
## Latest Audit Status
|
## Latest Audit Status
|
||||||
|
|
||||||
|
### 0. Latest Visual Compare Adjustment
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
- [`src/pbf/navsea-delivery-karatsu-20nm-latest.html`](/root/sourceserver/pbf/src/pbf/navsea-delivery-karatsu-20nm-latest.html)
|
||||||
|
- [`src/pbf/navsea-compare-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-compare-karatsu-20nm.html)
|
||||||
|
|
||||||
|
当前这两个页面已经从:
|
||||||
|
|
||||||
|
- `style.navsea-delivery-karatsu-10nm.json`
|
||||||
|
|
||||||
|
切到:
|
||||||
|
|
||||||
|
- `style.compare-delivery-karatsu-10nm.json`
|
||||||
|
|
||||||
|
目的:
|
||||||
|
|
||||||
|
- 先用现成的“兼容旧视觉”样式,把 20nm 右侧画面尽快拉近原始版
|
||||||
|
- 在不强行覆盖当前 delivery style 主文件的前提下,先验证视觉方向
|
||||||
|
|
||||||
|
当前线上页面:
|
||||||
|
|
||||||
|
- `http://192.168.200.184/newpec/navsea-delivery-karatsu-20nm-latest.html`
|
||||||
|
- `http://192.168.200.184/newpec/navsea-compare-karatsu-20nm.html`
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- 这一步优先解决“肉眼差距太大”的问题
|
||||||
|
- 下一步仍要把有效改动逐步收敛回正式 delivery style
|
||||||
|
|
||||||
### 1. Karatsu 20nm delivery
|
### 1. Karatsu 20nm delivery
|
||||||
|
|
||||||
已产出:
|
已产出:
|
||||||
|
|||||||
513
src/pbf/navsea-compare-karatsu-20nm.html
Normal file
513
src/pbf/navsea-compare-karatsu-20nm.html
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<title>NavSea Karatsu 20nm Compare</title>
|
||||||
|
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #eef2ed;
|
||||||
|
--panel: rgba(250, 248, 242, 0.94);
|
||||||
|
--ink: #17232b;
|
||||||
|
--muted: #667780;
|
||||||
|
--line: rgba(23, 35, 43, 0.12);
|
||||||
|
--shadow: 0 14px 28px rgba(23, 35, 43, 0.14);
|
||||||
|
--left: #305f72;
|
||||||
|
--right: #8b5e34;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, rgba(48, 95, 114, 0.12), transparent 28%),
|
||||||
|
radial-gradient(circle at bottom right, rgba(139, 94, 52, 0.1), transparent 24%),
|
||||||
|
var(--bg);
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: "Avenir Next", "Segoe UI", "PingFang SC", "Noto Sans SC", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 18px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 14px 18px 12px;
|
||||||
|
background: linear-gradient(180deg, rgba(250, 248, 242, 0.98), rgba(250, 248, 242, 0.9));
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
z-index: 20;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin-top: 4px;
|
||||||
|
max-width: 920px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(23, 35, 43, 0.16);
|
||||||
|
background: linear-gradient(180deg, #234a59, #17333f);
|
||||||
|
color: #fff;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 10px 22px rgba(23, 35, 43, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
min-height: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane {
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
border-right: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
left: 12px;
|
||||||
|
z-index: 5;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid rgba(23, 35, 43, 0.08);
|
||||||
|
box-shadow: 0 12px 24px rgba(23, 35, 43, 0.12);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-tag strong {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-tag span {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-panel {
|
||||||
|
position: fixed;
|
||||||
|
right: 14px;
|
||||||
|
bottom: 14px;
|
||||||
|
z-index: 30;
|
||||||
|
width: min(380px, calc(100vw - 28px));
|
||||||
|
max-height: 42vh;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 11px 12px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: rgba(250, 248, 242, 0.95);
|
||||||
|
border: 1px solid rgba(23, 35, 43, 0.12);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-panel h3 {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-hint {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-meta {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 96px 1fr;
|
||||||
|
gap: 4px 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-meta dt {
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-meta dd {
|
||||||
|
margin: 0;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-json {
|
||||||
|
margin: 0;
|
||||||
|
padding: 9px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(23, 35, 43, 0.93);
|
||||||
|
color: #eef4f7;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.4;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 14px;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 30;
|
||||||
|
max-width: calc(100% - 420px);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(23, 35, 43, 0.84);
|
||||||
|
color: #f7f9fb;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 980px) {
|
||||||
|
.layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane {
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspect-panel {
|
||||||
|
width: min(360px, calc(100vw - 24px));
|
||||||
|
max-height: 30vh;
|
||||||
|
right: 12px;
|
||||||
|
bottom: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
max-width: calc(100% - 24px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="toolbar">
|
||||||
|
<div>
|
||||||
|
<div class="title">唐津 20 海里对比页</div>
|
||||||
|
<div class="subtitle">左侧是原始版 <code>style.json</code>,右侧是更贴近旧视觉的兼容 delivery 样式 + 唐津 20 海里 delivery PBF。两边联动同步,点击任一对象可查看属性,适合直接肉眼排差异。</div>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<button id="reload-btn" type="button">重新加载</button>
|
||||||
|
<button id="home-btn" type="button">回到唐津</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layout">
|
||||||
|
<section class="pane">
|
||||||
|
<div class="pane-tag">
|
||||||
|
<strong style="color: var(--left);">左侧 · 原始版</strong>
|
||||||
|
<span>style.json + 原始 newpec 瓦片</span>
|
||||||
|
</div>
|
||||||
|
<div id="map-original" class="map"></div>
|
||||||
|
</section>
|
||||||
|
<section class="pane">
|
||||||
|
<div class="pane-tag">
|
||||||
|
<strong style="color: var(--right);">右侧 · Delivery</strong>
|
||||||
|
<span>兼容旧视觉 delivery style + 唐津 20 海里 PBF</span>
|
||||||
|
</div>
|
||||||
|
<div id="map-delivery" class="map"></div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside class="inspect-panel">
|
||||||
|
<h3>点击对比</h3>
|
||||||
|
<p id="inspect-hint" class="inspect-hint">点击左右任一地图对象,查看当前命中的 source、source-layer、render layer 和属性。</p>
|
||||||
|
<dl class="inspect-meta">
|
||||||
|
<dt>面板</dt>
|
||||||
|
<dd id="inspect-side">-</dd>
|
||||||
|
<dt>点击坐标</dt>
|
||||||
|
<dd id="inspect-lnglat">-</dd>
|
||||||
|
<dt>source</dt>
|
||||||
|
<dd id="inspect-source">-</dd>
|
||||||
|
<dt>source-layer</dt>
|
||||||
|
<dd id="inspect-layer">-</dd>
|
||||||
|
<dt>geometry</dt>
|
||||||
|
<dd id="inspect-geometry">-</dd>
|
||||||
|
<dt>render layer</dt>
|
||||||
|
<dd id="inspect-render-layer">-</dd>
|
||||||
|
</dl>
|
||||||
|
<pre id="inspect-json" class="inspect-json">{
|
||||||
|
"message": "等待点击对象"
|
||||||
|
}</pre>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<div id="status" class="status">等待加载对比样式…</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
||||||
|
<script>
|
||||||
|
const ORIGINAL_STYLE_URL = "./style.json";
|
||||||
|
const DELIVERY_STYLE_URL = "./domain/style.compare-delivery-karatsu-10nm.json";
|
||||||
|
const ORIGINAL_TILE_URL = "http://192.168.200.184/newpec/exported_auto/tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles/{z}/{x}/{y}.pbf";
|
||||||
|
const DELIVERY_TILE_URL = "http://192.168.200.184/pbf-delivery-karatsu-20nm/{z}/{x}/{y}.pbf";
|
||||||
|
const INITIAL_VIEW = {
|
||||||
|
center: [129.9697, 33.4425],
|
||||||
|
zoom: 11,
|
||||||
|
bearing: 0,
|
||||||
|
pitch: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const reloadBtn = document.getElementById("reload-btn");
|
||||||
|
const homeBtn = document.getElementById("home-btn");
|
||||||
|
const statusEl = document.getElementById("status");
|
||||||
|
const inspectHintEl = document.getElementById("inspect-hint");
|
||||||
|
const inspectSideEl = document.getElementById("inspect-side");
|
||||||
|
const inspectLngLatEl = document.getElementById("inspect-lnglat");
|
||||||
|
const inspectSourceEl = document.getElementById("inspect-source");
|
||||||
|
const inspectLayerEl = document.getElementById("inspect-layer");
|
||||||
|
const inspectGeometryEl = document.getElementById("inspect-geometry");
|
||||||
|
const inspectRenderLayerEl = document.getElementById("inspect-render-layer");
|
||||||
|
const inspectJsonEl = document.getElementById("inspect-json");
|
||||||
|
|
||||||
|
let originalMap;
|
||||||
|
let deliveryMap;
|
||||||
|
let syncLock = false;
|
||||||
|
let styleVersion = Date.now().toString();
|
||||||
|
|
||||||
|
function setStatus(text) {
|
||||||
|
statusEl.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withCacheBuster(url, version) {
|
||||||
|
const separator = url.includes("?") ? "&" : "?";
|
||||||
|
return `${url}${separator}v=${version}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStyle(url) {
|
||||||
|
const response = await fetch(withCacheBuster(url, styleVersion), { cache: "no-store" });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`加载样式失败: ${url}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchStyleAssets(style) {
|
||||||
|
if (style.sprite) style.sprite = withCacheBuster(style.sprite, styleVersion);
|
||||||
|
if (style.glyphs) style.glyphs = withCacheBuster(style.glyphs, styleVersion);
|
||||||
|
Object.values(style.sources || {}).forEach((source) => {
|
||||||
|
if (Array.isArray(source.tiles)) {
|
||||||
|
source.tiles = source.tiles.map((tileUrl) => withCacheBuster(tileUrl, styleVersion));
|
||||||
|
}
|
||||||
|
if (typeof source.url === "string") {
|
||||||
|
source.url = withCacheBuster(source.url, styleVersion);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOriginalStyle(style) {
|
||||||
|
const next = structuredClone(style);
|
||||||
|
if (next.sources?.newpec) {
|
||||||
|
next.sources.newpec.tiles = [withCacheBuster(ORIGINAL_TILE_URL, styleVersion)];
|
||||||
|
}
|
||||||
|
return touchStyleAssets(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDeliveryStyle(style) {
|
||||||
|
const next = structuredClone(style);
|
||||||
|
if (next.sources?.navsea_delivery) {
|
||||||
|
next.sources.navsea_delivery.tiles = [withCacheBuster(DELIVERY_TILE_URL, styleVersion)];
|
||||||
|
}
|
||||||
|
return touchStyleAssets(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetInspectPanel(message) {
|
||||||
|
inspectHintEl.textContent = message;
|
||||||
|
inspectSideEl.textContent = "-";
|
||||||
|
inspectLngLatEl.textContent = "-";
|
||||||
|
inspectSourceEl.textContent = "-";
|
||||||
|
inspectLayerEl.textContent = "-";
|
||||||
|
inspectGeometryEl.textContent = "-";
|
||||||
|
inspectRenderLayerEl.textContent = "-";
|
||||||
|
inspectJsonEl.textContent = JSON.stringify({ message }, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLngLat(lngLat) {
|
||||||
|
return `${lngLat.lng.toFixed(6)}, ${lngLat.lat.toFixed(6)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateInspectPanel(side, event, feature) {
|
||||||
|
inspectHintEl.textContent = "已选中对象。继续点击可对照两侧差异。";
|
||||||
|
inspectSideEl.textContent = side;
|
||||||
|
inspectLngLatEl.textContent = formatLngLat(event.lngLat);
|
||||||
|
inspectSourceEl.textContent = feature.source || "-";
|
||||||
|
inspectLayerEl.textContent = feature.sourceLayer || feature.layer?.["source-layer"] || "-";
|
||||||
|
inspectGeometryEl.textContent = feature.geometry?.type || "-";
|
||||||
|
inspectRenderLayerEl.textContent = feature.layer?.id || "-";
|
||||||
|
inspectJsonEl.textContent = JSON.stringify(feature.properties || {}, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindInspect(map, sideLabel) {
|
||||||
|
map.on("click", (event) => {
|
||||||
|
const features = map.queryRenderedFeatures(event.point);
|
||||||
|
if (!features.length) {
|
||||||
|
resetInspectPanel(`${sideLabel}点击位置没有命中对象。点击坐标: ${formatLngLat(event.lngLat)}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateInspectPanel(sideLabel, event, features[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncMaps(primary, secondary) {
|
||||||
|
primary.on("move", () => {
|
||||||
|
if (syncLock) return;
|
||||||
|
syncLock = true;
|
||||||
|
secondary.jumpTo({
|
||||||
|
center: primary.getCenter(),
|
||||||
|
zoom: primary.getZoom(),
|
||||||
|
bearing: primary.getBearing(),
|
||||||
|
pitch: primary.getPitch()
|
||||||
|
});
|
||||||
|
syncLock = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMaps() {
|
||||||
|
styleVersion = Date.now().toString();
|
||||||
|
reloadBtn.disabled = true;
|
||||||
|
homeBtn.disabled = true;
|
||||||
|
setStatus("正在加载原始版和 delivery 版样式…");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [originalStyleRaw, deliveryStyleRaw] = await Promise.all([
|
||||||
|
fetchStyle(ORIGINAL_STYLE_URL),
|
||||||
|
fetchStyle(DELIVERY_STYLE_URL)
|
||||||
|
]);
|
||||||
|
const originalStyle = buildOriginalStyle(originalStyleRaw);
|
||||||
|
const deliveryStyle = buildDeliveryStyle(deliveryStyleRaw);
|
||||||
|
|
||||||
|
if (!originalMap && !deliveryMap) {
|
||||||
|
originalMap = new maplibregl.Map({
|
||||||
|
container: "map-original",
|
||||||
|
style: originalStyle,
|
||||||
|
center: INITIAL_VIEW.center,
|
||||||
|
zoom: INITIAL_VIEW.zoom,
|
||||||
|
bearing: INITIAL_VIEW.bearing,
|
||||||
|
pitch: INITIAL_VIEW.pitch
|
||||||
|
});
|
||||||
|
deliveryMap = new maplibregl.Map({
|
||||||
|
container: "map-delivery",
|
||||||
|
style: deliveryStyle,
|
||||||
|
center: INITIAL_VIEW.center,
|
||||||
|
zoom: INITIAL_VIEW.zoom,
|
||||||
|
bearing: INITIAL_VIEW.bearing,
|
||||||
|
pitch: INITIAL_VIEW.pitch
|
||||||
|
});
|
||||||
|
|
||||||
|
originalMap.addControl(new maplibregl.NavigationControl(), "top-right");
|
||||||
|
deliveryMap.addControl(new maplibregl.NavigationControl(), "top-right");
|
||||||
|
bindInspect(originalMap, "左侧原始版");
|
||||||
|
bindInspect(deliveryMap, "右侧Delivery");
|
||||||
|
syncMaps(originalMap, deliveryMap);
|
||||||
|
syncMaps(deliveryMap, originalMap);
|
||||||
|
|
||||||
|
let loaded = 0;
|
||||||
|
function markLoaded() {
|
||||||
|
loaded += 1;
|
||||||
|
if (loaded >= 2) {
|
||||||
|
setStatus("双屏已加载,可直接拖动、缩放、点击对比。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originalMap.on("load", markLoaded);
|
||||||
|
deliveryMap.on("load", markLoaded);
|
||||||
|
} else {
|
||||||
|
const camera = {
|
||||||
|
center: originalMap.getCenter(),
|
||||||
|
zoom: originalMap.getZoom(),
|
||||||
|
bearing: originalMap.getBearing(),
|
||||||
|
pitch: originalMap.getPitch()
|
||||||
|
};
|
||||||
|
let loaded = 0;
|
||||||
|
function markLoaded() {
|
||||||
|
loaded += 1;
|
||||||
|
if (loaded >= 2) {
|
||||||
|
originalMap.jumpTo(camera);
|
||||||
|
deliveryMap.jumpTo(camera);
|
||||||
|
setStatus("双屏样式已重新加载。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originalMap.once("style.load", markLoaded);
|
||||||
|
deliveryMap.once("style.load", markLoaded);
|
||||||
|
originalMap.setStyle(originalStyle, { diff: false });
|
||||||
|
deliveryMap.setStyle(deliveryStyle, { diff: false });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
setStatus(error.message || "加载失败");
|
||||||
|
} finally {
|
||||||
|
reloadBtn.disabled = false;
|
||||||
|
homeBtn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadBtn.addEventListener("click", loadMaps);
|
||||||
|
homeBtn.addEventListener("click", () => {
|
||||||
|
if (!originalMap || !deliveryMap) return;
|
||||||
|
const camera = {
|
||||||
|
center: INITIAL_VIEW.center,
|
||||||
|
zoom: INITIAL_VIEW.zoom,
|
||||||
|
bearing: INITIAL_VIEW.bearing,
|
||||||
|
pitch: INITIAL_VIEW.pitch
|
||||||
|
};
|
||||||
|
originalMap.jumpTo(camera);
|
||||||
|
deliveryMap.jumpTo(camera);
|
||||||
|
setStatus("已回到唐津 20 海里初始视角。");
|
||||||
|
});
|
||||||
|
|
||||||
|
resetInspectPanel("点击左右任一地图对象,查看当前命中的 source、source-layer、render layer 和属性。");
|
||||||
|
loadMaps();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
96
src/pbf/navsea-delivery-karatsu-20nm-latest.html
Normal file
96
src/pbf/navsea-delivery-karatsu-20nm-latest.html
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<title>NavSea Delivery Karatsu 20nm Latest</title>
|
||||||
|
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; height: 100%; }
|
||||||
|
#map { position: fixed; inset: 0; }
|
||||||
|
.panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 12px;
|
||||||
|
left: 12px;
|
||||||
|
z-index: 10;
|
||||||
|
max-width: min(560px, calc(100vw - 24px));
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(255,255,255,0.94);
|
||||||
|
border: 1px solid rgba(0,0,0,0.12);
|
||||||
|
font: 12px/1.45 "Segoe UI", "PingFang SC", "Noto Sans SC", sans-serif;
|
||||||
|
}
|
||||||
|
.panel strong { display: block; margin-bottom: 4px; font-size: 13px; }
|
||||||
|
.status {
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 12px;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 10;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(0,0,0,0.78);
|
||||||
|
color: #fff;
|
||||||
|
font: 12px/1.4 "Segoe UI", sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<div class="panel">
|
||||||
|
<strong>NavSea Delivery Karatsu 20nm Latest</strong>
|
||||||
|
<div>Style: <code>./domain/style.compare-delivery-karatsu-10nm.json</code></div>
|
||||||
|
<div>Tiles: <code>http://192.168.200.184/pbf-delivery-karatsu-20nm/{z}/{x}/{y}.pbf</code></div>
|
||||||
|
</div>
|
||||||
|
<div id="status" class="status">正在加载最新 delivery 样式…</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
||||||
|
<script>
|
||||||
|
const STYLE_URL = "./domain/style.compare-delivery-karatsu-10nm.json";
|
||||||
|
const TILE_URL = "http://192.168.200.184/pbf-delivery-karatsu-20nm/{z}/{x}/{y}.pbf";
|
||||||
|
const styleVersion = Date.now().toString();
|
||||||
|
const statusEl = document.getElementById("status");
|
||||||
|
|
||||||
|
function withCacheBuster(url) {
|
||||||
|
const sep = url.includes("?") ? "&" : "?";
|
||||||
|
return `${url}${sep}v=${styleVersion}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStatus(text) {
|
||||||
|
statusEl.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const response = await fetch(withCacheBuster(STYLE_URL), { cache: "no-store" });
|
||||||
|
if (!response.ok) throw new Error(`加载样式失败: ${STYLE_URL}`);
|
||||||
|
const style = await response.json();
|
||||||
|
if (style.sprite) style.sprite = withCacheBuster(style.sprite);
|
||||||
|
if (style.glyphs) style.glyphs = withCacheBuster(style.glyphs);
|
||||||
|
if (style.sources && style.sources.navsea_delivery) {
|
||||||
|
style.sources.navsea_delivery.tiles = [withCacheBuster(TILE_URL)];
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = new maplibregl.Map({
|
||||||
|
container: "map",
|
||||||
|
style,
|
||||||
|
center: [129.9697, 33.4425],
|
||||||
|
zoom: 11,
|
||||||
|
hash: true
|
||||||
|
});
|
||||||
|
|
||||||
|
map.addControl(new maplibregl.NavigationControl(), "top-right");
|
||||||
|
map.on("load", () => setStatus("最新 delivery 样式已加载"));
|
||||||
|
map.on("error", (event) => {
|
||||||
|
const message = event && event.error && event.error.message ? event.error.message : "未知错误";
|
||||||
|
setStatus(`加载出错: ${message}`);
|
||||||
|
console.error(event.error || event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
setStatus(error.message || "加载失败");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user