fix: refine workbench map layers
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||||
18
.trellis/tasks/08-26-workbench-layer-scene-polish/prd.md
Normal file
18
.trellis/tasks/08-26-workbench-layer-scene-polish/prd.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# 优化工作台图层与场景标线
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
移除不再需要的高德规整路口参考图层,提供可读的编译概览,并恢复场景模式下双向道路中心线的可辨识渲染。
|
||||||
|
|
||||||
|
## Confirmed Facts
|
||||||
|
|
||||||
|
- 科技园一路的三个双向路段在 `center_lines.geojson` 中都有完整的黄色虚线 feature;不是编译缺失。
|
||||||
|
- React adapter 将原版中心线的属性驱动样式简化为固定样式,造成场景模式下辨识度不正确。
|
||||||
|
- 高德参考层仅在 React 前端图层 registry、图层开关和状态装载中使用;不影响编译。
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- 工作台不显示或加载高德规整路口参考图层。
|
||||||
|
- 场景模式下保留中心线,并按线的颜色和虚/实线属性清晰渲染。
|
||||||
|
- 编译概览以中文分组指标和诊断摘要展示,不显示 schema、note、null 或 `[object Object]`。
|
||||||
|
- 格式化、类型检查和生产构建通过。
|
||||||
26
.trellis/tasks/08-26-workbench-layer-scene-polish/task.json
Normal file
26
.trellis/tasks/08-26-workbench-layer-scene-polish/task.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"id": "workbench-layer-scene-polish",
|
||||||
|
"name": "workbench-layer-scene-polish",
|
||||||
|
"title": "优化工作台图层与场景标线",
|
||||||
|
"description": "移除高德规整路口参考,优化编译概览,并修复场景模式下科技园一路中心线缺失",
|
||||||
|
"status": "in_progress",
|
||||||
|
"dev_type": null,
|
||||||
|
"scope": null,
|
||||||
|
"package": null,
|
||||||
|
"priority": "P2",
|
||||||
|
"creator": "dingkang",
|
||||||
|
"assignee": "dingkang",
|
||||||
|
"createdAt": "2026-08-26",
|
||||||
|
"completedAt": null,
|
||||||
|
"branch": null,
|
||||||
|
"base_branch": "main",
|
||||||
|
"worktree_path": null,
|
||||||
|
"commit": null,
|
||||||
|
"pr_url": null,
|
||||||
|
"subtasks": [],
|
||||||
|
"children": [],
|
||||||
|
"parent": null,
|
||||||
|
"relatedFiles": [],
|
||||||
|
"notes": "",
|
||||||
|
"meta": {}
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@ const layerLabels: Array<[LayerName, string]> = [
|
|||||||
['edgeLines', '道路外缘线'],
|
['edgeLines', '道路外缘线'],
|
||||||
['controls', '斑马线与停止线'],
|
['controls', '斑马线与停止线'],
|
||||||
['signals', '红绿灯设施'],
|
['signals', '红绿灯设施'],
|
||||||
['gaodeReference', '高德规整路口参考'],
|
|
||||||
['reference', 'osm2streets 参考面'],
|
['reference', 'osm2streets 参考面'],
|
||||||
];
|
];
|
||||||
const defaultLayers = Object.fromEntries(
|
const defaultLayers = Object.fromEntries(
|
||||||
@@ -26,6 +25,50 @@ const defaultLayers = Object.fromEntries(
|
|||||||
const direction = (road: Road) => (road.direction === 'forward' ? '沿 OSM 方向' : '逆 OSM 方向');
|
const direction = (road: Road) => (road.direction === 'forward' ? '沿 OSM 方向' : '逆 OSM 方向');
|
||||||
const label = (road: Road) => road.tags.name || `${road.highway}(OSM ${road.osmWayIds.join(', ')})`;
|
const label = (road: Road) => road.tags.name || `${road.highway}(OSM ${road.osmWayIds.join(', ')})`;
|
||||||
const laneIndex = (id: string) => Number(id.split(':').at(-1));
|
const laneIndex = (id: string) => Number(id.split(':').at(-1));
|
||||||
|
const overviewMetrics = [
|
||||||
|
['nativeRoadCount', '方向道路'],
|
||||||
|
['nativeRoadSurfaceFeatures', '道路面'],
|
||||||
|
['nativeJunctionSurfaceFeatures', '路口面'],
|
||||||
|
['nativeLaneCenterlineFeatures', '车道中心线'],
|
||||||
|
['nativeCenterLineFeatures', '道路中心线'],
|
||||||
|
['nativeConnectorFeatures', '连接路径'],
|
||||||
|
['nativeCrosswalkFeatures', '斑马线'],
|
||||||
|
['nativeVehicleStopLineFeatures', '停止线'],
|
||||||
|
['unconnectedInteriorRoadEnds', '未连接端点'],
|
||||||
|
] as const;
|
||||||
|
function Overview({ comparison }: { comparison: Record<string, unknown> }) {
|
||||||
|
const severity = comparison.diagnosticsBySeverity as Record<string, number> | undefined;
|
||||||
|
return (
|
||||||
|
<section className="overview">
|
||||||
|
<div className="overview-grid">
|
||||||
|
{overviewMetrics.map(([key, label]) => (
|
||||||
|
<div key={key}>
|
||||||
|
<span>{label}</span>
|
||||||
|
<strong>{Number(comparison[key] || 0).toLocaleString('zh-CN')}</strong>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="overview-status">
|
||||||
|
<span>osm2streets 参考面</span>
|
||||||
|
<strong>
|
||||||
|
{comparison.osm2streetsAvailable === true
|
||||||
|
? `${Number(comparison.osm2streetsRoadSurfaceFeatures || 0)} 个`
|
||||||
|
: '未提供'}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
{severity && (
|
||||||
|
<div className="overview-diagnostics">
|
||||||
|
<span>编译诊断</span>
|
||||||
|
{Object.entries(severity).map(([level, count]) => (
|
||||||
|
<strong key={level}>
|
||||||
|
{level === 'error' ? '错误' : level === 'warning' ? '警告' : '提示'} {count}
|
||||||
|
</strong>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
function App() {
|
function App() {
|
||||||
const [state, setState] = useState<WorkbenchState>();
|
const [state, setState] = useState<WorkbenchState>();
|
||||||
const [selected, setSelected] = useState<Road | null>(null);
|
const [selected, setSelected] = useState<Road | null>(null);
|
||||||
@@ -137,14 +180,7 @@ function App() {
|
|||||||
))}
|
))}
|
||||||
<hr />
|
<hr />
|
||||||
<h1>当前编译概览</h1>
|
<h1>当前编译概览</h1>
|
||||||
<dl>
|
<Overview comparison={state.comparison} />
|
||||||
{Object.entries(state.comparison).map(([key, value]) => (
|
|
||||||
<>
|
|
||||||
<dt key={`${key}-t`}>{key}</dt>
|
|
||||||
<dd key={`${key}-d`}>{String(value)}</dd>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</dl>
|
|
||||||
<hr />
|
<hr />
|
||||||
<h1>待检查问题</h1>
|
<h1>待检查问题</h1>
|
||||||
<div className="segmented">
|
<div className="segmented">
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ const geojson = new GeoJSON();
|
|||||||
const source = () => new VectorSource();
|
const source = () => new VectorSource();
|
||||||
export type LayerName =
|
export type LayerName =
|
||||||
| 'reference'
|
| 'reference'
|
||||||
| 'gaodeReference'
|
|
||||||
| 'native'
|
| 'native'
|
||||||
| 'sidewalks'
|
| 'sidewalks'
|
||||||
| 'osm'
|
| 'osm'
|
||||||
@@ -34,7 +33,6 @@ export function createLayers(onRoad: () => Road | null, scene: () => boolean) {
|
|||||||
new Style({ fill: new Fill({ color: `${color}55` }), stroke: new Stroke({ color, width }) });
|
new Style({ fill: new Fill({ color: `${color}55` }), stroke: new Stroke({ color, width }) });
|
||||||
const layers: Record<LayerName, VectorLayer<VectorSource>> = {
|
const layers: Record<LayerName, VectorLayer<VectorSource>> = {
|
||||||
reference: new VectorLayer({ source: source(), visible: false, style: simple('#8999a0') }),
|
reference: new VectorLayer({ source: source(), visible: false, style: simple('#8999a0') }),
|
||||||
gaodeReference: new VectorLayer({ source: source(), style: simple('#2563eb', 1.5) }),
|
|
||||||
native: new VectorLayer({
|
native: new VectorLayer({
|
||||||
source: source(),
|
source: source(),
|
||||||
style: () => (scene() ? new Style({ fill: new Fill({ color: '#3f4b50' }) }) : simple('#296956')),
|
style: () => (scene() ? new Style({ fill: new Fill({ color: '#3f4b50' }) }) : simple('#296956')),
|
||||||
@@ -72,7 +70,15 @@ export function createLayers(onRoad: () => Road | null, scene: () => boolean) {
|
|||||||
}),
|
}),
|
||||||
centerLines: new VectorLayer({
|
centerLines: new VectorLayer({
|
||||||
source: source(),
|
source: source(),
|
||||||
style: new Style({ fill: new Fill({ color: '#f5be2a' }), stroke: new Stroke({ color: '#d29d16', width: 1 }) }),
|
style: (feature) => {
|
||||||
|
const white = feature.get('color') === 'white';
|
||||||
|
const color = white ? '#faf9ee' : '#f5be2a';
|
||||||
|
const solid = feature.get('pattern') === 'solid';
|
||||||
|
return new Style({
|
||||||
|
fill: new Fill({ color }),
|
||||||
|
stroke: new Stroke({ color: solid ? color : white ? '#aeb0aa' : '#d29d16', width: solid ? 0.25 : 0.8 }),
|
||||||
|
});
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
controls: new VectorLayer({
|
controls: new VectorLayer({
|
||||||
source: source(),
|
source: source(),
|
||||||
@@ -126,7 +132,6 @@ export function updateLayers(layers: ReturnType<typeof createLayers>, state: Wor
|
|||||||
target.addFeatures(features(value));
|
target.addFeatures(features(value));
|
||||||
};
|
};
|
||||||
put('reference', state.layers.osm2streetsRoadSurface);
|
put('reference', state.layers.osm2streetsRoadSurface);
|
||||||
put('gaodeReference', state.junctionReference?.converted);
|
|
||||||
put('native', state.layers.nativeRoadSurface);
|
put('native', state.layers.nativeRoadSurface);
|
||||||
get('native').addFeatures(features(state.layers.nativeIntersectionSurface));
|
get('native').addFeatures(features(state.layers.nativeIntersectionSurface));
|
||||||
put('sidewalks', state.layers.nativeSidewalkSurface);
|
put('sidewalks', state.layers.nativeSidewalkSurface);
|
||||||
|
|||||||
Reference in New Issue
Block a user