前五卷地图
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,8 @@
|
||||
# gitignore template for Vue.js projects
|
||||
#
|
||||
# Recommended template: Node.gitignore
|
||||
node_modules/
|
||||
.claude/
|
||||
|
||||
# TODO: where does this rule come from?
|
||||
docs/_book
|
||||
|
||||
187
data/vol02.json
Normal file
187
data/vol02.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"volume": "卷二",
|
||||
"chapters": ["第01章 老奸巨猾", "第02章 尔虞我诈", "第03章 误打误撞", "第04章 发财大计", "第05章 东溟夫人", "第06章 利己利人", "第07章 网中之鱼", "第08章 红粉帮主", "第09章 初窥堂奥", "第10章 秘密账簿", "第11章 毒如蛇蝎", "第12章 诈死脱身"],
|
||||
|
||||
"locations": [
|
||||
{ "id": "liyang", "name": "历阳", "type": "city", "lat": 31.7, "lng": 118.37, "description": "杜伏威占据的重镇,江淮军的根据地" },
|
||||
{ "id": "xin_an", "name": "新安郡", "type": "city", "lat": 31.2, "lng": 118.5, "description": "沿长江南岸兴旺大城,寇徐与杜伏威同行处" },
|
||||
{ "id": "danyang", "name": "丹阳", "type": "city", "lat": 32.0, "lng": 118.95, "description": "长江沿岸重镇,宋师道活动地" },
|
||||
{ "id": "long_hai", "name": "陇海", "type": "city", "lat": 31.9, "lng": 118.7, "description": "沿海重镇" },
|
||||
{ "id": "yu_hang", "name": "余杭", "type": "city", "lat": 30.3, "lng": 120.1, "description": "沿海郡县,海沙帮分舵所在地" },
|
||||
{ "id": "sea_beach", "name": "海滩", "type": "landmark", "lat": 29.8, "lng": 121.5, "description": "东溟派船队停泊地,寇徐修炼两月处" },
|
||||
{ "id": "hui_shui", "name": "淮水", "type": "waterway", "lat": 32.1, "lng": 117.0, "description": "贯通南北的重要水道" },
|
||||
{ "id": "lei_gong_gorge", "name": "雷公峡", "type": "landmark", "lat": 32.5, "lng": 116.8, "description": "淮水沿岸险峻峡谷,杜伏威与巨鲲帮对战处" },
|
||||
{ "id": "peng_cheng", "name": "彭城", "type": "city", "lat": 34.4, "lng": 117.1, "description": "东溟夫人单美仙与李渊会面之地" },
|
||||
{ "id": "zhong_yang", "name": "钟阳", "type": "city", "lat": 31.0, "lng": 116.0, "description": "云玉真计划前往地" }
|
||||
],
|
||||
|
||||
"factions": [
|
||||
{
|
||||
"id": "du_fuwei_army",
|
||||
"name": "杜伏威军",
|
||||
"type": "义军",
|
||||
"color": "#FF8C00",
|
||||
"leader": "杜伏威",
|
||||
"territory": ["liyang"],
|
||||
"key_figures": ["杜伏威", "辅公祏"],
|
||||
"description": "江淮义军,占据历阳,攻占新安郡,与寇徐因缘际会相识"
|
||||
},
|
||||
{
|
||||
"id": "hai_sha_bang",
|
||||
"name": "海沙帮",
|
||||
"type": "帮派",
|
||||
"color": "#1E90FF",
|
||||
"leader": "韩盖天",
|
||||
"territory": ["yu_hang"],
|
||||
"key_figures": ["韩盖天", "游秋雁", "尤贵", "凌志高"],
|
||||
"description": "东南沿海三大帮派之一,私盐贸易,依附宇文门阀,龙王韩盖天之名颇著"
|
||||
},
|
||||
{
|
||||
"id": "ju_kun_bang",
|
||||
"name": "巨鲲帮",
|
||||
"type": "帮派",
|
||||
"color": "#FF1493",
|
||||
"leader": "云玉真",
|
||||
"territory": [],
|
||||
"key_figures": ["云玉真", "卜天志", "云芝", "陈老谋"],
|
||||
"description": "东南沿海三大帮派之一,独立自主,红粉帮主云玉真武艺精湛,实为独孤阀幕后势力"
|
||||
},
|
||||
{
|
||||
"id": "shui_long_bang",
|
||||
"name": "水龙帮",
|
||||
"type": "帮派",
|
||||
"color": "#4169E1",
|
||||
"leader": "未提及",
|
||||
"territory": [],
|
||||
"key_figures": [],
|
||||
"description": "东南沿海三大帮派之一,依附南方宋姓门阀"
|
||||
},
|
||||
{
|
||||
"id": "ba_ling_bang",
|
||||
"name": "巴陵帮",
|
||||
"type": "帮派",
|
||||
"color": "#8B0000",
|
||||
"leader": "隋炀帝杨广",
|
||||
"territory": [],
|
||||
"key_figures": [],
|
||||
"description": "以洞庭湖为根据地,专事贩卖妇女,供应妓院,获利最厚,背后乃皇帝"
|
||||
},
|
||||
{
|
||||
"id": "dong_ming_pai",
|
||||
"name": "东溟派",
|
||||
"type": "外族势力",
|
||||
"color": "#00CED1",
|
||||
"leader": "单美仙",
|
||||
"territory": [],
|
||||
"key_figures": ["单美仙", "游秋雁", "东溟夫人"],
|
||||
"description": "来自琉球大海岛,以女性为主,打造优质兵器,每年春分到中土选少男,运营飘香号"
|
||||
},
|
||||
{
|
||||
"id": "du_gu_fa",
|
||||
"name": "独孤阀",
|
||||
"type": "门阀",
|
||||
"color": "#9932CC",
|
||||
"leader": "独孤峰",
|
||||
"territory": [],
|
||||
"key_figures": ["独孤策", "独孤峰", "尤楚红"],
|
||||
"description": "四姓门阀之一,独孤策为阀主独孤峰之子,武功高强,与云玉真勾结"
|
||||
},
|
||||
{
|
||||
"id": "li_fa",
|
||||
"name": "李阀",
|
||||
"type": "门阀",
|
||||
"color": "#DC143C",
|
||||
"leader": "李渊",
|
||||
"territory": [],
|
||||
"key_figures": ["李渊"],
|
||||
"description": "四姓门阀之一,与东溟派有交易往来,购买兵器"
|
||||
},
|
||||
{
|
||||
"id": "yu_wen_fa",
|
||||
"name": "宇文阀",
|
||||
"type": "门阀",
|
||||
"color": "#4169E1",
|
||||
"leader": "宇文伤",
|
||||
"territory": [],
|
||||
"key_figures": ["宇文化及", "宇文伤"],
|
||||
"description": "四姓门阀之一,宇文化及为禁卫总管,命海沙帮追捕寇徐,图谋获取东溟派账簿"
|
||||
}
|
||||
],
|
||||
|
||||
"character_routes": [
|
||||
{
|
||||
"character": "寇仲 & 徐子陵",
|
||||
"color": "#FF4500",
|
||||
"route": [
|
||||
{ "location": "liyang", "chapter": 1, "event": "逃出杜伏威追捕,被挟到新安郡" },
|
||||
{ "location": "xin_an", "chapter": 2, "event": "到新安郡酒楼,遇沈乃堂和梁舜明,杜伏威动武" },
|
||||
{ "location": "xin_an", "chapter": 3, "event": "逃入飘香院躲避杜伏威追捕" },
|
||||
{ "lat": 30.5, "lng": 120.0, "chapter": 5, "event": "在海上从东溟派大船跳入水中,首次学会水底闭气" },
|
||||
{ "location": "yu_hang", "chapter": 5, "event": "登陆余杭城,遇老刘和谭勇,得知东溟派信息" },
|
||||
{ "lat": 30.2, "lng": 120.3, "chapter": 6, "event": "被海沙帮追捕后逃脱" },
|
||||
{ "lat": 29.8, "lng": 121.5, "chapter": 7, "event": "与偷盐船被海沙帮追获,被困铁笼,成功逃脱" },
|
||||
{ "location": "sea_beach", "chapter": 8, "event": "船只触礁沉没,损失盐包,遇云玉真" },
|
||||
{ "location": "sea_beach", "chapter": 9, "event": "海滩修炼两月,观海鸥悟道,获得天人合一之境" },
|
||||
{ "location": "sea_beach", "chapter": 10, "event": "尝试跳崖修炼轻功,成功突破" },
|
||||
{ "location": "sea_beach", "chapter": 11, "event": "被纳入云玉真巨鲲帮,船上修为大进" },
|
||||
{ "lat": 32.5, "lng": 116.8, "chapter": 12, "event": "淮水激战,杜伏威对独孤策,危崖绝境" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "杜伏威",
|
||||
"color": "#FF8C00",
|
||||
"route": [
|
||||
{ "location": "liyang", "chapter": 1, "event": "在镇外路上擒拿寇徐二人,强行索取关帝庙秘密" },
|
||||
{ "location": "xin_an", "chapter": 2, "event": "在新安郡酒楼与沈乃堂、梁舜明对战" },
|
||||
{ "location": "xin_an", "chapter": 3, "event": "追捕逃离的寇徐" },
|
||||
{ "lat": 32.5, "lng": 116.8, "chapter": 12, "event": "追击云玉真等人至雷公峡,与独孤策对战十招" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "云玉真",
|
||||
"color": "#FF1493",
|
||||
"route": [
|
||||
{ "location": "sea_beach", "chapter": 8, "event": "沙滩出现,与寇徐交手,提议拜师" },
|
||||
{ "location": "sea_beach", "chapter": 9, "event": "三次到沙滩传授鸟渡术轻功心法" },
|
||||
{ "lat": 32.0, "lng": 119.5, "chapter": 10, "event": "约定接寇徐上船进行任务" },
|
||||
{ "location": "yu_hang", "chapter": 11, "event": "接寇徐上巨鲲帮战船,传授偷盗技艺,与独孤策密会" },
|
||||
{ "lat": 32.1, "lng": 117.0, "chapter": 12, "event": "淮水行进中遭遇杜伏威,逃离至雷公峡绝崖" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "韩盖天",
|
||||
"color": "#1E90FF",
|
||||
"route": [
|
||||
{ "lat": 30.0, "lng": 120.5, "chapter": 7, "event": "海上追获偷盐船,俘获寇徐" },
|
||||
{ "location": "yu_hang", "chapter": 7, "event": "船队审问寇徐,获悉杨公宝藏信息" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "东溟派",
|
||||
"color": "#00CED1",
|
||||
"route": [
|
||||
{ "lat": 30.5, "lng": 120.0, "chapter": 5, "event": "飘香号船队在海上与海沙帮交战,寇徐从船上跳海逃脱" },
|
||||
{ "location": "yu_hang", "chapter": 5, "event": "东溟派在余杭招募选婿" },
|
||||
{ "location": "peng_cheng", "chapter": 11, "event": "东溟夫人单美仙七天后赴彭城会李渊,为偷账簿的机会窗口" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"key_events": [
|
||||
{ "chapter": 1, "location": "liyang", "event": "杜伏威在官道上追获逃离的寇徐,威胁要杀人灭口" },
|
||||
{ "chapter": 1, "location": "xin_an", "event": "寇徐被杜伏威挟到新安郡,众人在酒楼进餐" },
|
||||
{ "chapter": 2, "location": "xin_an", "event": "杜伏威与沈乃堂、梁舜明交手,展示袖里乾坤武功" },
|
||||
{ "chapter": 3, "event": "寇徐逃入飘香院躲避杜伏威,遇沈无双踩踏" },
|
||||
{ "chapter": 5, "event": "寇徐首次登上东溟派飘香号,遇单美仙但被逐下船", "lat": 30.5, "lng": 120.0 },
|
||||
{ "chapter": 5, "event": "寇徐从飘香号跳海,在水底首次领悟内息呼吸之妙" },
|
||||
{ "chapter": 6, "event": "寇徐进城遇海沙帮人员,得知盐仓位置和东溟派信息" },
|
||||
{ "chapter": 7, "event": "海沙帮五船追获寇徐与偷盐船,韩盖天审问与威胁" },
|
||||
{ "chapter": 7, "event": "寇徐在船底挖洞脱逃,偷盐船与海沙帮分开,触礁沉没", "lat": 30.0, "lng": 121.0 },
|
||||
{ "chapter": 8, "event": "徐子陵遇海鸥受启发,与寇仲一击打散其剑,首次成功使用奇功" },
|
||||
{ "chapter": 9, "event": "两人从高崖跳下,在生死关头突破轻功,掌握反劲之道" },
|
||||
{ "chapter": 10, "event": "寇徐试图在海底修炼,后来通过观察鱼儿与螃蟹修行渐悟奥妙" },
|
||||
{ "chapter": 11, "event": "云玉真与独孤策在船舱密会,寇徐无意中听闻被杀人灭口计划" },
|
||||
{ "chapter": 11, "event": "寇徐得知云玉真真实身份与陷害,计划诈死脱身" },
|
||||
{ "chapter": 12, "location": "lei_gong_gorge", "event": "杜伏威追至雷公峡,与独孤策约定十招对决,寇徐危崖绝处" }
|
||||
]
|
||||
}
|
||||
166
data/vol03.json
Normal file
166
data/vol03.json
Normal file
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"volume": "卷三",
|
||||
"chapters": ["第01章 生灵涂炭", "第02章 阴谋诡计", "第03章 美女赌约", "第04章 中计被擒", "第05章 一单交易", "第06章 绝地逃生", "第07章 嫖赌合一", "第08章 赌场风云", "第09章 东溟公主", "第10章 微湖战火"],
|
||||
|
||||
"locations": [
|
||||
{ "id": "pengcheng", "name": "彭城", "aliases": ["徐州"], "type": "city", "lat": 34.28, "lng": 117.57, "description": "卷三主要活动地点,战略要地,隋朝重镇" },
|
||||
{ "id": "shuishui", "name": "泗水", "aliases": ["泗河"], "type": "waterway", "lat": 34.5, "lng": 117.0, "description": "贯通中原的重要水道,寇徐二人逃生路线" },
|
||||
{ "id": "lvliang_mountain", "name": "吕梁山", "type": "landmark", "lat": 34.8, "lng": 117.3, "description": "彭城附近的山脉,秦叔宝念想所在" },
|
||||
{ "id": "piaoxi_number", "name": "飘香号", "aliases": ["飘香船"], "type": "landmark", "lat": 32.5, "lng": 119.0, "description": "东溟夫人的商船,海沙帮欲攻打之地,李世民船队所在" },
|
||||
{ "id": "luo_yang", "name": "洛阳", "aliases": ["东都"], "type": "city", "lat": 34.62, "lng": 112.45, "description": "李世民船队出发地" },
|
||||
{ "id": "xingyang", "name": "荥阳", "type": "city", "lat": 34.79, "lng": 113.38, "description": "瓦岗军翟让根据地,寇徐欲寻素素处" },
|
||||
{ "id": "taiyang", "name": "太原", "type": "city", "lat": 37.87, "lng": 112.55, "description": "李渊驻地,李世民活动范围" },
|
||||
{ "id": "fuchun", "name": "扶春", "type": "town", "lat": 34.5, "lng": 115.0, "description": "沈落雁防守之地,秦叔宝与隋将张须陀的战场" },
|
||||
{ "id": "ghost_stone_gorge", "name": "鬼石峡", "type": "landmark", "lat": 34.2, "lng": 117.3, "description": "泗水险滩,寇徐与渔夫失船处" },
|
||||
{ "id": "qinglong_beach", "name": "青龙滩", "type": "landmark", "lat": 34.15, "lng": 117.25, "description": "泗水上打鱼地点" },
|
||||
{ "id": "hunan", "name": "湖南", "type": "region", "lat": 27.0, "lng": 112.0, "description": "飘香号来往路线区域" }
|
||||
],
|
||||
|
||||
"factions": [
|
||||
{
|
||||
"id": "sui",
|
||||
"name": "隋朝",
|
||||
"type": "朝廷",
|
||||
"color": "#FFD700",
|
||||
"leader": "杨广(隋炀帝)",
|
||||
"territory": ["pengcheng", "luo_yang"],
|
||||
"key_figures": ["杨广", "秦叔宝", "张须陀"],
|
||||
"description": "杨广统治下衰亡中的隋朝,诸将各有心思"
|
||||
},
|
||||
{
|
||||
"id": "wagang_army",
|
||||
"name": "瓦岗军",
|
||||
"type": "义军",
|
||||
"color": "#FF6347",
|
||||
"leader": "翟让/李密",
|
||||
"territory": ["xingyang"],
|
||||
"key_figures": ["翟让", "李密", "沈落雁", "祖君彦"],
|
||||
"description": "天下最大义军势力,李密智计过人,沈落雁为俏军师"
|
||||
},
|
||||
{
|
||||
"id": "du_fuwei",
|
||||
"name": "杜伏威军",
|
||||
"type": "义军",
|
||||
"color": "#FF8C00",
|
||||
"leader": "杜伏威",
|
||||
"territory": ["pengcheng"],
|
||||
"key_figures": ["杜伏威"],
|
||||
"description": "江淮义军首领,内功深厚,掌控彭城地区,与寇徐二人有师徒渊源"
|
||||
},
|
||||
{
|
||||
"id": "li_clan",
|
||||
"name": "李阀",
|
||||
"type": "门阀",
|
||||
"color": "#DC143C",
|
||||
"leader": "李渊",
|
||||
"territory": ["taiyang"],
|
||||
"key_figures": ["李渊", "李世民", "李秀宁"],
|
||||
"description": "四姓门阀之一,暗中购买兵器,李世民智计过人,与寇徐二人有交易"
|
||||
},
|
||||
{
|
||||
"id": "dongming_pai",
|
||||
"name": "东溟派",
|
||||
"type": "江湖势力",
|
||||
"color": "#20B2AA",
|
||||
"leader": "东溟夫人(单美仙)",
|
||||
"territory": ["piaoxi_number"],
|
||||
"key_figures": ["东溟夫人", "单秀", "单玉蝶", "云玉真"],
|
||||
"description": "琉球兵器贸易大户,掌控天下兵器供应,护法仙子武力超群"
|
||||
},
|
||||
{
|
||||
"id": "pengliang_gang",
|
||||
"name": "彭梁会",
|
||||
"type": "黑道帮会",
|
||||
"color": "#8B008B",
|
||||
"leader": "任媚媚/香贵",
|
||||
"territory": ["pengcheng"],
|
||||
"key_figures": ["任媚媚", "香贵", "香玉山"],
|
||||
"description": "彭城重要黑帮,专事人口贩卖,与皇帝勾结"
|
||||
},
|
||||
{
|
||||
"id": "turks",
|
||||
"name": "突厥",
|
||||
"type": "外族",
|
||||
"color": "#2F4F4F",
|
||||
"leader": "始毕可汗",
|
||||
"territory": [],
|
||||
"key_figures": ["颜里回", "慕铁雄"],
|
||||
"description": "北方外患,与宇文阀勾结暗害翟让"
|
||||
}
|
||||
],
|
||||
|
||||
"character_routes": [
|
||||
{
|
||||
"character": "寇仲 & 徐子陵",
|
||||
"color": "#FF4500",
|
||||
"route": [
|
||||
{ "lat": 32.8, "lng": 116.5, "chapter": 12, "event": "离开翠山镇,北上赶往彭城" },
|
||||
{ "lat": 33.5, "lng": 117.0, "chapter": 12, "event": "遇见战场生灵涂炭之象,斩杀隋兵" },
|
||||
{ "lat": 34.0, "lng": 117.2, "chapter": 12, "event": "参与大战,与沈落雁初识" },
|
||||
{ "location": "pengcheng", "chapter": 13, "event": "到达彭城,遇秦叔宝" },
|
||||
{ "location": "shuishui", "chapter": 13, "event": "河边约定与沈落雁赌赛" },
|
||||
{ "lat": 34.2, "lng": 117.3, "chapter": 13, "event": "乘船逆流,遇莫成老渔夫,潜水脱险" },
|
||||
{ "lat": 34.3, "lng": 117.4, "chapter": 14, "event": "乘船逃脱被发现,躲入水底" },
|
||||
{ "location": "pengcheng", "chapter": 14, "event": "返回彭城,入住旅馆" },
|
||||
{ "location": "pengcheng", "chapter": 14, "event": "与沈落雁交手,冲破包围逃脱" },
|
||||
{ "location": "pengcheng", "chapter": 15, "event": "入翠碧楼,遭沈落雁暗杀队伏击" },
|
||||
{ "location": "pengcheng", "chapter": 16, "event": "赌场与杜伏威对峙,东溟派援救" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "沈落雁",
|
||||
"color": "#FF1493",
|
||||
"route": [
|
||||
{ "location": "shuishui", "chapter": 13, "event": "船上生擒秦叔宝,与寇徐定赌约" },
|
||||
{ "lat": 34.2, "lng": 117.3, "chapter": 13, "event": "追捕过程中,投放追踪粉末" },
|
||||
{ "location": "pengcheng", "chapter": 14, "event": "追至彭城,多次围捕寇徐" },
|
||||
{ "lat": 34.5, "lng": 117.5, "chapter": 14, "event": "房间内与寇徐交手,闯关失败" },
|
||||
{ "location": "pengcheng", "chapter": 15, "event": "警告寇徐不要去青楼" },
|
||||
{ "location": "pengcheng", "chapter": 16, "event": "赌场制止任媚媚,对阵杜伏威与东溟派" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "秦叔宝",
|
||||
"color": "#FFB6C1",
|
||||
"route": [
|
||||
{ "location": "shuishui", "chapter": 13, "event": "河边遇寇仲徐子陵,被沈落雁生擒" },
|
||||
{ "location": "pengcheng", "chapter": 13, "event": "到达彭城,参与赌赛" },
|
||||
{ "location": "pengcheng", "chapter": 14, "event": "与寇徐分头逃走,最终被沈落雁所擒" },
|
||||
{ "location": "pengcheng", "chapter": 16, "event": "已归降瓦岗军,与沈落雁配合" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "李世民",
|
||||
"color": "#4169E1",
|
||||
"route": [
|
||||
{ "location": "luo_yang", "chapter": 14, "event": "与李渊船队从洛阳出发" },
|
||||
{ "location": "shuishui", "chapter": 14, "event": "船上与寇徐相识,达成合作协议" },
|
||||
{ "location": "pengcheng", "chapter": 14, "event": "船队到达彭城,继续谈判" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "杜伏威",
|
||||
"color": "#FF8C00",
|
||||
"route": [
|
||||
{ "location": "pengcheng", "chapter": 16, "event": "在赌场突然出现,力压群雄" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"key_events": [
|
||||
{ "chapter": 12, "event": "寇徐二人目睹隋军暴行,开始习武对敌", "lat": 33.5, "lng": 117.0 },
|
||||
{ "chapter": 12, "event": "寇徐参与战场,遇见沈落雁率领的青衣武士", "lat": 33.8, "lng": 117.2 },
|
||||
{ "chapter": 13, "location": "pengcheng", "event": "秦叔宝、寇徐遇沈落雁于泗水,定下赌约" },
|
||||
{ "chapter": 13, "event": "寇徐二人身上被沾追踪粉末,识破鸟儿追踪之法", "lat": 34.0, "lng": 117.2 },
|
||||
{ "chapter": 13, "event": "渔夫莫成布局,寇徐潜水脱险,乘大船逃脱", "lat": 34.15, "lng": 117.25 },
|
||||
{ "chapter": 14, "event": "莫成等人为李阀来客所阻,意识到形势变化", "lat": 34.15, "lng": 117.2 },
|
||||
{ "chapter": 14, "event": "李世民在船上与寇徐相识,得知东溟夫人账簿秘密", "location": "shuishui" },
|
||||
{ "chapter": 14, "event": "寇徐进城赴约,提防沈落雁陷阱", "location": "pengcheng" },
|
||||
{ "chapter": 14, "event": "寇徐在旅馆遭沈落雁暴力追杀,破壁逃脱", "location": "pengcheng" },
|
||||
{ "chapter": 15, "event": "寇徐计划攀城逃脱,购取钩子与绳索", "location": "pengcheng" },
|
||||
{ "chapter": 15, "event": "入翠碧楼,遇香玉山与任媚媚,被施展媚术", "location": "pengcheng" },
|
||||
{ "chapter": 16, "event": "赌场与任媚媚对赌,沈落雁突然现身", "location": "pengcheng" },
|
||||
{ "chapter": 16, "event": "杜伏威突现赌场,压倒众人,欲带寇徐回家", "location": "pengcheng" },
|
||||
{ "chapter": 16, "event": "东溟派护法单秀、单玉蝶现身,与杜伏威对峙", "location": "pengcheng" }
|
||||
]
|
||||
}
|
||||
186
data/vol04.json
Normal file
186
data/vol04.json
Normal file
@@ -0,0 +1,186 @@
|
||||
{
|
||||
"volume": "卷四",
|
||||
"chapters": [
|
||||
"第01章 志比天高",
|
||||
"第02章 井边悟道",
|
||||
"第03章 彗星北来",
|
||||
"第04章 奇女青璇",
|
||||
"第05章 宇文无敌",
|
||||
"第06章 重会素素",
|
||||
"第07章 避难学艺",
|
||||
"第08章 笼中之鸟",
|
||||
"第09章 衷诚合作",
|
||||
"第10章 以怨报德",
|
||||
"第11章 夜访青楼",
|
||||
"第12章 大祸忽至"
|
||||
],
|
||||
|
||||
"locations": [
|
||||
{ "id": "baiyezeregion", "name": "巨野泽地区", "aliases": ["巨野", "大湖"], "type": "waterway", "lat": 35.0, "lng": 115.3, "description": "鲁西南运河沿线湖泽,寇徐与李世民分手处" },
|
||||
{ "id": "dongpingg郡", "name": "东平郡", "aliases": ["东平"], "type": "city", "lat": 35.4, "lng": 115.8, "description": "运河沿线重镇,石青璇初现、跋锋寒约战欧阳希夷处,寇徐短暂隐居处" },
|
||||
{ "id": "xingyang", "name": "荥阳", "aliases": ["荥阳城"], "type": "city", "lat": 34.79, "lng": 113.38, "description": "瓦岗军大龙头翟让根据地,大运河与黄河交汇处,兵家必争之地" },
|
||||
{ "id": "luokou", "name": "洛口", "aliases": ["兴洛仓", "洛口仓"], "type": "landmark", "lat": 34.5, "lng": 113.1, "description": "大运河与黄河交汇处,隋朝最大粮仓,李密攻占处" },
|
||||
{ "id": "luoyang", "name": "洛阳", "aliases": ["东都"], "type": "city", "lat": 34.62, "lng": 112.45, "description": "隋朝东都,王世充镇守处" },
|
||||
{ "id": "hujie", "name": "虎牢", "aliases": ["虎牢关"], "type": "landmark", "lat": 34.78, "lng": 112.95, "description": "荥阳西要塞,裴仁基守兵处" },
|
||||
{ "id": "xiangyang_region", "name": "香玉山来处", "type": "landmark", "lat": 31.0, "lng": 116.0, "description": "巴陵帮二当家萧铣活动地区" },
|
||||
{ "id": "leshoucheng", "name": "乐寿", "aliases": ["乐寿城"], "type": "city", "lat": 38.5, "lng": 116.8, "description": "窦建德根据地,河北地区" }
|
||||
],
|
||||
|
||||
"factions": [
|
||||
{
|
||||
"id": "wagang_army",
|
||||
"name": "瓦岗军",
|
||||
"type": "义军",
|
||||
"color": "#FF6347",
|
||||
"leader": "翟让(后由李密取而代之)",
|
||||
"territory": ["xingyang", "luokou"],
|
||||
"key_figures": ["翟让", "李密", "祖君彦", "沈落雁", "王伯当", "徐世绩"],
|
||||
"description": "天下义军之首,翟让为名义大龙头,但李密实权逐渐上升,最终导致内争"
|
||||
},
|
||||
{
|
||||
"id": "li_clan",
|
||||
"name": "李阀",
|
||||
"type": "门阀",
|
||||
"color": "#DC143C",
|
||||
"leader": "李渊",
|
||||
"territory": [],
|
||||
"key_figures": ["李渊", "李世民", "李秀宁"],
|
||||
"description": "四姓门阀之一,李世民招募寇徐,图谋割据"
|
||||
},
|
||||
{
|
||||
"id": "yuwen",
|
||||
"name": "宇文阀",
|
||||
"type": "门阀",
|
||||
"color": "#4169E1",
|
||||
"leader": "宇文伤",
|
||||
"territory": ["daxing"],
|
||||
"key_figures": ["宇文伤", "宇文化及", "宇文无敌", "宇文成都"],
|
||||
"description": "四姓门阀之一,宇文无敌为高手,追捕寇徐账簿"
|
||||
},
|
||||
{
|
||||
"id": "balingang",
|
||||
"name": "巴陵帮",
|
||||
"type": "江湖势力",
|
||||
"color": "#9370DB",
|
||||
"leader": "萧铣(二当家)",
|
||||
"territory": [],
|
||||
"key_figures": ["萧铣", "香玉山", "陆抗"],
|
||||
"description": "八帮次席,经营青楼赌馆庞大网络,与宇文阿针对"
|
||||
},
|
||||
{
|
||||
"id": "dou_jiande",
|
||||
"name": "窦建德军",
|
||||
"type": "义军",
|
||||
"color": "#8B4513",
|
||||
"leader": "窦建德",
|
||||
"territory": ["leshoucheng"],
|
||||
"key_figures": ["窦建德"],
|
||||
"description": "河北黑道霸主,翟让往日命交"
|
||||
},
|
||||
{
|
||||
"id": "dong_ming_pai",
|
||||
"name": "东溟派",
|
||||
"type": "江湖势力",
|
||||
"color": "#FF8C00",
|
||||
"leader": "东溟夫人",
|
||||
"territory": [],
|
||||
"key_figures": ["单婉晶", "尚明", "尚邦", "尚奎义"],
|
||||
"description": "海上势力,贩运兵器,与李阀、宇文阀有贸易往来"
|
||||
},
|
||||
{
|
||||
"id": "sui",
|
||||
"name": "隋朝",
|
||||
"type": "朝廷",
|
||||
"color": "#FFD700",
|
||||
"leader": "杨广(隋炀帝)",
|
||||
"territory": ["luoyang", "yangzhou"],
|
||||
"key_figures": ["杨广", "王世充", "刘长恭", "裴仁基"],
|
||||
"description": "当朝政权,各地义军起义,气数将尽"
|
||||
}
|
||||
],
|
||||
|
||||
"character_routes": [
|
||||
{
|
||||
"character": "寇仲 & 徐子陵",
|
||||
"color": "#FF4500",
|
||||
"route": [
|
||||
{ "location": "baiyezeregion", "chapter": 1, "event": "与李世民分手,寇仲立志争天下" },
|
||||
{ "lat": 35.2, "lng": 115.5, "chapter": 1, "event": "两人在野外露宿,讨论人生理想" },
|
||||
{ "location": "dongpingg郡", "chapter": 2, "event": "抵达东平郡,在酒楼与沈乃堂等遇见" },
|
||||
{ "lat": 35.4, "lng": 115.8, "chapter": 3, "event": "在王府见证跋锋寒与欧阳希夷激战,听石青璇箫音" },
|
||||
{ "location": "dongpingg郡", "chapter": 4, "event": "在王府柴房潜修七天,领悟武道真谛" },
|
||||
{ "lat": 34.9, "lng": 114.5, "chapter": 5, "event": "途中遇宇文无敌,首次恶战获胜,伤敌不伤己" },
|
||||
{ "location": "xingyang", "chapter": 6, "event": "抵达荥阳翟府,重逢素素" },
|
||||
{ "location": "xingyang", "chapter": 7, "event": "在翟府学艺于屠叔方,被翟娇奴役于膳房" },
|
||||
{ "location": "xingyang", "chapter": 8, "event": "与屠叔方交心,获得保护与指导" },
|
||||
{ "location": "xingyang", "chapter": 9, "event": "在街上遇香玉山,洽谈合作协议" },
|
||||
{ "location": "xingyang", "chapter": 10, "event": "见翟让,遭其掌击,进入合作双修阶段" },
|
||||
{ "lat": 34.8, "lng": 113.2, "chapter": 11, "event": "赴黛青院见沈落雁,获悉翟让伪装让位计划" },
|
||||
{ "location": "xingyang", "chapter": 12, "event": "李密发动突变,与素素逃离荥阳" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "翟让",
|
||||
"color": "#FF1493",
|
||||
"route": [
|
||||
{ "location": "xingyang", "chapter": 6, "event": "大胜张须陀,声威如日中天" },
|
||||
{ "location": "xingyang", "chapter": 10, "event": "被李密暗算受重伤,与寇徐二人激战" },
|
||||
{ "location": "xingyang", "chapter": 11, "event": "伪装让位,设计延缓李密动作" },
|
||||
{ "location": "xingyang", "chapter": 12, "event": "与李密决战,为寇徐逃脱争取时间" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "李密",
|
||||
"color": "#8B0000",
|
||||
"route": [
|
||||
{ "location": "luokou", "chapter": 6, "event": "攻占兴洛仓,声望日增,威胁翟让地位" },
|
||||
{ "location": "xingyang", "chapter": 10, "event": "暗算翟让,伤其经脉" },
|
||||
{ "location": "xingyang", "chapter": 12, "event": "率军进攻翟府,发动最终决战" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "沈落雁",
|
||||
"color": "#228B22",
|
||||
"route": [
|
||||
{ "location": "luokou", "chapter": 8, "event": "在洛口战场统军" },
|
||||
{ "location": "xingyang", "chapter": 8, "event": "返回荥阳,对寇徐用刑逼供" },
|
||||
{ "location": "xingyang", "chapter": 11, "event": "在黛青院与寇徐谈心,试探真实意图" },
|
||||
{ "location": "xingyang", "chapter": 12, "event": "配合李密行动,发动突变" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "素素",
|
||||
"color": "#FFB6C1",
|
||||
"route": [
|
||||
{ "location": "xingyang", "chapter": 6, "event": "在翟府与寇徐重逢,充当桥梁人物" },
|
||||
{ "location": "xingyang", "chapter": 7, "event": "被王伯当所辱,心灵创伤" },
|
||||
{ "location": "xingyang", "chapter": 10, "event": "陪伴寇徐,成为三人唯一纽带" },
|
||||
{ "location": "xingyang", "chapter": 12, "event": "与寇徐逃离荥阳,踏上新征途" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "跋锋寒",
|
||||
"color": "#DC143C",
|
||||
"route": [
|
||||
{ "location": "dongpingg郡", "chapter": 4, "event": "初临中原,与欧阳希夷激战,震撼众人" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"key_events": [
|
||||
{ "chapter": 1, "location": "baiyezeregion", "event": "寇仲立志争天下,与李世民和平分手" },
|
||||
{ "chapter": 2, "location": "dongpingg郡", "event": "寇徐在井边悟道,领悟'不波井水'心法精髓" },
|
||||
{ "chapter": 3, "location": "dongpingg郡", "event": "跋锋寒现身,与欧阳希夷激战,石青璇箫音化解恶斗" },
|
||||
{ "chapter": 4, "location": "dongpingg郡", "event": "寇徐躲藏柴房七天,深化武学理解" },
|
||||
{ "chapter": 5, "lat": 34.9, "lng": 114.5, "event": "寇徐与宇文无敌首次对战,双方受伤,分出高下" },
|
||||
{ "chapter": 6, "location": "xingyang", "event": "寇徐抵达荥阳,与素素重逢,获翟让接纳" },
|
||||
{ "chapter": 6, "location": "luokou", "event": "瓦岗军攻占兴洛仓,李密声望上升,翟让地位动摇" },
|
||||
{ "chapter": 7, "location": "xingyang", "event": "寇徐在翟府学艺,屠叔方成为恩师" },
|
||||
{ "chapter": 8, "location": "xingyang", "event": "沈落雁对寇徐进行盘问与试探,双方交集增加" },
|
||||
{ "chapter": 9, "location": "xingyang", "event": "香玉山出现,代表巴陵帮提议合作对付宇文阀" },
|
||||
{ "chapter": 10, "lat": 34.75, "lng": 113.4, "event": "翟让因内伤复发与寇徐激战,双方力量均衡" },
|
||||
{ "chapter": 10, "location": "xingyang", "event": "翟让与李密之间的矛盾公开化,翟让拟将大权下交" },
|
||||
{ "chapter": 11, "lat": 35.4, "lng": 115.8, "event": "寇徐赴黛青院见沈落雁,获悉翟让伪装让位的计谋" },
|
||||
{ "chapter": 12, "location": "xingyang", "event": "李密发动突变进攻翟府,翟让与其决战,寇徐素素乘乱逃脱" }
|
||||
]
|
||||
}
|
||||
183
data/vol05.json
Normal file
183
data/vol05.json
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"volume": "卷五",
|
||||
"chapters": ["第01章 仅以身免", "第02章 大隐于市", "第03章 影子刺客", "第04章 偷龙转凤", "第05章 情孽纠缠"],
|
||||
|
||||
"locations": [
|
||||
{ "id": "yangzhou", "name": "扬州", "aliases": ["江都"], "type": "city", "lat": 32.39, "lng": 119.43, "description": "隋朝南都,长江与运河交汇的重镇,寇仲徐子陵的出生地" },
|
||||
{ "id": "xingyang", "name": "荥阳", "type": "city", "lat": 34.79, "lng": 113.38, "description": "瓦岗军翟让的根据地,本卷主要舞台" },
|
||||
{ "id": "wagang", "name": "瓦岗寨", "type": "town", "lat": 35.25, "lng": 114.7, "description": "翟让起义之地,大龙头府所在地" },
|
||||
{ "id": "grand_canal", "name": "大运河", "aliases": ["运河","通济渠"], "type": "waterway", "lat": 33.5, "lng": 118.0, "description": "贯通南北的水路交通线" },
|
||||
{ "id": "yangtze", "name": "长江", "aliases": ["大江"], "type": "waterway", "lat": 32.2, "lng": 119.0, "description": "中国第一大河" },
|
||||
{ "id": "liyang", "name": "历阳", "type": "city", "lat": 31.7, "lng": 118.37, "description": "长江沿岸重镇,被杜伏威攻占,截断长江水道" },
|
||||
{ "id": "luoyang", "name": "洛阳", "aliases": ["东都"], "type": "city", "lat": 34.62, "lng": 112.45, "description": "隋朝东都" },
|
||||
{ "id": "daxing", "name": "大兴", "aliases": ["长安","京师"], "type": "city", "lat": 34.26, "lng": 108.94, "description": "隋朝西京,帝国首都" },
|
||||
{ "id": "heiyang", "name": "黎阳仓", "type": "town", "lat": 35.8, "lng": 114.5, "description": "粮仓重镇,李密攻打的目标" }
|
||||
],
|
||||
|
||||
"factions": [
|
||||
{
|
||||
"id": "wagang_army",
|
||||
"name": "瓦岗军",
|
||||
"type": "义军",
|
||||
"color": "#FF6347",
|
||||
"leader": "翟让(已死)、李密",
|
||||
"territory": ["xingyang", "wagang"],
|
||||
"key_figures": ["翟让(死于本卷开头)", "李密", "徐世绩", "沈落雁", "祖君彦"],
|
||||
"description": "天下义军之首,翟让已遭李密属下击杀,内部出现严重分裂。李密接管势力,但仍有翟让旧部不服。现驻荥阳"
|
||||
},
|
||||
{
|
||||
"id": "li_clan",
|
||||
"name": "李阀",
|
||||
"type": "门阀",
|
||||
"color": "#DC143C",
|
||||
"leader": "李渊",
|
||||
"territory": [],
|
||||
"key_figures": ["李渋"],
|
||||
"description": "四姓门阀之一"
|
||||
},
|
||||
{
|
||||
"id": "song_clan",
|
||||
"name": "宋阀",
|
||||
"type": "门阀",
|
||||
"color": "#228B22",
|
||||
"leader": "宋缺",
|
||||
"territory": ["chengdu"],
|
||||
"key_figures": ["宋缺", "宋师道", "宋玉致"],
|
||||
"description": "四姓门阀之一,派宋玉致往荥阳联结瓦岗军,图谋联手对付杜伏威"
|
||||
},
|
||||
{
|
||||
"id": "du_fuwei",
|
||||
"name": "杜伏威军",
|
||||
"type": "义军",
|
||||
"color": "#FF8C00",
|
||||
"leader": "杜伏威",
|
||||
"territory": ["liyang"],
|
||||
"key_figures": ["杜伏威", "辅公祏"],
|
||||
"description": "江淮义军,占据历阳,截断长江盐船交通,成为宋阀和瓦岗军的共同威胁"
|
||||
},
|
||||
{
|
||||
"id": "sui",
|
||||
"name": "隋朝",
|
||||
"type": "朝廷",
|
||||
"color": "#FFD700",
|
||||
"leader": "杨广(隋炀帝)",
|
||||
"territory": [],
|
||||
"key_figures": ["杨广"],
|
||||
"description": "当朝政权,大军源源进驻江东,图谋收复江南"
|
||||
},
|
||||
{
|
||||
"id": "baijing_bang",
|
||||
"name": "巴陵帮",
|
||||
"type": "江湖势力",
|
||||
"color": "#DAA520",
|
||||
"leader": "佩佩(香玉山)",
|
||||
"territory": [],
|
||||
"key_figures": ["佩佩", "香玉山", "云娘"],
|
||||
"description": "荥阳黛青楼所属势力,老板娘佩佩为首领,受瓦岗军压制"
|
||||
},
|
||||
{
|
||||
"id": "iron_serfs",
|
||||
"name": "铁勒",
|
||||
"type": "外族",
|
||||
"color": "#696969",
|
||||
"leader": "铁勒王",
|
||||
"territory": [],
|
||||
"key_figures": ["曲傲"],
|
||||
"description": "西疆势力,与突厥为敌,派曲傲来中原联结势力,密谋刺杀李密"
|
||||
}
|
||||
],
|
||||
|
||||
"character_routes": [
|
||||
{
|
||||
"character": "寇仲 & 徐子陵",
|
||||
"color": "#FF4500",
|
||||
"route": [
|
||||
{ "location": "wagang", "chapter": 1, "event": "大龙头府火烧翟让死讯传出,两人在府内逃脱" },
|
||||
{ "lat": 34.79, "lng": 113.35, "chapter": 1, "event": "躲在水池假石山干井内,听李密与沈落雁商议" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "潜入沈落雁香居落雁庄躲藏" },
|
||||
{ "lat": 34.79, "lng": 113.38, "chapter": 2, "event": "在衣铺购买绸缎计划,通过素素寻找佩佩" },
|
||||
{ "location": "xingyang", "chapter": 3, "event": "徐子陵在沈宅闺房遭杨虚彦重创,险些丧命" },
|
||||
{ "lat": 34.79, "lng": 113.35, "chapter": 3, "event": "徐子陵伤重后潜逃,后向沈落雁诈降救素素" },
|
||||
{ "location": "xingyang", "chapter": 4, "event": "两人互换名册,以论语骗沈落雁,救出素素" },
|
||||
{ "location": "xingyang", "chapter": 5, "event": "躲入黛青楼,寻求佩佩帮助无果,改道潜入徐世绩府第探图" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "素素",
|
||||
"color": "#FFB6C1",
|
||||
"route": [
|
||||
{ "location": "wagang", "chapter": 1, "event": "翟府大火中被寇仲背着逃出,躲在水池假石山干井" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "进入沈落雁香居躲藏,后被沈府婢仆发现行迹异常" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "以小婢身份赴衣铺购买绸缎,获取佩佩的联系方式" },
|
||||
{ "location": "xingyang", "chapter": 3, "event": "在沈宅遭徐世绩逮捕,但寇仲以名册诈降救回" },
|
||||
{ "location": "xingyang", "chapter": 5, "event": "躲入徐世绩府中大柜,被徐子陵以真气保护呼吸" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "李密",
|
||||
"color": "#FF6347",
|
||||
"route": [
|
||||
{ "location": "wagang", "chapter": 1, "event": "率众火烧翟让大龙头府,杀翟让并接管瓦岗军" },
|
||||
{ "lat": 34.79, "lng": 113.35, "chapter": 1, "event": "亲临现场搜捕漏网之人,对寇仲徐子陵下杀令" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "率兵出城北上,攻打黎阳仓" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "沈落雁",
|
||||
"color": "#228B22",
|
||||
"route": [
|
||||
{ "location": "wagang", "chapter": 1, "event": "与沈落雁在翟府外商议李密建议" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "在落雁庄接待宋玉致,商议对付杜伏威的计划" },
|
||||
{ "location": "xingyang", "chapter": 3, "event": "闺房遭杨虚彦暗袭,险被刺杀" },
|
||||
{ "location": "xingyang", "chapter": 4, "event": "与寇仲在门前交易,以素素换名册,却被骗以论语替代" },
|
||||
{ "location": "xingyang", "chapter": 5, "event": "与徐世绩商议搜捕计划,怀疑徐子陵未死" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "徐世绩",
|
||||
"color": "#FF6347",
|
||||
"route": [
|
||||
{ "location": "wagang", "chapter": 1, "event": "参与火烧翟府,主持全城搜捕寇徐二人" },
|
||||
{ "location": "xingyang", "chapter": 2, "event": "在沈宅设伏搜索,全城逐户逐街查缉" },
|
||||
{ "location": "xingyang", "chapter": 5, "event": "与沈落雁商议扩大搜索范围,对感情生变而不悦" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "宋玉致",
|
||||
"color": "#228B22",
|
||||
"route": [
|
||||
{ "location": "xingyang", "chapter": 2, "event": "自成都来荥阳谒见李密,与沈落雁商议联手对付杜伏威及曲傲" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "杨虚彦",
|
||||
"color": "#000000",
|
||||
"route": [
|
||||
{ "location": "xingyang", "chapter": 3, "event": "躲在沈落雁闺房内暗袭,误将徐子陵作为沈落雁的人而重创他" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"character": "佩佩",
|
||||
"color": "#DAA520",
|
||||
"route": [
|
||||
{ "location": "xingyang", "chapter": 5, "event": "返回黛青楼闺房,遭沈落雁威胁,决定向其报告寇徐消息" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"key_events": [
|
||||
{ "chapter": 1, "location": "wagang", "event": "翟让大龙头府大火,翟让遭李密属下击杀,瓦岗军内部分裂" },
|
||||
{ "chapter": 1, "lat": 34.79, "lng": 113.35, "event": "寇仲徐子陵救素素躲入水池假石山干井,听李密决议杀死两人" },
|
||||
{ "chapter": 1, "event": "沈落雁对徐世绩表示寇徐两人功力日增,可能成为祸患", "lat": 34.79, "lng": 113.35 },
|
||||
{ "chapter": 2, "location": "xingyang", "event": "三人潜入沈落雁的落雁庄,利用荥阳城的迷宫般小巷躲避搜查" },
|
||||
{ "chapter": 2, "event": "宋玉致抵荥阳,向沈落雁透露曲傲密谋刺杀李密的计划", "lat": 34.79, "lng": 113.38 },
|
||||
{ "chapter": 2, "event": "素素为获取佩佩联系方式,赴衣铺指定购买绸缎,险被沈落雁撞见", "lat": 34.79, "lng": 113.38 },
|
||||
{ "chapter": 3, "location": "xingyang", "event": "沈宅内徐子陵遭影子刺客杨虚彦重创,险些丧命,寇仲救出" },
|
||||
{ "chapter": 3, "event": "三人夜间逃离沈宅,躲入附近民居储物房,徐子陵通过真气疗伤恢复", "lat": 34.79, "lng": 113.35 },
|
||||
{ "chapter": 4, "location": "xingyang", "event": "寇仲赴沈宅门前诈降,声称徐子陵已死,骗得沈落雁释放素素" },
|
||||
{ "chapter": 4, "event": "寇仲以论语替代名册,骗过沈落雁的验证,成功救出素素", "lat": 34.79, "lng": 113.38 },
|
||||
{ "chapter": 5, "location": "xingyang", "event": "三人躲入黛青楼,计划通过佩佩(香玉山)获得逃生帮助" },
|
||||
{ "chapter": 5, "event": "佩佩被沈落雁威胁,决定向其通报寇徐行踪,望破灭", "lat": 34.79, "lng": 113.38 },
|
||||
{ "chapter": 5, "event": "寇徐潜入徐世绩府中,在书室搜得荥阳城地下水沟图,寻得逃脱之路", "lat": 34.79, "lng": 113.38 }
|
||||
]
|
||||
}
|
||||
507
frontend/App.vue
Normal file
507
frontend/App.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<div class="map-container">
|
||||
<div id="map"></div>
|
||||
|
||||
<div class="map-title">大唐双龙传 - 势力分布地图</div>
|
||||
|
||||
<!-- 势力图例 -->
|
||||
<div class="legend">
|
||||
<h3>势力图例</h3>
|
||||
<div
|
||||
v-for="faction in factions"
|
||||
:key="faction.id"
|
||||
class="legend-item"
|
||||
@click="showFactionInfo(faction)"
|
||||
>
|
||||
<div class="legend-dot" :style="{ background: faction.color }"></div>
|
||||
<span>{{ faction.name }}({{ faction.leader }})</span>
|
||||
</div>
|
||||
|
||||
<div class="legend-section">
|
||||
<h3>人物路线</h3>
|
||||
<div
|
||||
v-for="route in routes"
|
||||
:key="route.character"
|
||||
class="legend-item"
|
||||
@click="toggleRoute(route)"
|
||||
>
|
||||
<div
|
||||
class="legend-line"
|
||||
:style="{
|
||||
background: route.color,
|
||||
opacity: selectedRoutes.includes(route.character) ? 1 : 0.4
|
||||
}"
|
||||
></div>
|
||||
<span :style="{ opacity: selectedRoutes.includes(route.character) ? 1 : 0.5 }">{{ route.character }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 章节面板 -->
|
||||
<div class="chapter-panel">
|
||||
<h3>章节进度</h3>
|
||||
<select v-model="selectedVolume" class="volume-select" @change="onVolumeChange">
|
||||
<option v-for="(data, idx) in allData" :key="idx" :value="idx">
|
||||
{{ data.volume }}
|
||||
</option>
|
||||
</select>
|
||||
<input
|
||||
type="range"
|
||||
class="chapter-slider"
|
||||
v-model.number="currentChapter"
|
||||
:min="1"
|
||||
:max="maxChapter"
|
||||
@input="updateMap"
|
||||
>
|
||||
<div class="chapter-label">第 {{ currentChapter }} / {{ maxChapter }} 章</div>
|
||||
<div class="chapter-name">{{ currentChapterName }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 势力详情面板 -->
|
||||
<div class="info-panel" v-if="selectedFaction">
|
||||
<span class="close-btn" @click="selectedFaction = null">×</span>
|
||||
<h3 :style="{ color: selectedFaction.color }">{{ selectedFaction.name }}</h3>
|
||||
<p><b>首领:</b>{{ selectedFaction.leader }}</p>
|
||||
<p>{{ selectedFaction.description }}</p>
|
||||
<p v-if="selectedFaction.territory && selectedFaction.territory.length">
|
||||
<b>据点:</b>{{ getTerritoryNames(selectedFaction.territory).join('、') }}
|
||||
</p>
|
||||
<p v-if="selectedFaction.key_figures && selectedFaction.key_figures.length">
|
||||
<b>关键人物:</b>{{ selectedFaction.key_figures.join('、') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import L from 'leaflet'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
|
||||
const allData = ref([])
|
||||
const factions = ref([])
|
||||
const locations = ref([])
|
||||
const routes = ref([])
|
||||
const currentChapter = ref(1)
|
||||
const selectedVolume = ref(0)
|
||||
const selectedRoutes = ref([])
|
||||
const selectedFaction = ref(null)
|
||||
|
||||
let map = null
|
||||
let routeLayers = []
|
||||
let locationMarkers = []
|
||||
let territoryLayers = []
|
||||
|
||||
const currentData = computed(() => allData.value[selectedVolume.value] || {})
|
||||
const chapters = computed(() => currentData.value.chapters || [])
|
||||
const maxChapter = computed(() => chapters.value.length || 1)
|
||||
const currentChapterName = computed(() => chapters.value[currentChapter.value - 1] || '')
|
||||
|
||||
onMounted(async () => {
|
||||
await loadAllData()
|
||||
initMap()
|
||||
updateMap()
|
||||
})
|
||||
|
||||
async function loadAllData() {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
const response = await fetch(`/data/vol${String(i).padStart(2, '0')}.json`)
|
||||
const data = await response.json()
|
||||
allData.value.push(data)
|
||||
}
|
||||
|
||||
// 初始化第一卷数据
|
||||
factions.value = allData.value[0]?.factions || []
|
||||
locations.value = allData.value[0]?.locations || []
|
||||
routes.value = allData.value[0]?.character_routes || []
|
||||
|
||||
currentChapter.value = maxChapter.value
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
map = L.map('map', {
|
||||
center: [32.0, 116.0],
|
||||
zoom: 6,
|
||||
zoomControl: true,
|
||||
attributionControl: false
|
||||
})
|
||||
|
||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||
maxZoom: 18,
|
||||
subdomains: 'abcd'
|
||||
}).addTo(map)
|
||||
|
||||
L.control.attribution({ prefix: false, position: 'bottomright' })
|
||||
.addAttribution('大唐双龙传 - 黄易')
|
||||
.addTo(map)
|
||||
}
|
||||
|
||||
function onVolumeChange() {
|
||||
factions.value = currentData.value.factions || []
|
||||
locations.value = currentData.value.locations || []
|
||||
routes.value = currentData.value.character_routes || []
|
||||
currentChapter.value = maxChapter.value
|
||||
selectedRoutes.value = []
|
||||
updateMap()
|
||||
}
|
||||
|
||||
function updateMap() {
|
||||
if (!map) return
|
||||
|
||||
// 确保当前章节在有效范围内
|
||||
if (currentChapter.value > maxChapter.value) {
|
||||
currentChapter.value = maxChapter.value
|
||||
}
|
||||
if (currentChapter.value < 1) {
|
||||
currentChapter.value = 1
|
||||
}
|
||||
|
||||
clearLayers()
|
||||
drawTerritories()
|
||||
drawLocations()
|
||||
drawRoutes()
|
||||
}
|
||||
|
||||
function clearLayers() {
|
||||
routeLayers.forEach(layer => map.removeLayer(layer))
|
||||
locationMarkers.forEach(layer => map.removeLayer(layer))
|
||||
territoryLayers.forEach(layer => map.removeLayer(layer))
|
||||
routeLayers = []
|
||||
locationMarkers = []
|
||||
territoryLayers = []
|
||||
}
|
||||
|
||||
function drawTerritories() {
|
||||
factions.value.forEach(f => {
|
||||
if (!f.territory || !f.territory.length) return
|
||||
|
||||
f.territory.forEach(tid => {
|
||||
const loc = locations.value.find(l => l.id === tid)
|
||||
if (!loc) return
|
||||
|
||||
const circle = L.circle([loc.lat, loc.lng], {
|
||||
radius: 50000,
|
||||
color: f.color,
|
||||
fillColor: f.color,
|
||||
fillOpacity: 0.12,
|
||||
weight: 2,
|
||||
opacity: 0.5,
|
||||
dashArray: '6 4'
|
||||
}).addTo(map)
|
||||
|
||||
const label = L.marker([loc.lat + 0.35, loc.lng], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="color:${f.color};font-size:11px;font-weight:bold;text-shadow:0 0 4px rgba(0,0,0,0.8);white-space:nowrap;text-align:center">${f.name}</div>`,
|
||||
iconAnchor: [30, 8]
|
||||
})
|
||||
}).addTo(map)
|
||||
|
||||
territoryLayers.push(circle, label)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function drawLocations() {
|
||||
locations.value.forEach(loc => {
|
||||
let markerColor = '#aaa'
|
||||
for (const f of factions.value) {
|
||||
if (f.territory && f.territory.includes(loc.id)) {
|
||||
markerColor = f.color
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const size = loc.type === 'city' ? 10 : loc.type === 'landmark' ? 8 : 6
|
||||
const icon = L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="width:${size}px;height:${size}px;background:${markerColor};border:2px solid #fff;border-radius:50%;box-shadow:0 0 6px ${markerColor}"></div>`,
|
||||
iconSize: [size, size],
|
||||
iconAnchor: [size / 2, size / 2]
|
||||
})
|
||||
|
||||
const marker = L.marker([loc.lat, loc.lng], { icon })
|
||||
.bindPopup(`<b>${loc.name}</b><br>${loc.description || ''}`)
|
||||
.addTo(map)
|
||||
|
||||
const nameLabel = L.marker([loc.lat - 0.15, loc.lng], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="color:#ccc;font-size:11px;text-shadow:0 0 3px #000,0 0 6px #000;white-space:nowrap;text-align:center">${loc.name}</div>`,
|
||||
iconAnchor: [30, 0]
|
||||
})
|
||||
}).addTo(map)
|
||||
|
||||
locationMarkers.push(marker, nameLabel)
|
||||
})
|
||||
}
|
||||
|
||||
function drawRoutes() {
|
||||
routes.value.forEach(route => {
|
||||
if (!selectedRoutes.value.includes(route.character)) return
|
||||
|
||||
const points = route.route || []
|
||||
|
||||
for (let i = 0; i < points.length - 1; i++) {
|
||||
const p1 = getPointCoords(points[i])
|
||||
const p2 = getPointCoords(points[i + 1])
|
||||
if (!p1 || !p2) continue
|
||||
|
||||
const line = L.polyline([[p1.lat, p1.lng], [p2.lat, p2.lng]], {
|
||||
color: route.color,
|
||||
weight: 3,
|
||||
opacity: 0.8
|
||||
}).addTo(map)
|
||||
|
||||
routeLayers.push(line)
|
||||
}
|
||||
|
||||
points.forEach((p, idx) => {
|
||||
const coords = getPointCoords(p)
|
||||
if (!coords) return
|
||||
|
||||
const isEnd = idx === points.length - 1
|
||||
const isStart = idx === 0
|
||||
const size = (isStart || isEnd) ? 7 : 5
|
||||
|
||||
const dot = L.circleMarker([coords.lat, coords.lng], {
|
||||
radius: size,
|
||||
color: route.color,
|
||||
fillColor: isEnd ? '#fff' : route.color,
|
||||
fillOpacity: 0.9,
|
||||
weight: 2
|
||||
})
|
||||
.bindPopup(`<b>${route.character}</b><br>第${p.chapter}章:${p.event || ''}`)
|
||||
.addTo(map)
|
||||
|
||||
routeLayers.push(dot)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getPointCoords(point) {
|
||||
if (point.lat && point.lng) {
|
||||
return { lat: point.lat, lng: point.lng }
|
||||
}
|
||||
if (point.location) {
|
||||
const loc = locations.value.find(l => l.id === point.location)
|
||||
if (loc) {
|
||||
return { lat: loc.lat, lng: loc.lng }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function toggleRoute(route) {
|
||||
const idx = selectedRoutes.value.indexOf(route.character)
|
||||
if (idx > -1) {
|
||||
selectedRoutes.value.splice(idx, 1)
|
||||
} else {
|
||||
selectedRoutes.value.push(route.character)
|
||||
}
|
||||
|
||||
clearLayers()
|
||||
drawTerritories()
|
||||
drawLocations()
|
||||
drawRoutes()
|
||||
}
|
||||
|
||||
function showFactionInfo(faction) {
|
||||
selectedFaction.value = faction
|
||||
}
|
||||
|
||||
function getTerritoryNames(territoryIds) {
|
||||
return territoryIds.map(tid => {
|
||||
const loc = locations.value.find(l => l.id === tid)
|
||||
return loc ? loc.name : tid
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 根容器必须 position:relative,使绝对定位子元素相对它定位 */
|
||||
.map-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.map-title {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1000;
|
||||
background: rgba(20, 20, 40, 0.9);
|
||||
padding: 8px 24px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #c9a96e;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #c9a96e;
|
||||
letter-spacing: 4px;
|
||||
text-shadow: 0 0 10px rgba(201, 169, 110, 0.5);
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ====== 势力图例 ====== */
|
||||
.legend {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 10px;
|
||||
z-index: 1000;
|
||||
background: rgba(20, 20, 40, 0.92);
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #555;
|
||||
max-width: 260px;
|
||||
max-height: calc(100vh - 60px);
|
||||
overflow-y: auto;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.legend h3 {
|
||||
color: #c9a96e;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #444;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 3px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.legend-item:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.legend-line {
|
||||
width: 20px;
|
||||
height: 3px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.legend-section {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* ====== 章节面板 ====== */
|
||||
.chapter-panel {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 10px;
|
||||
z-index: 1000;
|
||||
background: rgba(20, 20, 40, 0.92);
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #555;
|
||||
width: 320px;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.chapter-panel h3 {
|
||||
color: #c9a96e;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #444;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.volume-select {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
padding: 4px 8px;
|
||||
background: #333;
|
||||
color: #e0e0e0;
|
||||
border: 1px solid #555;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.chapter-slider {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
accent-color: #c9a96e;
|
||||
}
|
||||
|
||||
.chapter-label {
|
||||
font-size: 12px;
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chapter-name {
|
||||
font-size: 13px;
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* ====== 势力详情面板 ====== */
|
||||
.info-panel {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 10px;
|
||||
z-index: 1000;
|
||||
background: rgba(20, 20, 40, 0.92);
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #555;
|
||||
width: 320px;
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.info-panel h3 {
|
||||
color: #c9a96e;
|
||||
margin-bottom: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.info-panel .close-btn {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 12px;
|
||||
cursor: pointer;
|
||||
color: #aaa;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.info-panel .close-btn:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel p {
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin: 4px 0;
|
||||
}
|
||||
</style>
|
||||
12
frontend/index.html
Normal file
12
frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>大唐双龙传 - 势力分布地图</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
5
frontend/main.js
Normal file
5
frontend/main.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import './style.css'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
1214
frontend/package-lock.json
generated
Normal file
1214
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
frontend/package.json
Normal file
18
frontend/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "dt-map",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.0",
|
||||
"leaflet": "^1.9.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
}
|
||||
14
frontend/style.css
Normal file
14
frontend/style.css
Normal file
@@ -0,0 +1,14 @@
|
||||
* { margin: 0; padding: 0; box-sizing: border-box }
|
||||
body { font-family: 'Microsoft YaHei', 'SimSun', sans-serif; background: #1a1a2e; color: #e0e0e0 }
|
||||
#app { width: 100%; height: 100vh; overflow: hidden }
|
||||
#map { width: 100%; height: 100vh }
|
||||
|
||||
.leaflet-popup-content-wrapper {
|
||||
background: rgba(30,30,50,0.95) !important;
|
||||
color: #e0e0e0 !important;
|
||||
border: 1px solid #c9a96e !important;
|
||||
border-radius: 6px !important
|
||||
}
|
||||
.leaflet-popup-tip { background: rgba(30,30,50,0.95) !important }
|
||||
.leaflet-popup-content { font-size: 13px !important; line-height: 1.5 !important }
|
||||
.leaflet-popup-content b { color: #c9a96e }
|
||||
36
frontend/vite.config.js
Normal file
36
frontend/vite.config.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'path'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
// 开发时将 ../data 目录挂载到 /data 路径
|
||||
{
|
||||
name: 'serve-data-dir',
|
||||
configureServer(server) {
|
||||
server.middlewares.use('/data', (req, res, next) => {
|
||||
const filePath = path.resolve(__dirname, '../data', req.url.replace(/^\//, '').split('?')[0])
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
res.setHeader('Content-Type', 'application/json; charset=utf-8')
|
||||
res.end(content)
|
||||
} catch {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
],
|
||||
server: {
|
||||
port: 5173
|
||||
},
|
||||
build: {
|
||||
outDir: resolve(__dirname, '../dist')
|
||||
}
|
||||
})
|
||||
443
index.html
443
index.html
@@ -1,443 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>大唐双龙传 - 势力分布地图(卷一)</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Microsoft YaHei', 'SimSun', sans-serif; background: #1a1a2e; color: #e0e0e0; }
|
||||
|
||||
#map { width: 100%; height: 100vh; }
|
||||
|
||||
/* Title overlay */
|
||||
.map-title {
|
||||
position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
|
||||
z-index: 1000; background: rgba(20,20,40,0.9); padding: 8px 24px;
|
||||
border-radius: 8px; border: 1px solid #c9a96e;
|
||||
font-size: 20px; font-weight: bold; color: #c9a96e;
|
||||
letter-spacing: 4px; text-shadow: 0 0 10px rgba(201,169,110,0.5);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Legend panel */
|
||||
.legend {
|
||||
position: absolute; bottom: 20px; left: 10px; z-index: 1000;
|
||||
background: rgba(20,20,40,0.92); padding: 12px 16px;
|
||||
border-radius: 8px; border: 1px solid #555; max-width: 260px;
|
||||
font-size: 13px; line-height: 1.6;
|
||||
}
|
||||
.legend h3 { color: #c9a96e; margin-bottom: 8px; font-size: 14px; border-bottom: 1px solid #444; padding-bottom: 4px; }
|
||||
.legend-item { display: flex; align-items: center; margin: 3px 0; cursor: pointer; }
|
||||
.legend-item:hover { opacity: 0.7; }
|
||||
.legend-dot { width: 12px; height: 12px; border-radius: 50%; margin-right: 8px; flex-shrink: 0; border: 1px solid rgba(255,255,255,0.3); }
|
||||
.legend-line { width: 20px; height: 3px; margin-right: 8px; flex-shrink: 0; border-radius: 2px; }
|
||||
.legend-section { margin-top: 8px; }
|
||||
|
||||
/* Chapter slider */
|
||||
.chapter-panel {
|
||||
position: absolute; bottom: 20px; right: 10px; z-index: 1000;
|
||||
background: rgba(20,20,40,0.92); padding: 12px 16px;
|
||||
border-radius: 8px; border: 1px solid #555; width: 320px;
|
||||
}
|
||||
.chapter-panel h3 { color: #c9a96e; margin-bottom: 8px; font-size: 14px; border-bottom: 1px solid #444; padding-bottom: 4px; }
|
||||
.chapter-slider { width: 100%; margin: 8px 0; accent-color: #c9a96e; }
|
||||
.chapter-label { font-size: 12px; color: #aaa; text-align: center; }
|
||||
.chapter-name { font-size: 13px; color: #e0e0e0; text-align: center; margin-top: 4px; }
|
||||
|
||||
/* Info panel */
|
||||
.info-panel {
|
||||
position: absolute; top: 60px; right: 10px; z-index: 1000;
|
||||
background: rgba(20,20,40,0.92); padding: 12px 16px;
|
||||
border-radius: 8px; border: 1px solid #555; width: 320px;
|
||||
max-height: 50vh; overflow-y: auto; display: none;
|
||||
}
|
||||
.info-panel h3 { color: #c9a96e; margin-bottom: 6px; font-size: 15px; }
|
||||
.info-panel .close-btn {
|
||||
position: absolute; top: 8px; right: 12px; cursor: pointer;
|
||||
color: #aaa; font-size: 16px;
|
||||
}
|
||||
.info-panel .close-btn:hover { color: #fff; }
|
||||
.info-panel p { font-size: 13px; line-height: 1.6; margin: 4px 0; }
|
||||
.info-panel .tag { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 11px; margin-right: 4px; }
|
||||
|
||||
/* Custom popup */
|
||||
.leaflet-popup-content-wrapper {
|
||||
background: rgba(30,30,50,0.95) !important;
|
||||
color: #e0e0e0 !important;
|
||||
border: 1px solid #c9a96e !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
.leaflet-popup-tip { background: rgba(30,30,50,0.95) !important; }
|
||||
.leaflet-popup-content { font-size: 13px !important; line-height: 1.5 !important; }
|
||||
.leaflet-popup-content b { color: #c9a96e; }
|
||||
|
||||
/* Route animation */
|
||||
@keyframes dash { to { stroke-dashoffset: 0; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
<div class="map-title">大唐双龙传 - 卷一势力分布图</div>
|
||||
|
||||
<div class="legend" id="legend">
|
||||
<h3>势力图例</h3>
|
||||
<div id="faction-legend"></div>
|
||||
<div class="legend-section">
|
||||
<h3>人物路线</h3>
|
||||
<div id="route-legend"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chapter-panel">
|
||||
<h3>章节进度</h3>
|
||||
<input type="range" class="chapter-slider" id="chapterSlider" min="1" max="11" value="11" step="1">
|
||||
<div class="chapter-label">第 <span id="chapterNum">11</span> / 11 章</div>
|
||||
<div class="chapter-name" id="chapterName">第11章 追兵忽至</div>
|
||||
</div>
|
||||
|
||||
<div class="info-panel" id="infoPanel">
|
||||
<span class="close-btn" onclick="document.getElementById('infoPanel').style.display='none'">×</span>
|
||||
<div id="infoPanelContent"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ==================== DATA ====================
|
||||
const chapters = [
|
||||
"第01章 相依为命", "第02章 大祸临头", "第03章 远离扬州",
|
||||
"第04章 纠缠不清", "第05章 晴天霹雳", "第06章 九玄大法",
|
||||
"第07章 和氏之璧", "第08章 痛不欲生", "第09章 再上征途",
|
||||
"第10章 奋不顾身", "第11章 追兵忽至"
|
||||
];
|
||||
|
||||
const locations = [
|
||||
{ id:"yangzhou", name:"扬州(江都)", type:"city", lat:32.39, lng:119.43, desc:"隋朝南都,运河与长江交汇的重镇。寇仲徐子陵出生地,宇文化及夺《长生诀》之地。", chapter:1 },
|
||||
{ id:"danyang", name:"丹阳", type:"city", lat:32.0, lng:118.95, desc:"扬州上游最大城市,河道纵横的水城。三人遇宋师道之处。", chapter:5 },
|
||||
{ id:"beipo", name:"北坡县", type:"town", lat:32.5, lng:119.3, desc:"扬州附近大县,寇徐冒充宇文家公子骗吃骗住。", chapter:4 },
|
||||
{ id:"liyang", name:"历阳", type:"city", lat:31.7, lng:118.37, desc:"长江沿岸重镇,杜伏威大破隋军后占领,截断长江水路。", chapter:10 },
|
||||
{ id:"luoyang", name:"洛阳(东都)", type:"city", lat:34.62, lng:112.45, desc:"隋朝东都,和氏璧传闻出现之地,寇徐目标目的地。", chapter:7 },
|
||||
{ id:"daxing", name:"大兴(长安)", type:"city", lat:34.26, lng:108.94, desc:"隋朝西京,帝国首都。杨公宝库藏于京都跃马桥。", chapter:1 },
|
||||
{ id:"xingyang", name:"荥阳", type:"city", lat:34.79, lng:113.38, desc:"瓦岗军翟让根据地。李密在此大败隋军、击杀张须陀。", chapter:10 },
|
||||
{ id:"cuishan", name:"翠山镇", type:"town", lat:29.5, lng:116.8, desc:"鄱阳湖东,新安郡南的大镇。寇徐在老张饭馆打工三月。", chapter:9 },
|
||||
{ id:"gaoyou", name:"高邮", type:"city", lat:32.78, lng:119.44, desc:"运河沿线城市,李靖约定的北上会合点。", chapter:11 },
|
||||
{ id:"chengdu", name:"成都", type:"city", lat:30.57, lng:104.07, desc:"独尊堡解晖的基地,宋阀私盐运往此处。", chapter:7 },
|
||||
{ id:"gaoji", name:"高鸡泊", type:"town", lat:37.5, lng:115.7, desc:"窦建德据此为基地,势力贯黄河,拥兵十万。", chapter:10 },
|
||||
{ id:"valley", name:"傅君婥墓(山谷)", type:"landmark", lat:31.3, lng:118.0, desc:"傅君婥战死安葬之地。寇徐在此隐居练功,突破气机。", chapter:8 }
|
||||
];
|
||||
|
||||
const factions = [
|
||||
{ id:"sui", name:"隋朝", color:"#FFD700", leader:"杨广(隋炀帝)", territories:["yangzhou","luoyang","daxing","danyang","gaoyou"], desc:"控制三大重镇,但内忧外患,叛乱四起" },
|
||||
{ id:"yuwen", name:"宇文阀", color:"#4169E1", leader:"宇文伤 / 宇文化及", territories:["daxing"], desc:"四大门阀之首,暗图复辟北周。宇文化及为禁卫总管" },
|
||||
{ id:"song_clan", name:"宋阀", color:"#228B22", leader:"天刀·宋缺", territories:["chengdu"], desc:"南方汉族正统,私盐贸易暴利,势力暗增" },
|
||||
{ id:"wagang", name:"瓦岗军", color:"#FF6347", leader:"翟让 / 李密", territories:["xingyang"], desc:"天下义军之首。李密声势凌驾翟让,暗藏内讧之患" },
|
||||
{ id:"du_fuwei", name:"杜伏威军", color:"#FF8C00", leader:"杜伏威", territories:["liyang"], desc:"江淮义军,新占历阳,截断长江交通" },
|
||||
{ id:"dou_jiande", name:"窦建德军", color:"#8B4513", leader:"窦建德", territories:["gaoji"], desc:"河北霸主,十万之众,势力直贯黄河" },
|
||||
{ id:"li_clan", name:"李阀", color:"#DC143C", leader:"李渊", territories:[], desc:"四姓门阀之一,受杨广猜忌,尚未起事" },
|
||||
{ id:"goguryeo", name:"高丽", color:"#00CED1", leader:"傅采林", territories:[], desc:"东北邻国,派傅君婥刺杀杨广" },
|
||||
{ id:"turks", name:"突厥", color:"#2F4F4F", leader:"武尊·毕玄", territories:[], desc:"北方最大外患" }
|
||||
];
|
||||
|
||||
const routes = [
|
||||
{
|
||||
name: "寇仲 & 徐子陵", color: "#FF4500", dashArray: null,
|
||||
points: [
|
||||
{ lat:32.39, lng:119.43, ch:1, label:"扬州:相依为命" },
|
||||
{ lat:32.3, lng:119.2, ch:3, label:"经暗渠出城" },
|
||||
{ lat:32.25, lng:119.1, ch:3, label:"跳入长江" },
|
||||
{ lat:32.5, lng:119.3, ch:4, label:"北坡县冒充公子" },
|
||||
{ lat:32.0, lng:118.95, ch:5, label:"丹阳遇宋师道" },
|
||||
{ lat:31.8, lng:118.5, ch:6, label:"宋船上学九玄大法" },
|
||||
{ lat:31.5, lng:118.2, ch:8, label:"逃离宋船" },
|
||||
{ lat:31.3, lng:118.0, ch:8, label:"山谷:傅君婥战死" },
|
||||
{ lat:29.5, lng:116.8, ch:9, label:"翠山镇打工三月" },
|
||||
{ lat:31.5, lng:117.8, ch:10, label:"救素素、遇李靖" },
|
||||
{ lat:31.9, lng:118.5, ch:11, label:"丹阳近郊遇追兵" }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "宇文化及", color: "#4169E1", dashArray: "8 4",
|
||||
points: [
|
||||
{ lat:33.5, lng:118.0, ch:1, label:"率五牙大舰南下" },
|
||||
{ lat:32.39, lng:119.43, ch:1, label:"扬州击杀石龙" },
|
||||
{ lat:32.0, lng:119.0, ch:3, label:"长江追击" },
|
||||
{ lat:31.5, lng:118.2, ch:8, label:"山上决战受重伤" }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "傅君婥", color: "#E0E0E0", dashArray: "4 4",
|
||||
points: [
|
||||
{ lat:32.5, lng:119.35, ch:1, label:"扬州北郊杀焦邪" },
|
||||
{ lat:32.25, lng:119.1, ch:3, label:"长江上救起二人" },
|
||||
{ lat:32.5, lng:119.3, ch:4, label:"北坡县救人" },
|
||||
{ lat:32.0, lng:118.95, ch:5, label:"丹阳" },
|
||||
{ lat:31.8, lng:118.5, ch:7, label:"船上传功" },
|
||||
{ lat:31.3, lng:118.0, ch:8, label:"山谷:战死" }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "李靖", color: "#00BFFF", dashArray: "6 3",
|
||||
points: [
|
||||
{ lat:31.7, lng:118.37, ch:10, label:"随杜伏威军驻历阳" },
|
||||
{ lat:31.5, lng:117.8, ch:10, label:"射杀祈老大救人" },
|
||||
{ lat:31.9, lng:118.5, ch:11, label:"丹阳近郊被重伤" }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== MAP INIT ====================
|
||||
const map = L.map('map', {
|
||||
center: [32.0, 116.0],
|
||||
zoom: 6,
|
||||
zoomControl: true,
|
||||
attributionControl: false
|
||||
});
|
||||
|
||||
// Dark tile layer
|
||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||
maxZoom: 18,
|
||||
subdomains: 'abcd'
|
||||
}).addTo(map);
|
||||
|
||||
// Attribution
|
||||
L.control.attribution({ prefix: false, position: 'bottomright' })
|
||||
.addAttribution('大唐双龙传 - 黄易')
|
||||
.addTo(map);
|
||||
|
||||
// ==================== LAYERS ====================
|
||||
const layerGroups = {};
|
||||
let currentChapter = 11;
|
||||
|
||||
// Faction territory circles
|
||||
const territoryLayers = [];
|
||||
factions.forEach(f => {
|
||||
f.territories.forEach(tid => {
|
||||
const loc = locations.find(l => l.id === tid);
|
||||
if (!loc) return;
|
||||
const circle = L.circle([loc.lat, loc.lng], {
|
||||
radius: 50000,
|
||||
color: f.color,
|
||||
fillColor: f.color,
|
||||
fillOpacity: 0.12,
|
||||
weight: 2,
|
||||
opacity: 0.5,
|
||||
dashArray: '6 4'
|
||||
}).addTo(map);
|
||||
circle._factionId = f.id;
|
||||
circle._chapterMin = loc.chapter;
|
||||
territoryLayers.push(circle);
|
||||
|
||||
// Faction label
|
||||
const label = L.marker([loc.lat + 0.35, loc.lng], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="color:${f.color};font-size:11px;font-weight:bold;text-shadow:0 0 4px rgba(0,0,0,0.8);white-space:nowrap;text-align:center">${f.name}</div>`,
|
||||
iconAnchor: [30, 8]
|
||||
})
|
||||
}).addTo(map);
|
||||
label._chapterMin = loc.chapter;
|
||||
territoryLayers.push(label);
|
||||
});
|
||||
});
|
||||
|
||||
// Location markers
|
||||
const locationMarkers = [];
|
||||
const cityIcon = (color) => L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="width:10px;height:10px;background:${color};border:2px solid #fff;border-radius:50%;box-shadow:0 0 6px ${color}"></div>`,
|
||||
iconSize: [10, 10],
|
||||
iconAnchor: [5, 5]
|
||||
});
|
||||
const townIcon = (color) => L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="width:8px;height:8px;background:${color};border:1.5px solid #ccc;border-radius:50%;box-shadow:0 0 4px ${color}"></div>`,
|
||||
iconSize: [8, 8],
|
||||
iconAnchor: [4, 4]
|
||||
});
|
||||
const landmarkIcon = L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="width:8px;height:8px;background:#FF69B4;border:1.5px solid #fff;transform:rotate(45deg);box-shadow:0 0 4px #FF69B4"></div>`,
|
||||
iconSize: [8, 8],
|
||||
iconAnchor: [4, 4]
|
||||
});
|
||||
|
||||
locations.forEach(loc => {
|
||||
// Determine controlling faction color
|
||||
let markerColor = '#aaa';
|
||||
for (const f of factions) {
|
||||
if (f.territories.includes(loc.id)) { markerColor = f.color; break; }
|
||||
}
|
||||
|
||||
const icon = loc.type === 'city' ? cityIcon(markerColor) :
|
||||
loc.type === 'landmark' ? landmarkIcon : townIcon(markerColor);
|
||||
|
||||
const marker = L.marker([loc.lat, loc.lng], { icon })
|
||||
.bindPopup(`<b>${loc.name}</b><br>${loc.desc}`)
|
||||
.addTo(map);
|
||||
marker._chapterMin = loc.chapter;
|
||||
locationMarkers.push(marker);
|
||||
|
||||
// City name label
|
||||
const nameLabel = L.marker([loc.lat - 0.15, loc.lng], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="color:#ccc;font-size:11px;text-shadow:0 0 3px #000,0 0 6px #000;white-space:nowrap;text-align:center">${loc.name}</div>`,
|
||||
iconAnchor: [30, 0]
|
||||
})
|
||||
}).addTo(map);
|
||||
nameLabel._chapterMin = loc.chapter;
|
||||
locationMarkers.push(nameLabel);
|
||||
});
|
||||
|
||||
// Character routes
|
||||
const routeLayers = [];
|
||||
routes.forEach(r => {
|
||||
// Create polyline segments per chapter
|
||||
for (let i = 0; i < r.points.length - 1; i++) {
|
||||
const p1 = r.points[i], p2 = r.points[i+1];
|
||||
const maxCh = p2.ch;
|
||||
|
||||
const line = L.polyline([[p1.lat, p1.lng], [p2.lat, p2.lng]], {
|
||||
color: r.color,
|
||||
weight: 3,
|
||||
opacity: 0.8,
|
||||
dashArray: r.dashArray || undefined
|
||||
}).addTo(map);
|
||||
line._chapterMax = maxCh;
|
||||
line._routeName = r.name;
|
||||
routeLayers.push(line);
|
||||
}
|
||||
|
||||
// Route point markers
|
||||
r.points.forEach((p, idx) => {
|
||||
const isEnd = idx === r.points.length - 1;
|
||||
const isStart = idx === 0;
|
||||
const size = (isStart || isEnd) ? 7 : 5;
|
||||
|
||||
const dot = L.circleMarker([p.lat, p.lng], {
|
||||
radius: size,
|
||||
color: r.color,
|
||||
fillColor: isEnd ? '#fff' : r.color,
|
||||
fillOpacity: 0.9,
|
||||
weight: 2
|
||||
}).bindPopup(`<b>${r.name}</b><br>第${p.ch}章:${p.label}`)
|
||||
.addTo(map);
|
||||
dot._chapterMax = p.ch;
|
||||
dot._routeName = r.name;
|
||||
routeLayers.push(dot);
|
||||
});
|
||||
});
|
||||
|
||||
// Waterways (simplified)
|
||||
const grandCanal = L.polyline([
|
||||
[39.9, 116.4], [37.5, 116.8], [35.0, 117.0], [34.62, 114.0],
|
||||
[33.5, 118.0], [32.78, 119.44], [32.39, 119.43]
|
||||
], { color: '#2a6496', weight: 1.5, opacity: 0.4, dashArray: '4 4' }).addTo(map);
|
||||
|
||||
const yangtze = L.polyline([
|
||||
[30.57, 104.07], [29.5, 106.5], [30.5, 111.3], [30.6, 114.3],
|
||||
[29.5, 116.0], [31.3, 118.0], [31.7, 118.37], [32.0, 118.95], [32.2, 119.2], [32.39, 119.43]
|
||||
], { color: '#2a6496', weight: 2, opacity: 0.4 }).addTo(map);
|
||||
|
||||
// ==================== LEGEND ====================
|
||||
const factionLegend = document.getElementById('faction-legend');
|
||||
factions.forEach(f => {
|
||||
if (f.territories.length === 0 && f.id !== 'li_clan') return;
|
||||
const div = document.createElement('div');
|
||||
div.className = 'legend-item';
|
||||
div.innerHTML = `<div class="legend-dot" style="background:${f.color}"></div><span>${f.name}(${f.leader})</span>`;
|
||||
div.onclick = () => showFactionInfo(f);
|
||||
factionLegend.appendChild(div);
|
||||
});
|
||||
|
||||
const routeLegend = document.getElementById('route-legend');
|
||||
routes.forEach(r => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'legend-item';
|
||||
div.innerHTML = `<div class="legend-line" style="background:${r.color}"></div><span>${r.name}</span>`;
|
||||
routeLegend.appendChild(div);
|
||||
});
|
||||
|
||||
function showFactionInfo(f) {
|
||||
const panel = document.getElementById('infoPanel');
|
||||
const content = document.getElementById('infoPanelContent');
|
||||
content.innerHTML = `
|
||||
<h3 style="color:${f.color}">${f.name}</h3>
|
||||
<p><b>首领:</b>${f.leader}</p>
|
||||
<p>${f.desc}</p>
|
||||
${f.territories.length ? `<p><b>据点:</b>${f.territories.map(t => {
|
||||
const loc = locations.find(l => l.id === t);
|
||||
return loc ? loc.name : t;
|
||||
}).join('、')}</p>` : ''}
|
||||
`;
|
||||
panel.style.display = 'block';
|
||||
}
|
||||
|
||||
// ==================== CHAPTER SLIDER ====================
|
||||
const slider = document.getElementById('chapterSlider');
|
||||
const chapterNumEl = document.getElementById('chapterNum');
|
||||
const chapterNameEl = document.getElementById('chapterName');
|
||||
|
||||
slider.addEventListener('input', (e) => {
|
||||
currentChapter = parseInt(e.target.value);
|
||||
chapterNumEl.textContent = currentChapter;
|
||||
chapterNameEl.textContent = chapters[currentChapter - 1];
|
||||
updateVisibility();
|
||||
});
|
||||
|
||||
function updateVisibility() {
|
||||
// Territory layers
|
||||
territoryLayers.forEach(layer => {
|
||||
const show = !layer._chapterMin || layer._chapterMin <= currentChapter;
|
||||
if (show) {
|
||||
if (!map.hasLayer(layer)) map.addLayer(layer);
|
||||
} else {
|
||||
if (map.hasLayer(layer)) map.removeLayer(layer);
|
||||
}
|
||||
});
|
||||
|
||||
// Location markers
|
||||
locationMarkers.forEach(marker => {
|
||||
const show = !marker._chapterMin || marker._chapterMin <= currentChapter;
|
||||
if (show) {
|
||||
if (!map.hasLayer(marker)) map.addLayer(marker);
|
||||
} else {
|
||||
if (map.hasLayer(marker)) map.removeLayer(marker);
|
||||
}
|
||||
});
|
||||
|
||||
// Route layers
|
||||
routeLayers.forEach(layer => {
|
||||
const show = !layer._chapterMax || layer._chapterMax <= currentChapter;
|
||||
if (show) {
|
||||
if (!map.hasLayer(layer)) map.addLayer(layer);
|
||||
} else {
|
||||
if (map.hasLayer(layer)) map.removeLayer(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== WATERWAY LABELS ====================
|
||||
L.marker([33.0, 117.5], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: '<div style="color:#4a90b8;font-size:10px;opacity:0.6;transform:rotate(-30deg);white-space:nowrap">大运河</div>',
|
||||
iconAnchor: [15, 5]
|
||||
})
|
||||
}).addTo(map);
|
||||
|
||||
L.marker([30.8, 113.0], {
|
||||
icon: L.divIcon({
|
||||
className: '',
|
||||
html: '<div style="color:#4a90b8;font-size:10px;opacity:0.6;white-space:nowrap">长江</div>',
|
||||
iconAnchor: [10, 5]
|
||||
})
|
||||
}).addTo(map);
|
||||
|
||||
// Initial state
|
||||
updateVisibility();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user