|
|
| (未显示另一用户的1个中间版本) |
| 第1行: |
第1行: |
| [[Category:公共设施]] | | [[Category:公共设施]]<br/> |
| {{未完成}} | | {{未完成}}<br/> |
| <html>
| | {{铁路}}<br/> |
| | | 图例:<br/> |
| <body>
| | {{角标|背景颜色=#B02E26|文字颜色=#FFFFFF|内容=1号线}} |
| <div id="MainMap"></div>
| | {{角标|背景颜色=#3C44AA|文字颜色=#FFFFFF|内容=2号线}} |
| <script>
| | {{角标|背景颜色=#FED83D|文字颜色=#000000|内容=3号线}} |
| window.dataset = {
| | {{角标|背景颜色=#169C9C|文字颜色=#FFFFFF|内容=4号线}} |
| "lines": {
| | {{角标|背景颜色=#8932B8|文字颜色=#FFFFFF|内容=5号线}} |
| "1": {
| | {{角标|背景颜色=#C74EBD|文字颜色=#FFFFFF|内容=6号线}} |
| "color": "#B02E26",
| | {{角标|背景颜色=#5E7C16|文字颜色=#FFFFFF|内容=8号线}}<br/> |
| "route": [
| |
| { "SCZCT": "" },
| |
| { "CZHCT": "" },
| |
| { "NNCNL": "" },
| |
| { "SPAWN": "" },
| |
| { "MNTDY": "" },
| |
| { "EYYCT": "" },
| |
| { "LNYCT": "" }
| |
| ]
| |
| },
| |
| "2": {
| |
| "color": "#3C44AA",
| |
| "route": [
| |
| { "WTCCT": "" },
| |
| { "LNYCT": "" },
| |
| { "WUMIN": "" },
| |
| { "XJIAN": "" },
| |
| { "PGNUN": "" }
| |
| ],
| |
| "stat": "planned"
| |
| },
| |
| "2支线": {
| |
| "color": "#3C44AA",
| |
| "route": [
| |
| { "WUMIN": "" },
| |
| { "STRHD": "" },
| |
| { "BREAD": "" }
| |
| ]
| |
| },
| |
| "3": {
| |
| "color": "#FED83D",
| |
| "route": [
| |
| { "SPAWN": "" },
| |
| { "NNCNL": "" },
| |
| { "pos": [0, 4], "stat": "planned" },
| |
| { "INITS": "" },
| |
| { "KEMOW": "" },
| |
| { "UKN03": "" },
| |
| { "YXLAN": "" }
| |
| ],
| |
| "stat": "planned"
| |
| },
| |
| "4": {
| |
| "color": "#169C9C",
| |
| "route": [
| |
| { "HINDA": "" },
| |
| { "UKN01": "" },
| |
| { "KMRPK": "" },
| |
| { "SPAWN": "" },
| |
| { "SCZCT": "" },
| |
| { "BAIZE": "" },
| |
| { "STADM": "" },
| |
| { "UKN02": "" }
| |
| ]
| |
| },
| |
| "4支线": {
| |
| "color": "#169C9C",
| |
| "route": [
| |
| { "STADM": "" },
| |
| { "ACBTF": "" }
| |
| ]
| |
| },
| |
| "5": {
| |
| "color": "#8932B8",
| |
| "route": [
| |
| { "SCZCT": "" },
| |
| { "CZHCT": "" },
| |
| { "XNMCT": "" },
| |
| { "MUYLN": "" },
| |
| { "pos": [-8, 4], "stat": "planned" },
| |
| { "ACBTF": "" },
| |
| { "pos": [-12, 2], "stat": "planned" },
| |
| { "YGHOM": "" },
| |
| { "pos": [-12, 8], "stat": "planned" },
| |
| { "pos": [-14, 8], "stat": "planned" },
| |
| { "SZHCT": "" }
| |
| ]
| |
| },
| |
| "6": {
| |
| "color": "#C74EBD",
| |
| "route": [
| |
| { "QIWAN": "" },
| |
| { "pos": [-6, 12], "stat": "planned" },
| |
| { "ENSHM": "" },
| |
| { "CINDA": "" },
| |
| { "XNMCT": "" },
| |
| { "pos": [-2, 4], "stat": "planned" },
| |
| { "GJHOM": "" },
| |
| { "KEMOW": "" },
| |
| { "UKN03": "" },
| |
| { "KMRPK": "" },
| |
| { "LINDA": "" },
| |
| { "XYHOM": "" },
| |
| { "BREAD": "" },
| |
| { "ICERF": "" }
| |
| ]
| |
| },
| |
| "8": {
| |
| "color": "#5E7C16",
| |
| "route": [
| |
| { "ENSHM": "" },
| |
| { "WNSHM": "" },
| |
| { "pos": [-12, 8], "stat": "planned" },
| |
| { "YGHOM": "" }
| |
| ]
| |
| }
| |
| },
| |
| "stations": {
| |
| "ACBTF": {
| |
| "label": "古战场",
| |
| "pos": [-8, 2],
| |
| "stat": "planned"
| |
| },
| |
| "BAIZE": {
| |
| "label": "白泽",
| |
| "pos": [-4, 0],
| |
| "stat": "planned"
| |
| },
| |
| "BREAD": {
| |
| "label": "面包",
| |
| "pos": [8, -6],
| |
| "stat": "planned"
| |
| },
| |
| "CINDA": {
| |
| "label": "工业区空置域",
| |
| "pos": [-6, 6],
| |
| "stat": "planned"
| |
| },
| |
| "CZHCT": {
| |
| "label": "赐召",
| |
| "pos": [-2, 2],
| |
| "stat": "finished"
| |
| },
| |
| "ENSHM": {
| |
| "label": "满天星家东",
| |
| "pos": [-6, 8],
| |
| "stat": "planned"
| |
| },
| |
| "EYYCT": {
| |
| "label": "漪阳东",
| |
| "pos": [0, -4],
| |
| "stat": "finished"
| |
| },
| |
| "GJHOM": {
| |
| "label": "烧仙草家",
| |
| "pos": [-2, 6],
| |
| "stat": "planned"
| |
| },
| |
| "HINDA": {
| |
| "label": "重工业区",
| |
| "pos": [12, 0],
| |
| "stat": "planned"
| |
| },
| |
| "ICERF": {
| |
| "label": "冰道",
| |
| "pos": [10, -8],
| |
| "stat": "planned"
| |
| },
| |
| "INITS": {
| |
| "label": "元始",
| |
| "pos": [4, 4],
| |
| "stat": "planned"
| |
| },
| |
| "KEMOW": {
| |
| "label": "科魔",
| |
| "pos": [4, 6],
| |
| "stat": "planned"
| |
| },
| |
| "KMRPK": {
| |
| "label": "烟草公园",
| |
| "pos": [8, 0],
| |
| "stat": "planned"
| |
| },
| |
| "LINDA": {
| |
| "label": "轻工业区",
| |
| "pos": [8, -2],
| |
| "stat": "planned"
| |
| },
| |
| "LNYCT": {
| |
| "label": "临漪",
| |
| "pos": [0, -6],
| |
| "stat": "finished"
| |
| },
| |
| "MNTDY": {
| |
| "label": "定漪山",
| |
| "pos": [0, -2],
| |
| "stat": "finished"
| |
| },
| |
| "MUYLN": {
| |
| "label": "暮阳陵",
| |
| "pos": [-6, 4],
| |
| "stat": "planned"
| |
| },
| |
| "NNCNL": {
| |
| "label": "北运河北",
| |
| "pos": [0, 2],
| |
| "stat": "finished"
| |
| },
| |
| "PGNUN": {
| |
| "label": "鸽联",
| |
| "pos": [4, -10],
| |
| "stat": "planned"
| |
| },
| |
| "QIWAN": {
| |
| "label": "绮湾",
| |
| "pos": [-2, 12],
| |
| "stat": "planned"
| |
| },
| |
| "SCZCT": {
| |
| "label": "赐召南",
| |
| "pos": [-2, 0],
| |
| "stat": "planned"
| |
| },
| |
| "SPAWN": {
| |
| "label": "主城",
| |
| "pos": [0, 0],
| |
| "stat": "finished"
| |
| },
| |
| "STADM": {
| |
| "label": "玩家体育场",
| |
| "pos": [-8, 0],
| |
| "stat": "planned"
| |
| },
| |
| "STRHD": {
| |
| "label": "要塞",
| |
| "pos": [6, -6],
| |
| "stat": "planned"
| |
| },
| |
| "SZHCT": {
| |
| "label": "汕州",
| |
| "pos": [-14, 10],
| |
| "stat": "planned"
| |
| },
| |
| "UKN01": {
| |
| "label": "Unknown01",
| |
| "pos": [10, 0],
| |
| "stat": "planned"
| |
| },
| |
| "UKN02": {
| |
| "label": "Unknown02",
| |
| "pos": [-8, -4],
| |
| "stat": "planned"
| |
| },
| |
| "UKN03": {
| |
| "label": "Unknown03",
| |
| "pos": [8, 6],
| |
| "stat": "planned"
| |
| },
| |
| "WNSHM": {
| |
| "label": "满天星家西",
| |
| "pos": [-10, 8],
| |
| "stat": "finished"
| |
| },
| |
| "WTCCT": {
| |
| "label": "天策西",
| |
| "pos": [-2, -6],
| |
| "stat": "finished"
| |
| },
| |
| "WUMIN": {
| |
| "label": "梧鸣",
| |
| "pos": [2, -6],
| |
| "stat": "planned"
| |
| },
| |
| "XJIAN": {
| |
| "label": "薪涧",
| |
| "pos": [4, -8],
| |
| "stat": "planned"
| |
| },
| |
| "XNMCT": {
| |
| "label": "星眸",
| |
| "pos": [-4, 4],
| |
| "stat": "finished"
| |
| },
| |
| "XYHOM": {
| |
| "label": "逍遥家",
| |
| "pos": [8, -4],
| |
| "stat": "planned"
| |
| },
| |
| "YGHOM": {
| |
| "label": "叶光",
| |
| "pos": [-12, 6],
| |
| "stat": "finished"
| |
| },
| |
| "YXLAN": {
| |
| "label": "垭西兰",
| |
| "pos": [8, 8],
| |
| "stat": "planned"
| |
| }
| |
| }
| |
| }
| |
| </script>
| |
| <script>
| |
| const BLACK = "#000000"
| |
| const LIGHTGRAY = "#AAAAAA"
| |
| const WHITE = "#FFFFFF"
| |
| | |
| function canvPos(x, y) {
| |
| x = - Number(minx) + Number(x) + 1
| |
| y = Number(maxy) - Number(y) + 1
| |
| return [Math.round(x), Math.round(y)]
| |
| }
| |
| | |
| function drawMap(mapData, lineGet) {
| |
| // 处理只显示单条的情况
| |
| if(!(lineGet == undefined || mapData["lines"][lineGet] == undefined)) {
| |
| // 处理线路列表
| |
| const lineShow = mapData["lines"][lineGet]
| |
| mapData["lines"] = {}
| |
| mapData["lines"][lineGet] = lineShow
| |
| // 处理站点列表(删除不需要的站点)
| |
| for (let station in mapData.stations) {
| |
| let get = false
| |
| for(let site in mapData["lines"][lineGet]["route"]) {
| |
| if(Object.keys(mapData["lines"][lineGet]["route"][site]) == station) {
| |
| get = true
| |
| break
| |
| }
| |
| }
| |
| if(!get) {
| |
| delete mapData.stations[station]
| |
| }
| |
| }
| |
| }
| |
| // 计算全图大小
| |
| for (let station in mapData.stations) {
| |
| station = mapData.stations[station]
| |
| let [x, y] = station.pos
| |
| maxx = Math.max(maxx, x)
| |
| maxy = Math.max(maxy, y)
| |
| minx = Math.min(minx, x)
| |
| miny = Math.min(miny, y)
| |
| }
| |
| size = Math.max(Math.abs(maxx) + Math.abs(minx), Math.abs(maxy) + Math.abs(miny)) * 0.55
| |
| // 计算中心偏移
| |
| adx = (minx + maxx) / 2
| |
| ady = (miny + maxy) / 2
| |
| // 开始显示
| |
| let links = []
| |
| for (let line in mapData.lines) {
| |
| let lastpoint = undefined
| |
| for (let waypoint in mapData.lines[line].route) {
| |
| waypoint = mapData.lines[line].route[waypoint]
| |
| if (waypoint.pos == undefined) {
| |
| waypoint = mapData.stations[Object.keys(waypoint)[0]]
| |
| }
| |
| else {
| |
| if (waypoint.stat == undefined) { waypoint.stat = "finished" }
| |
| }
| |
| if (lastpoint != undefined) {
| |
| let color = { "finished": mapData.lines[line].color, "planned": LIGHTGRAY }
| |
| let stat = "finished"
| |
| if (waypoint.stat == "planned" || lastpoint.stat == "planned") stat = "planned"
| |
| if (mapData.lines[line].stat == "planned") stat = "planned"
| |
| if (links[[lastpoint.pos, waypoint.pos]] != undefined) {
| |
| links[[lastpoint.pos, waypoint.pos]].push([line, color[stat]])
| |
| }
| |
| else {
| |
| if (links[[waypoint.pos, lastpoint.pos]] != undefined) {
| |
| links[[waypoint.pos, lastpoint.pos]].push([line, color[stat]])
| |
| }
| |
| else links[[lastpoint.pos, waypoint.pos]] = [[line, color[stat]]]
| |
| }
| |
| }
| |
| lastpoint = waypoint
| |
| }
| |
| }
| |
| | |
| /* Draw lines */
| |
| // 构建线条图层
| |
| const gLine = document.createElementNS('http://www.w3.org/2000/svg','g')
| |
| gLine.id = "LineList"
| |
| gLine.style.transform = "translateX(" + adx / size * 50 + "%)"
| |
| gLine.style.transform = "translateY(" + ady / size * 50 + "%)"
| |
| for (let link in links) {
| |
| let [x1, y1, x2, y2] = link.split(",")
| |
| let linklen = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
| |
| linkInfo = links[link]
| |
| for (let rail in linkInfo) {
| |
| let dl = (rail - (linkInfo.length - 1) / 2) * 0.25
| |
| let [dx, dy] = [- (y2 - y1) / linklen * dl, (x2 - x1) / linklen * dl]
| |
| let [startx, starty] = [
| |
| 50 + (Number(x1) / size * 50) + "%",
| |
| 50 - (Number(y1) / size * 50) + "%"
| |
| ]
| |
| let [stopx, stopy] = [
| |
| 50 + (Number(x2) / size * 50) + "%",
| |
| 50 - (Number(y2) / size * 50) + "%"
| |
| ]
| |
| | |
| const line = document.createElementNS('http://www.w3.org/2000/svg','line')
| |
| line.dataset.raw = link
| |
| line.dataset.name = linkInfo[rail][0]
| |
| line.setAttribute("x1", startx)
| |
| line.setAttribute("y1", starty)
| |
| line.setAttribute("x2", stopx)
| |
| line.setAttribute("y2", stopy)
| |
| line.style.strokeWidth = "0.25rem"
| |
| line.style.strokeLinecap = "round"
| |
| line.style.stroke = linkInfo[rail][1]
| |
| line.style.transition = "stroke-width .3s"
| |
| // 偏移
| |
| let move = ""
| |
| if(dx > 0) {
| |
| move += "translateX(0.15rem) "
| |
| } else if(dx < 0) {
| |
| move += "translateX(-0.15rem) "
| |
| }
| |
| if(dy > 0) {
| |
| move += "translateY(0.15rem) "
| |
| } else if(dy < 0) {
| |
| move += "translateY(-0.15rem) "
| |
| }
| |
| line.style.transform = move
| |
| | |
| // 鼠标事件
| |
| line.onmouseover = function() { onLineHover(line) }
| |
| line.onmouseleave = function() { onLineLeave(line) }
| |
| | |
| if(gLine.children.length == 0) {
| |
| gLine.append(line)
| |
| } else {
| |
| gLine.insertBefore(line, gLine.firstChild)
| |
| }
| |
| }
| |
| }
| |
| this.append(gLine)
| |
| | |
| | |
| /* Draw stations */
| |
| // 构建站点图层
| |
| const gSite = document.createElementNS('http://www.w3.org/2000/svg','g')
| |
| gSite.style.transform = "translateX(" + adx / size * 50 + "%)"
| |
| gSite.style.transform = "translateY(" + ady / size * 50 + "%)"
| |
| for (let station in mapData.stations) {
| |
| station = mapData.stations[station]
| |
| let stationColor = BLACK
| |
| if (station.stat == "planned") stationColor = LIGHTGRAY
| |
| let name = station.label
| |
| let [x, y] = station.pos
| |
| | |
| // <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
| |
| const point = document.createElementNS('http://www.w3.org/2000/svg','circle')
| |
| point.dataset.raw = station.pos
| |
| point.setAttribute("cx", 50 + (Number(x) / size * 50) + "%")
| |
| point.setAttribute("cy", 50 - (Number(y) / size * 50) + "%")
| |
| point.style.transition = "r .3s, stroke-width .3s"
| |
| point.style.r = "0.5rem"
| |
| point.style.fill = WHITE
| |
| point.style.stroke = stationColor
| |
| point.style.strokeWidth = "0.2rem"
| |
| | |
| point.onmouseover = function() { onPointOver(point) }
| |
| point.onmouseleave = function() { onPointLeace(point) }
| |
| | |
| // <text x="0" y="15" fill="red">I love SVG</text>
| |
| const text = document.createElementNS('http://www.w3.org/2000/svg','text')
| |
| text.setAttribute("x", 50 + (Number(x) / size * 50) + "%")
| |
| text.setAttribute("y", 50 - (Number(y) / size * 50) + "%")
| |
| text.style.transform = "translateX(0.7rem) translateY(-0.7rem)"
| |
| text.style.fontSize = "0.6rem"
| |
| text.style.fill = BLACK
| |
| text.innerHTML = name
| |
| | |
| if(gSite.children.length == 0) {
| |
| gSite.append(point)
| |
| gSite.append(text)
| |
| } else {
| |
| gSite.insertBefore(point, gSite.firstChild)
| |
| gSite.insertBefore(text, gSite.firstChild)
| |
| }
| |
| }
| |
| this.append(gSite)
| |
| }
| |
| | |
| // 整图大小
| |
| let minx = 0, miny = 0, maxx = 0, maxy = 0, size = 0, adx = 0, ady = 0, view = 900
| |
| | |
| // 初始化
| |
| const div = document.getElementById("MainMap") // SVG 框架
| |
| // 生成 SVG
| |
| // <svg width="100vh" height="100%" view-box="0 0 2048 2048">
| |
| window.mainMap = document.createElementNS('http://www.w3.org/2000/svg','svg')
| |
| mainMap.setAttribute('version','1.1')
| |
| mainMap.setAttribute("viewBox", "0 0 " + view + " " + view)
| |
| mainMap.setAttribute("preserveAspectRatio", "xMidYMid meet")
| |
| mainMap.style.width = '100vh'
| |
| mainMap.style.height = '100%'
| |
| | |
| mainMap.drawMap = drawMap
| |
| mainMap.drawMap(dataset)
| |
| | |
| div.append(mainMap)
| |
| </script>
| |
| <script>
| |
| // 线段悬停事件
| |
| function onLineHover(sender) {
| |
| // 线名
| |
| const name = sender.dataset.name
| |
| // 寻找所有线段
| |
| const list = document.getElementById("LineList").children
| |
| for(let i=0; i<=list.length; i++) {
| |
| if(!(list[i] == undefined || list[i].dataset.name != name)) {
| |
| list[i].style.strokeWidth = "0.4rem"
| |
| }
| |
| }
| |
| }
| |
| function onLineLeave(sender) {
| |
| // 线名
| |
| const name = sender.dataset.name
| |
| // 寻找所有线段
| |
| const list = document.getElementById("LineList").children
| |
| for(let i=0; i<=list.length; i++) {
| |
| if(!(list[i] == undefined || list[i].dataset.name != name)) {
| |
| list[i].style.strokeWidth = "0.25rem"
| |
| }
| |
| }
| |
| }
| |
| | |
| // 站点悬停事件
| |
| function onPointOver(sender) {
| |
| sender.style.r = "1px"
| |
| sender.style.strokeWidth = "1rem"
| |
| }
| |
| function onPointLeace(sender) {
| |
| sender.style.r = "0.5rem"
| |
| sender.style.strokeWidth = "0.2rem"
| |
| }
| |
| </script>
| |
| </body>
| |
| | |
| </html> | |