|
|
@@ -0,0 +1,262 @@
|
|
|
+// 阶段图/相位图 icon 组合示例数据(演示/调试用)
|
|
|
+// 覆盖 1-3 个 icon 的各种组合 + 边界情况,验证 PhaseDiagram / SignalTimingChart
|
|
|
+// 在不同 icon 数量下的渲染。
|
|
|
+//
|
|
|
+// === 12 个合法 token(按驶入方向分 4 组,每组 3 种动作)===
|
|
|
+//
|
|
|
+// 直行 左转 左转带掉头
|
|
|
+// 上方驶入 (LT 锚) STRAIGHT_DOWN TURN_DOWN_LEFT TURN_DOWN_LEFT_UTURN
|
|
|
+// 下方驶入 (RB 锚) STRAIGHT_UP TURN_UP_LEFT TURN_UP_LEFT_UTURN
|
|
|
+// 右侧驶入 (RT 锚) STRAIGHT_LEFT TURN_LEFT_DOWN TURN_LEFT_DOWN_UTURN
|
|
|
+// 左侧驶入 (LB 锚) STRAIGHT_RIGHT TURN_RIGHT_UP TURN_RIGHT_UP_UTURN
|
|
|
+//
|
|
|
+// 每个 token 锚定到 30×30 单位路口方块的某个角落;同组 3 个 token 共用同一角落,
|
|
|
+// 放在同一阶段会重叠(视觉只见最后那一个)。所以一阶段独立角落上限 = 4。
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 一、stageList 示例 —— 喂给 PhaseDiagram(路口方块组件)
|
|
|
+// ============================================================
|
|
|
+//
|
|
|
+// 字段:
|
|
|
+// value 阶段编号字符串("1"/"2"/...)
|
|
|
+// phaseName 显示名("P1"/"P2"/...)
|
|
|
+// time 阶段总时长(秒)
|
|
|
+// direction 主放行方向('ns' 南北 / 'ew' 东西)
|
|
|
+// icons NEW: 路口方块上要渲染的 token 数组(0-4 个有效)
|
|
|
+// img 旧字段,PhaseDiagram 不渲染时由 <img> fallback
|
|
|
+// _note 仅本演示用,业务字段无此项
|
|
|
+
|
|
|
+// 约束:每阶段 icons 只来自单一方向:
|
|
|
+// NS 方向:仅 LT (上方驶入) + RB (下方驶入)
|
|
|
+// EW 方向:仅 RT (右侧驶入) + LB (左侧驶入)
|
|
|
+//
|
|
|
+// 12 阶段:南北双向 6 个 + 东西双向 6 个
|
|
|
+// 每阶段 25 秒,总周期 300 秒
|
|
|
+// 排序规则:corner 内 icon 渲染顺序固定为 右转 → 直行 → 左转(数据数组顺序不影响)
|
|
|
+export const SAMPLE_STAGE_LIST = [
|
|
|
+ // ============= 南北双向(6 阶段)=============
|
|
|
+ // P1-P3:每方向 1 icon,单动作双向
|
|
|
+ {
|
|
|
+ value: '1', phaseName: 'P1', time: 25, direction: 'ns',
|
|
|
+ icons: ['STRAIGHT_DOWN', 'STRAIGHT_UP'],
|
|
|
+ _note: '【南北直行】北直 + 南直'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '2', phaseName: 'P2', time: 25, direction: 'ns',
|
|
|
+ icons: ['TURN_DOWN_LEFT', 'TURN_UP_LEFT'],
|
|
|
+ _note: '【南北左转】北左 + 南左'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '3', phaseName: 'P3', time: 25, direction: 'ns',
|
|
|
+ icons: ['TURN_DOWN_RIGHT', 'TURN_UP_RIGHT'],
|
|
|
+ _note: '【南北右转】北右 + 南右'
|
|
|
+ },
|
|
|
+
|
|
|
+ // P4-P6:每方向 3 icon (直/左/右) 双向 = 共 6 icon
|
|
|
+ {
|
|
|
+ value: '4', phaseName: 'P4', time: 25, direction: 'ns',
|
|
|
+ icons: ['STRAIGHT_DOWN', 'TURN_DOWN_LEFT', 'TURN_DOWN_RIGHT',
|
|
|
+ 'STRAIGHT_UP', 'TURN_UP_LEFT', 'TURN_UP_RIGHT'],
|
|
|
+ _note: '【南北全放行】北直左右 + 南直左右(6 icon)'
|
|
|
+ },
|
|
|
+ // P5-P6:非对称(一方 1 icon,另一方 3 icon)
|
|
|
+ {
|
|
|
+ value: '5', phaseName: 'P5', time: 25, direction: 'ns',
|
|
|
+ icons: ['STRAIGHT_DOWN',
|
|
|
+ 'STRAIGHT_UP', 'TURN_UP_LEFT', 'TURN_UP_RIGHT'],
|
|
|
+ _note: '【非对称】北直 + 南直左右'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '6', phaseName: 'P6', time: 25, direction: 'ns',
|
|
|
+ icons: ['STRAIGHT_DOWN', 'TURN_DOWN_LEFT', 'TURN_DOWN_RIGHT',
|
|
|
+ 'STRAIGHT_UP'],
|
|
|
+ _note: '【非对称】北直左右 + 南直'
|
|
|
+ },
|
|
|
+
|
|
|
+ // ============= 东西双向(6 阶段)=============
|
|
|
+ {
|
|
|
+ value: '7', phaseName: 'P7', time: 25, direction: 'ew',
|
|
|
+ icons: ['STRAIGHT_LEFT', 'STRAIGHT_RIGHT'],
|
|
|
+ _note: '【东西直行】东直 + 西直'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '8', phaseName: 'P8', time: 25, direction: 'ew',
|
|
|
+ icons: ['TURN_LEFT_DOWN', 'TURN_RIGHT_UP'],
|
|
|
+ _note: '【东西左转】东左 + 西左'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '9', phaseName: 'P9', time: 25, direction: 'ew',
|
|
|
+ icons: ['TURN_LEFT_UP', 'TURN_RIGHT_DOWN'],
|
|
|
+ _note: '【东西右转】东右 + 西右'
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ value: '10', phaseName: 'P10', time: 25, direction: 'ew',
|
|
|
+ icons: ['STRAIGHT_LEFT', 'TURN_LEFT_DOWN', 'TURN_LEFT_UP',
|
|
|
+ 'STRAIGHT_RIGHT', 'TURN_RIGHT_UP', 'TURN_RIGHT_DOWN'],
|
|
|
+ _note: '【东西全放行】东直左右 + 西直左右(6 icon)'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '11', phaseName: 'P11', time: 25, direction: 'ew',
|
|
|
+ icons: ['STRAIGHT_LEFT',
|
|
|
+ 'STRAIGHT_RIGHT', 'TURN_RIGHT_UP', 'TURN_RIGHT_DOWN'],
|
|
|
+ _note: '【非对称】东直 + 西直左右'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: '12', phaseName: 'P12', time: 25, direction: 'ew',
|
|
|
+ icons: ['STRAIGHT_LEFT', 'TURN_LEFT_DOWN', 'TURN_LEFT_UP',
|
|
|
+ 'STRAIGHT_RIGHT'],
|
|
|
+ _note: '【非对称】东直左右 + 西直'
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 二、phaseData 示例 —— 喂给 SignalTimingChart(时间条带)
|
|
|
+// ============================================================
|
|
|
+//
|
|
|
+// 9 元组结构(一行 = 一段连续色块):
|
|
|
+// [trackIdx, startTime, endTime, phaseName, duration, colorType, iconStr, direction, stageTotal]
|
|
|
+// 0 1 2 3 4 5 6 7 8
|
|
|
+//
|
|
|
+// iconStr (列 [6]):
|
|
|
+// · 仅 colorType='green' 段才会画 icon,其它段(stripe/yellow/red)传 null
|
|
|
+// · 接受三种形式:
|
|
|
+// 字符串逗号串 'STRAIGHT_DOWN,STRAIGHT_UP' (mock 当前用法)
|
|
|
+// 数组 ['STRAIGHT_DOWN','STRAIGHT_UP']
|
|
|
+// 单值 'STRAIGHT_UP'
|
|
|
+//
|
|
|
+// 下面这份示例:周期 100s,4 个阶段,icon 数 1/2/3/2 各异
|
|
|
+
|
|
|
+export const SAMPLE_PHASE_DATA = [
|
|
|
+ // 阶段 1(绿 20 / 闪 3 / 黄 3 / 红 2 = 28s),icon × 1
|
|
|
+ [0, 0, 20, 'P1', 20, 'green', 'STRAIGHT_UP', 'ns', 28],
|
|
|
+ [0, 20, 23, '', 3, 'stripe', null, 'ns'],
|
|
|
+ [0, 23, 26, '', 3, 'yellow', null, 'ns'],
|
|
|
+ [0, 26, 28, '', 2, 'red', null, 'ns'],
|
|
|
+
|
|
|
+ // 阶段 2(绿 22 / 闪 3 / 黄 3 / 红 2 = 30s),icon × 2(对称)
|
|
|
+ [0, 28, 50, 'P2', 22, 'green', 'STRAIGHT_DOWN,STRAIGHT_UP', 'ns', 30],
|
|
|
+ [0, 50, 53, '', 3, 'stripe', null, 'ns'],
|
|
|
+ [0, 53, 56, '', 3, 'yellow', null, 'ns'],
|
|
|
+ [0, 56, 58, '', 2, 'red', null, 'ns'],
|
|
|
+
|
|
|
+ // 阶段 3(绿 18 / 闪 3 / 黄 3 / 红 2 = 26s),icon × 3
|
|
|
+ [0, 58, 76, 'P3', 18, 'green', ['STRAIGHT_LEFT','STRAIGHT_RIGHT','TURN_UP_LEFT_UTURN'], 'ew', 26],
|
|
|
+ [0, 76, 79, '', 3, 'stripe', null, 'ew'],
|
|
|
+ [0, 79, 82, '', 3, 'yellow', null, 'ew'],
|
|
|
+ [0, 82, 84, '', 2, 'red', null, 'ew'],
|
|
|
+
|
|
|
+ // 阶段 4(绿 8 / 闪 3 / 黄 3 / 红 2 = 16s),icon × 2(非对称,含掉头)
|
|
|
+ [0, 84, 92, 'P4', 8, 'green', 'TURN_LEFT_DOWN_UTURN,STRAIGHT_DOWN', 'ew', 16],
|
|
|
+ [0, 92, 95, '', 3, 'stripe', null, 'ew'],
|
|
|
+ [0, 95, 98, '', 3, 'yellow', null, 'ew'],
|
|
|
+ [0, 98, 100, '', 2, 'red', null, 'ew'],
|
|
|
+];
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 三、SignalTimingChart 的 hasL/hasR 提示
|
|
|
+// ============================================================
|
|
|
+//
|
|
|
+// 相位图深绿色背景的宽度按 icon 角落分布动态变化(见 SignalTimingChart:528-531):
|
|
|
+// - icons 同时含 L 锚 (LT/LB) 和 R 锚 (RT/RB) → darkWidth ≈ 46px
|
|
|
+// - icons 只含 L 或只含 R 一侧 → darkWidth ≈ 28px
|
|
|
+// - icons 为空但有 phaseName → darkWidth ≈ 8px(仅放文字)
|
|
|
+// - 全空 → darkWidth = 0
|
|
|
+//
|
|
|
+// 上面 SAMPLE_PHASE_DATA 的 4 个阶段恰好覆盖:
|
|
|
+// P1 icon×1 (RB) → 只 R → 28px
|
|
|
+// P2 icon×2 (LT+RB) → L+R → 46px
|
|
|
+// P3 icon×3 (RT+LB+RB) → L+R → 46px
|
|
|
+// P4 icon×2 (RT+LT) → L+R → 46px
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 四、Random 组合生成器(后续接入 mock 时可直接 reuse)
|
|
|
+// ============================================================
|
|
|
+//
|
|
|
+// 按"4 个角落各最多 1 个 token"的规则随机抽 1-3 个 icon。
|
|
|
+// 同角落 3 个 token 等价,随机选一个动作。
|
|
|
+
|
|
|
+const TOKENS_BY_CORNER = {
|
|
|
+ LT: ['STRAIGHT_DOWN', 'TURN_DOWN_LEFT', 'TURN_DOWN_LEFT_UTURN'],
|
|
|
+ RB: ['STRAIGHT_UP', 'TURN_UP_LEFT', 'TURN_UP_LEFT_UTURN'],
|
|
|
+ RT: ['STRAIGHT_LEFT', 'TURN_LEFT_DOWN', 'TURN_LEFT_DOWN_UTURN'],
|
|
|
+ LB: ['STRAIGHT_RIGHT','TURN_RIGHT_UP', 'TURN_RIGHT_UP_UTURN'],
|
|
|
+};
|
|
|
+
|
|
|
+const CORNERS = Object.keys(TOKENS_BY_CORNER);
|
|
|
+
|
|
|
+function pick(arr) { return arr[Math.floor(Math.random() * arr.length)]; }
|
|
|
+
|
|
|
+/** 随机抽 n 个不同角落各 1 个 token;n 默认 1-3 中随机 */
|
|
|
+export function randomIconCombo(n) {
|
|
|
+ const count = n || (1 + Math.floor(Math.random() * 3)); // 1-3
|
|
|
+ // 随机洗牌角落,取前 count 个
|
|
|
+ const shuffled = CORNERS.slice().sort(() => Math.random() - 0.5);
|
|
|
+ return shuffled.slice(0, count).map(corner => pick(TOKENS_BY_CORNER[corner]));
|
|
|
+}
|
|
|
+
|
|
|
+// 示例:randomIconCombo(2) → ['STRAIGHT_DOWN', 'TURN_LEFT_DOWN'] (LT+RT)
|
|
|
+// randomIconCombo() → ['STRAIGHT_UP'] (n 随机 = 1)
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 五、Demo 路口完整数据构造(用于 apiGetCrossingDetailData 注入)
|
|
|
+// ============================================================
|
|
|
+//
|
|
|
+// 把 SAMPLE_STAGE_LIST 转成 CrossingDetailPanel 直接可用的 stageList +
|
|
|
+// 配套 phaseData + cycleLength。每个阶段:
|
|
|
+// 绿灯 = stageList[i].time - 8 秒
|
|
|
+// stripe(3) + yellow(3) + red(2) = 8 秒固定尾段
|
|
|
+
|
|
|
+const DEMO_TAIL = { stripe: 3, yellow: 3, red: 2 }; // 共 8 秒
|
|
|
+
|
|
|
+const DEMO_LOCKTIME_OPTIONS = [
|
|
|
+ { label: '20', value: 20 }, { label: '30', value: 30 },
|
|
|
+ { label: '45', value: 45 }, { label: '60', value: 60 },
|
|
|
+];
|
|
|
+
|
|
|
+/**
|
|
|
+ * 构造 Icon 组合演示路口的完整数据(喂给 apiGetCrossingDetailData 返回值)
|
|
|
+ * @returns { stageList, phaseData, cycleLength }
|
|
|
+ */
|
|
|
+export function buildIconComboDemoData() {
|
|
|
+ const stageList = [];
|
|
|
+ const phaseData = [];
|
|
|
+ let t = 0;
|
|
|
+ const trackIdx = 0;
|
|
|
+
|
|
|
+ SAMPLE_STAGE_LIST.forEach((item, i) => {
|
|
|
+ const stageTotal = item.time;
|
|
|
+ const g = Math.max(1, stageTotal - DEMO_TAIL.stripe - DEMO_TAIL.yellow - DEMO_TAIL.red);
|
|
|
+ const iconStr = (item.icons || []).join(',');
|
|
|
+ const dir = item.direction || 'ns';
|
|
|
+
|
|
|
+ // 4 段 phaseData:green + stripe + yellow + red
|
|
|
+ phaseData.push([trackIdx, t, t + g, item.phaseName, g, 'green', iconStr, dir, stageTotal]);
|
|
|
+ phaseData.push([trackIdx, t + g, t + g + DEMO_TAIL.stripe, '', DEMO_TAIL.stripe, 'stripe', null, dir]);
|
|
|
+ phaseData.push([trackIdx, t + g + DEMO_TAIL.stripe, t + g + DEMO_TAIL.stripe + DEMO_TAIL.yellow, '', DEMO_TAIL.yellow, 'yellow', null, dir]);
|
|
|
+ phaseData.push([trackIdx, t + g + DEMO_TAIL.stripe + DEMO_TAIL.yellow, t + g + DEMO_TAIL.stripe + DEMO_TAIL.yellow + DEMO_TAIL.red, '', DEMO_TAIL.red, 'red', null, dir]);
|
|
|
+
|
|
|
+ // stageList 项(补 CrossingDetailPanel 需要的字段)
|
|
|
+ stageList.push({
|
|
|
+ value: item.value,
|
|
|
+ phaseName: item.phaseName,
|
|
|
+ time: stageTotal,
|
|
|
+ direction: dir,
|
|
|
+ icons: item.icons, // 新字段:PhaseDiagram 渲染用
|
|
|
+ img: null, // 设为 null 防止 fallback <img> 加载失败 404
|
|
|
+ locktimeOptions: DEMO_LOCKTIME_OPTIONS,
|
|
|
+ _note: item._note,
|
|
|
+ });
|
|
|
+
|
|
|
+ t += stageTotal;
|
|
|
+ });
|
|
|
+
|
|
|
+ return { stageList, phaseData, cycleLength: t };
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ SAMPLE_STAGE_LIST,
|
|
|
+ SAMPLE_PHASE_DATA,
|
|
|
+ randomIconCombo,
|
|
|
+ buildIconComboDemoData,
|
|
|
+};
|