73 lines
4.2 KiB
PHP
73 lines
4.2 KiB
PHP
<?php
|
||||
|
|
/**
|
|||
|
|
* 旅程**地图视图**的主体(v54 用户 2026-10-16 第 3 条)。
|
|||
|
|
*
|
|||
|
|
* 用户原话:「你去读一下 TripLog 的代码,在旅程这个模块,**可以在地图上显示旅程数据**。
|
|||
|
|
* 1. 先读一下它之前那个代码是怎么实现的,**在我们的旅程模块也实现一下**。」
|
|||
|
|
*
|
|||
|
|
* ── TripLog 那套是怎么做的(读了它的 `templates/activities/index.php`)──
|
|||
|
|
* · 用**高德 JS API**(`AMap.Map` + `AMap.Marker`);
|
|||
|
|
* · 每个活动一枚标记;标记的 `content` 是自绘的"小卡片"(封面图 + 标题 + 地点),
|
|||
|
|
* 同城/邻近的卡片会**环形扇开**+画引线,避免叠在一起;
|
|||
|
|
* · `map.setFitView()` 自动框住所有点,但**上限 11 级**(不然只有一趟时会被
|
|||
|
|
* 一路放大到街道级,那是导航视角不是"足迹"视角)。
|
|||
|
|
*
|
|||
|
|
* ── 本仓怎么落地(同一套思路,但数据源更规整)──
|
|||
|
|
* · 坐标来源:`Trip::attachSpots()` —— 旅程下所有节点的 from/to 坐标**取重心**;
|
|||
|
|
* 没有坐标就退到城市(内置离线城市表,**不发网络请求**,见那里的说明)。
|
|||
|
|
* · 每趟旅程一枚标记,点它进 `trips/show`。
|
|||
|
|
* · 卡片只放"标题 + 时间 + 城市",不放封面图 —— 本仓列表已经是图片卡片,
|
|||
|
|
* 地图上再来一层图片会喧宾夺主(地图的作用是"看空间分布")。
|
|||
|
|
* · 视野上限同样 11 级、贴合全部标记。
|
|||
|
|
*
|
|||
|
|
* ⚠️ **合规**:地图用高德(腾讯/高德/百度/天地图是合规白名单内),
|
|||
|
|
* 绝不用 Google/OSM 等境外瓦片。key 走本仓既有配置(`App\Geo::jsConfig()`),
|
|||
|
|
* 由 `layout.php` 的 `fb-amap` 按需加载 —— 本页不自己拼 SDK 地址。
|
|||
|
|
* ⚠️ 容器必须有**固定高度**(这里是 `.trip-map` 的 CSS 高度):
|
|||
|
|
* 高德地图在"高度为 0 的容器"里渲染出来是空白,这是最常见的坑。
|
|||
|
|
* ⚠️ 没有坐标的旅程**不画**(数据里说了 `trip_spot=false`);
|
|||
|
|
* 若**一个点都没有**,不渲染地图容器,直接给一句说明(免得用户对着白框发呆)。
|
|||
|
|
*
|
|||
|
|
* 变量:$rows(Trip::all + attachDerived + attachSpots 之后)、$total
|
|||
|
|
*/
|
|||
|
|
$mapPoints = [];
|
|||
|
|
foreach ((array)($rows ?? []) as $row) {
|
|||
|
|
if (empty($row['trip_spot'])) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
$mapPoints[] = [
|
|||
|
|
'id' => (int)$row['id'],
|
|||
|
|
'title' => (string)$row['title'],
|
|||
|
|
'lng' => (float)$row['trip_lng'],
|
|||
|
|
'lat' => (float)$row['trip_lat'],
|
|||
|
|
'when' => \App\Trip::activitySpan($row['starts_at'] ?? null, $row['ends_at'] ?? null),
|
|||
|
|
'city' => (string)($row['city'] ?? ''),
|
|||
|
|
'url' => url('trips/show', ['id' => (int)$row['id']]),
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
?>
|
|||
|
|
<?php if (!$mapPoints): ?>
|
|||
|
|
<?php /* 一个坐标都没有 —— 如实说清楚"为什么没有",而不是给个空地图。
|
|||
|
|
常见原因:行程里没填出发/到达地,或填了但(当时没配高德)没解析出坐标。 */ ?>
|
|||
|
|
<div class="card card-pad empty" id="tripMapEmpty">
|
|||
|
|
<b>还没有能在地图上显示的旅程</b>
|
|||
|
|
地图要靠行程里的**出发地 / 到达地**(有坐标或能认出城市)。
|
|||
|
|
去某趟旅程里加一段行程、把出发到达填上,它就会出现在这里。
|
|||
|
|
</div>
|
|||
|
|
<?php else: ?>
|
|||
|
|
<?php /* 🔴 高度写在内联 style 上不够稳(有的主题会覆盖),
|
|||
|
|
所以主要靠 `.trip-map` 的 CSS;这里只在**无 JS** 时兜一个提示。 */ ?>
|
|||
|
|
<div class="trip-map-wrap">
|
|||
|
|
<div class="trip-map" id="tripMapCanvas"
|
|||
|
|
data-points="<?= e(json_encode($mapPoints, JSON_UNESCAPED_UNICODE | JSON_HEX_APOS | JSON_HEX_QUOT)) ?>">
|
|||
|
|
<noscript><p class="trip-map-fallback">地图需要 JavaScript;用左侧的「列表」看旅程。</p></noscript>
|
|||
|
|
</div>
|
|||
|
|
<?php if (count($mapPoints) < (int)($total ?? 0)): ?>
|
|||
|
|
<?php /* 有旅程不在图上 —— 说清楚,免得用户以为"少了几趟"。 */ ?>
|
|||
|
|
<p class="small muted trip-map-hint">
|
|||
|
|
有 <?= (int)($total ?? 0) - count($mapPoints) ?> 趟旅程没有可用位置(行程里没填出发/到达,或认不出城市),
|
|||
|
|
没有画在地图上 —— 它们在「列表」里照常显示。
|
|||
|
|
</p>
|
|||
|
|
<?php endif; ?>
|
|||
|
|
</div>
|
|||
|
|
<?php endif; ?>
|