[
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"i18n-ally.localesPaths\": [\"src/i18n/locales\"],\n  \"i18n-ally.extract.autoDetect\": true,\n  \"i18n-ally.keystyle\": \"nested\",\n  \"i18n-ally.sourceLanguage\": \"zh\",\n  \"i18n-ally.displayLanguage\": \"zh\",\n  \"i18n-ally.extract.ignored\": [\n    \"“\\n              \",\n    \"”\\n            \",\n    \"”\\n            \",\n    \"\\n              重做\\n            \",\n    \".title .click-panel\",\n    \".title .click-panel\"\n  ],\n  \"i18n-ally.extract.ignoredByFiles\": {\n    \"src/WelcomeTour/WelcomeTour.tsx\": [\n      \".welcome-tour .body\"\n    ]\n  }\n}\n"
  },
  {
    "path": "README-cn.md",
    "content": "\n<img  style=\"border-radius: 5px\" width=\"50\" src=\"https://mini-metro-web.gitlab.io/app-icon.png\">\n\n# Mini Metro Web \n迷你地铁地图构建工具: `创建迷你地铁风格的地铁线路图`。\n\n支持**无限**站点与线路，支持**多次穿过**同一站点，设置**背景图**，设置**支线**，支持**导出图片**。\n   \n[https://mini-metro-web.gitlab.io/](https://mini-metro-web.gitlab.io/)\n\n[English Version](https://github.com/RyanEdo/mini-metro-web/blob/master/README.md)\n\n\n## 更新日志\n#### 1.2.1 `修复添加站点时，连续双击站点导致的站点重复添加报错` \n#### 1.2.0 `支持英文` \n#### 1.1.1 `增加更多站点形状，新增站点时支持修改默认形状` \n#### 1.1.0 `支持修改背景颜色与背景图`  \n#### 1.0.2 `加入刷新后快速恢复通知`  \n#### 1.0.1 `加入报错指引`  \n\n\n##  基本用法\n\n### 菜单\n点击左上角标题进入菜单，点击任意空白处退出菜单\n\n### 创建站点\n 1. 菜单 => 站点 => 添加站点\n 2. 点击空白处添加\n\n### 创建线路\n1. 点击任意站点\n2. 选择 操作 => 以此为起点新建线路\n3. 按照提示依次点击站点添加到线路\n\n### 删除站点/线路\n1. 点击站点/线路\n2. 选择 操作 => 删除\n\n### 设置背景图\n1. 点击线路 => 设定背景\n2. 选择 `纯白` / `浅黄` / `取色器` 设定背景颜色\n3. 选择 `导入背景图` 导入图片\n4. 导入图片后，进入修改图片页面，可以拖动修改图片位置，也可以修改图片透明度\n\n### 导出图片/文件\n菜单 => 作为图片/文件导出\n\n## 进阶用法\n请参考应用内教程或[视频教程](https://space.bilibili.com/8217854)\n\n## 构建\n\n和大部分react项目一样，先运行`npm i`,然后:\n\n### `npm start`\n\n本地运行\n打开 [http://localhost:3000](http://localhost:3000) 浏览器中查看.\n\n### `npm run build`\n\n打包成静态文件\n\n### 注意\n##### 建议安装 `i18n-ally`[VS Code 插件地址](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 。项目有部分字符串由该插件生成，安装后能自动在字符串位置显示原文。"
  },
  {
    "path": "README.md",
    "content": "\n<img  style=\"border-radius: 5px\" width=\"50\" src=\"https://mini-metro-web.gitlab.io/app-icon.png\">\n\n# Mini Metro Web \nMini Metro Map Building Tool: `Create mini metro-style subway maps`.\n\nSupports **unlimited** stations and lines, supports **multiple crossings** of the same station, set **background images**, set **sub lines**, and supports **exporting images**.\n\nhttps://mini-metro-web.gitlab.io/\n\n[中文文档](https://github.com/RyanEdo/mini-metro-web/blob/master/README-cn.md)\n\n## Changelog\n#### 1.2.1 `fix adding duplicate stations when double clicking at adding station mode`\n#### 1.2.0 `Support for English`\n#### 1.1.1 `Added more station shapes, support for modifying default shapes when adding new stations`\n#### 1.1.0 `Support for changing background color and background image`\n#### 1.0.2 `Added quick recovery notification after refresh`\n#### 1.0.1 `Added error guidance`\n\n## Basic Usage\n\n### Menu\nClick the title in the top left corner to enter the menu, click any blank area to exit the menu.\n\n### Create Station\n1. Menu => Station => Add Station\n2. Click on a blank area to add\n\n### Create Line\n1. Click any station\n2. Select Action => Create new line from this point\n3. Follow the prompts to click stations in sequence to add them to the line\n\n### Delete Station/Line\n1. Click the station/line\n2. Select Action => Delete\n\n### Set Background Image\n1. Click the line => Set background\n2. Choose `Pure White` / `Light Yellow` / `Color Picker` to set the background color\n3. Choose `Import Background Image` to import an image\n4. After importing the image, enter the image editing page, where you can drag to adjust the image position and modify the image transparency\n\n### Export Image/File\nMenu => Export as image/file\n\n## Advanced Usage\nPlease refer to the in-app tutorial or video tutorial\n\n## Build\n\nLike most React projects, first run `npm i`, then:\n\n### `npm start`\n\nRun locally\nOpen http://localhost:3000 to view in the browser.\n\n### `npm run build`\n\nBuild into static files\n\n### Note\n##### It is recommended to install the `i18n-ally` VS Code plugin. Some strings in the project are generated by this plugin, and after installation, the original text will be automatically displayed at the string location.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mini-metro-web\",\n  \"version\": \"1.2.1\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@svgr/webpack\": \"^8.1.0\",\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^13.4.0\",\n    \"@testing-library/user-event\": \"^13.5.0\",\n    \"@types/downloadjs\": \"^1.4.6\",\n    \"classnames\": \"^2.5.1\",\n    \"downloadjs\": \"^1.4.7\",\n    \"driver.js\": \"^1.3.1\",\n    \"html-to-image\": \"^1.11.11\",\n    \"i18next\": \"^23.16.3\",\n    \"i18next-browser-languagedetector\": \"^8.0.0\",\n    \"moment\": \"^2.30.1\",\n    \"qrcode\": \"^1.5.3\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-error-boundary\": \"^4.0.13\",\n    \"react-i18next\": \"^15.1.0\",\n    \"react-scripts\": \"5.0.1\",\n    \"sass\": \"^1.62.0\",\n    \"ua-parser-js\": \"^1.0.37\",\n    \"web-vitals\": \"^2.1.4\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@types/qrcode\": \"^1.5.5\",\n    \"@types/ua-parser-js\": \"^0.7.39\"\n  }\n}\n"
  },
  {
    "path": "public/beijing.json",
    "content": "{\"title\":\"北京\",\"stations\":[{\"stationId\":1,\"stationName\":\"苹果园\",\"position\":[2056,3189],\"shape\":\"cicle\",\"lineIds\":[1,6]},{\"stationId\":2,\"stationName\":\"金安桥\",\"position\":[1892,3213],\"shape\":\"cicle\",\"lineIds\":[1,6,11]},{\"stationId\":3,\"stationName\":\"四道桥\",\"position\":[1606,3286],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":4,\"stationName\":\"桥户营\",\"position\":[1524,3322],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":5,\"stationName\":\"上岸\",\"position\":[1488,3395],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":6,\"stationName\":\"栗园庄\",\"position\":[1499,3488],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":7,\"stationName\":\"小园\",\"position\":[1410,3542],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":3},{\"stationId\":8,\"stationName\":\"石厂\",\"position\":[1269,3552],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":9,\"stationName\":\"古城\",\"position\":[2169,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":10,\"stationName\":\"八角游乐园\",\"position\":[2393,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":11,\"stationName\":\"八宝山\",\"position\":[2626,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":12,\"stationName\":\"玉泉路\",\"position\":[2795,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":13,\"stationName\":\"五棵松\",\"position\":[3006,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":14,\"stationName\":\"万寿路\",\"position\":[3214,3372],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":15,\"stationName\":\"公主坟\",\"position\":[3365,3372],\"shape\":\"cicle\",\"lineIds\":[2,10]},{\"stationId\":16,\"stationName\":\"军事博物馆\",\"position\":[3481,3372],\"shape\":\"cicle\",\"lineIds\":[2,9]},{\"stationId\":17,\"stationName\":\"木樨地\",\"position\":[3642,3372],\"shape\":\"cicle\",\"lineIds\":[2,15],\"tagDirection\":3},{\"stationId\":18,\"stationName\":\"南礼士路\",\"position\":[3792,3374],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":7},{\"stationId\":19,\"stationName\":\"复兴门\",\"position\":[3835,3374],\"shape\":\"cicle\",\"lineIds\":[2,3],\"tagDirection\":5},{\"stationId\":20,\"stationName\":\"西单\",\"position\":[4007,3372],\"shape\":\"cicle\",\"lineIds\":[2,4]},{\"stationId\":21,\"stationName\":\"天安门西\",\"position\":[4179,3372],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":22,\"stationName\":\"天安门东\",\"position\":[4278,3368],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":23,\"stationName\":\"王府井\",\"position\":[4382,3366],\"shape\":\"cicle\",\"lineIds\":[2,8],\"tagDirection\":4},{\"stationId\":24,\"stationName\":\"东单\",\"position\":[4451,3363],\"shape\":\"cicle\",\"lineIds\":[2,5],\"tagDirection\":1},{\"stationId\":25,\"stationName\":\"建国门\",\"position\":[4624,3361],\"shape\":\"cicle\",\"lineIds\":[2,3],\"tagDirection\":1},{\"stationId\":26,\"stationName\":\"永安里\",\"position\":[4771,3362],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":27,\"stationName\":\"国贸\",\"position\":[4884,3355],\"shape\":\"cicle\",\"lineIds\":[2,10],\"tagDirection\":1},{\"stationId\":28,\"stationName\":\"大望路\",\"position\":[5024,3363],\"shape\":\"cicle\",\"lineIds\":[2,13],\"tagDirection\":1},{\"stationId\":29,\"stationName\":\"四惠\",\"position\":[5221,3359],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":30,\"stationName\":\"四惠东\",\"position\":[5423,3361],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":31,\"stationName\":\"高碑店\",\"position\":[5580,3352],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":32,\"stationName\":\"传媒大学\",\"position\":[5812,3354],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":33,\"stationName\":\"双桥\",\"position\":[6034,3345],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":34,\"stationName\":\"管庄\",\"position\":[6256,3355],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":35,\"stationName\":\"八里桥\",\"position\":[6453,3385],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":36,\"stationName\":\"通州北苑\",\"position\":[6639,3408],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":37,\"stationName\":\"果园\",\"position\":[6732,3513],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":38,\"stationName\":\"九棵树\",\"position\":[6841,3543],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":39,\"stationName\":\"梨园\",\"position\":[6953,3609],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":40,\"stationName\":\"临河里\",\"position\":[7054,3691],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":41,\"stationName\":\"土桥\",\"position\":[7130,3727],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":42,\"stationName\":\"花庄\",\"position\":[7221,3879],\"shape\":\"cicle\",\"lineIds\":[2,7]},{\"stationId\":43,\"stationName\":\"环球度假区\",\"position\":[7057,3955],\"shape\":\"cicle\",\"lineIds\":[2,7]},{\"stationId\":44,\"stationName\":\"积水潭\",\"position\":[3997,2960],\"shape\":\"cicle\",\"lineIds\":[3,18],\"tagDirection\":1},{\"stationId\":45,\"stationName\":\"鼓楼大街\",\"position\":[4204,2957],\"shape\":\"cicle\",\"lineIds\":[3,8]},{\"stationId\":46,\"stationName\":\"安定门\",\"position\":[4348,2954],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":47,\"stationName\":\"雍和宫\",\"position\":[4437,2953],\"shape\":\"cicle\",\"lineIds\":[3,5]},{\"stationId\":48,\"stationName\":\"东直门\",\"position\":[4624,3030],\"shape\":\"cicle\",\"lineIds\":[3,12,22],\"tagDirection\":7},{\"stationId\":49,\"stationName\":\"东四十条\",\"position\":[4607,3108],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":3},{\"stationId\":50,\"stationName\":\"朝阳门\",\"position\":[4612,3201],\"shape\":\"cicle\",\"lineIds\":[3,6],\"tagDirection\":7},{\"stationId\":51,\"stationName\":\"北京站\",\"position\":[4539,3396],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":52,\"stationName\":\"崇文门\",\"position\":[4437,3436],\"shape\":\"cicle\",\"lineIds\":[3,5],\"tagDirection\":5},{\"stationId\":53,\"stationName\":\"前门\",\"position\":[4245,3444],\"shape\":\"cicle\",\"lineIds\":[3,8],\"tagDirection\":5},{\"stationId\":54,\"stationName\":\"和平门\",\"position\":[4108,3445],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":4},{\"stationId\":55,\"stationName\":\"宣武门\",\"position\":[4009,3449],\"shape\":\"cicle\",\"lineIds\":[3,4],\"tagDirection\":5},{\"stationId\":56,\"stationName\":\"长椿街\",\"position\":[3900,3452],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":57,\"stationName\":\"阜成门\",\"position\":[3826,3209],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":58,\"stationName\":\"车公庄\",\"position\":[3810,3122],\"shape\":\"cicle\",\"lineIds\":[3,6]},{\"stationId\":59,\"stationName\":\"西直门\",\"position\":[3820,3041],\"shape\":\"cicle\",\"lineIds\":[3,4,12]},{\"stationId\":60,\"stationName\":\"天宫院\",\"position\":[3465,5743],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":61,\"stationName\":\"生物医药基地\",\"position\":[3483,5581],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":62,\"stationName\":\"义和庄\",\"position\":[3457,5322],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":63,\"stationName\":\"黄村火车站\",\"position\":[3592,5217],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":64,\"stationName\":\"黄村西大街\",\"position\":[3592,5129],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":65,\"stationName\":\"清源路\",\"position\":[3591,5019],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":66,\"stationName\":\"枣园\",\"position\":[3588,4912],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":67,\"stationName\":\"高米店南\",\"position\":[3582,4811],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":68,\"stationName\":\"高米店北\",\"position\":[3574,4711],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":69,\"stationName\":\"西红门\",\"position\":[3553,4548],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":70,\"stationName\":\"新宫\",\"position\":[3922,4320],\"shape\":\"cicle\",\"lineIds\":[4,18]},{\"stationId\":71,\"stationName\":\"公益西桥\",\"position\":[3974,4085],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":2},{\"stationId\":72,\"stationName\":\"角门西\",\"position\":[3978,3988],\"shape\":\"cicle\",\"lineIds\":[4,10]},{\"stationId\":73,\"stationName\":\"马家堡\",\"position\":[3980,3915],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":74,\"stationName\":\"北京南站\",\"position\":[4056,3796],\"shape\":\"cicle\",\"lineIds\":[4,13],\"tagDirection\":1},{\"stationId\":75,\"stationName\":\"陶然亭\",\"position\":[4010,3662],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":76,\"stationName\":\"菜市口\",\"position\":[4010,3553],\"shape\":\"cicle\",\"lineIds\":[4,7],\"tagDirection\":5},{\"stationId\":77,\"stationName\":\"灵境胡同\",\"position\":[4004,3287],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":78,\"stationName\":\"西四\",\"position\":[3999,3204],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":79,\"stationName\":\"平安里\",\"position\":[3995,3107],\"shape\":\"cicle\",\"lineIds\":[4,6,18]},{\"stationId\":80,\"stationName\":\"新街口\",\"position\":[3943,3040],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":7},{\"stationId\":81,\"stationName\":\"动物园\",\"position\":[3656,3064],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":1},{\"stationId\":82,\"stationName\":\"国家图书馆\",\"position\":[3518,3015],\"shape\":\"cicle\",\"lineIds\":[4,9,15]},{\"stationId\":83,\"stationName\":\"魏公村\",\"position\":[3498,2867],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":84,\"stationName\":\"人民大学\",\"position\":[3480,2777],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":85,\"stationName\":\"海淀黄庄\",\"position\":[3442,2686],\"shape\":\"cicle\",\"lineIds\":[4,10],\"tagDirection\":5},{\"stationId\":86,\"stationName\":\"中关村\",\"position\":[3431,2606],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":87,\"stationName\":\"北京大学东门\",\"position\":[3424,2524],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":88,\"stationName\":\"圆明园\",\"position\":[3368,2450],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":89,\"stationName\":\"西苑\",\"position\":[3175,2464],\"shape\":\"cicle\",\"lineIds\":[4,15]},{\"stationId\":90,\"stationName\":\"北宫门\",\"position\":[3043,2423],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":91,\"stationName\":\"安河桥北\",\"position\":[2966,2324],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":92,\"stationName\":\"宋家庄\",\"position\":[4550,3988],\"shape\":\"cicle\",\"lineIds\":[5,10,25],\"tagDirection\":5},{\"stationId\":93,\"stationName\":\"刘家窑\",\"position\":[4487,3871],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":94,\"stationName\":\"蒲黄榆\",\"position\":[4497,3790],\"shape\":\"cicle\",\"lineIds\":[5,13],\"tagDirection\":1},{\"stationId\":95,\"stationName\":\"天坛东门\",\"position\":[4474,3621],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":96,\"stationName\":\"磁器口\",\"position\":[4465,3515],\"shape\":\"cicle\",\"lineIds\":[5,7],\"tagDirection\":5},{\"stationId\":97,\"stationName\":\"灯市口\",\"position\":[4444,3275],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":98,\"stationName\":\"东四\",\"position\":[4441,3203],\"shape\":\"cicle\",\"lineIds\":[5,6],\"tagDirection\":3},{\"stationId\":99,\"stationName\":\"张自忠路\",\"position\":[4438,3110],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":100,\"stationName\":\"北新桥\",\"position\":[4435,3038],\"shape\":\"cicle\",\"lineIds\":[5,22]},{\"stationId\":101,\"stationName\":\"和平里北街\",\"position\":[4451,2859],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":102,\"stationName\":\"和平西桥\",\"position\":[4446,2762],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":103,\"stationName\":\"惠新西街南口\",\"position\":[4441,2675],\"shape\":\"cicle\",\"lineIds\":[5,10],\"tagDirection\":1},{\"stationId\":104,\"stationName\":\"惠新西街北口\",\"position\":[4436,2568],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":105,\"stationName\":\"大屯路东\",\"position\":[4440,2408],\"shape\":\"cicle\",\"lineIds\":[5,14],\"tagDirection\":7},{\"stationId\":106,\"stationName\":\"北苑路北\",\"position\":[4447,2142],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":107,\"stationName\":\"立水桥南\",\"position\":[4411,2027],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":108,\"stationName\":\"立水桥\",\"position\":[4390,1916],\"shape\":\"cicle\",\"lineIds\":[5,12]},{\"stationId\":109,\"stationName\":\"天通苑南\",\"position\":[4393,1782],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":110,\"stationName\":\"天通苑\",\"position\":[4394,1694],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":111,\"stationName\":\"天通苑北\",\"position\":[4395,1610],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":112,\"stationName\":\"潞城\",\"position\":[7740,3420],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":113,\"stationName\":\"东夏园\",\"position\":[7605,3415],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":0},{\"stationId\":114,\"stationName\":\"郝家府\",\"position\":[7444,3414],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":115,\"stationName\":\"北运河东\",\"position\":[7337,3414],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":0},{\"stationId\":116,\"stationName\":\"北运河西\",\"position\":[7150,3416],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":117,\"stationName\":\"通州北关\",\"position\":[6877,3267],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":118,\"stationName\":\"物资学院路\",\"position\":[6659,3178],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":119,\"stationName\":\"草房\",\"position\":[6422,3201],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":120,\"stationName\":\"常营\",\"position\":[6263,3189],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":0},{\"stationId\":121,\"stationName\":\"黄渠\",\"position\":[6049,3204],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":0},{\"stationId\":122,\"stationName\":\"褡裢坡\",\"position\":[5906,3206],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":123,\"stationName\":\"青年路\",\"position\":[5440,3215],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":124,\"stationName\":\"十里堡\",\"position\":[5286,3215],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":125,\"stationName\":\"金台路\",\"position\":[5047,3211],\"shape\":\"cicle\",\"lineIds\":[6,13],\"tagDirection\":7},{\"stationId\":126,\"stationName\":\"呼家楼\",\"position\":[4882,3213],\"shape\":\"cicle\",\"lineIds\":[6,10],\"tagDirection\":7},{\"stationId\":127,\"stationName\":\"东大桥\",\"position\":[4783,3216],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":128,\"stationName\":\"南锣鼓巷\",\"position\":[4308,3108],\"shape\":\"cicle\",\"lineIds\":[6,8],\"tagDirection\":1},{\"stationId\":129,\"stationName\":\"北海北\",\"position\":[4134,3114],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":130,\"stationName\":\"车公庄西\",\"position\":[3707,3122],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":4},{\"stationId\":131,\"stationName\":\"二里沟\",\"position\":[3603,3122],\"shape\":\"cicle\",\"lineIds\":[6,15]},{\"stationId\":132,\"stationName\":\"白石桥南\",\"position\":[3523,3116],\"shape\":\"cicle\",\"lineIds\":[6,9],\"tagDirection\":7},{\"stationId\":133,\"stationName\":\"花园桥\",\"position\":[3373,3123],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":134,\"stationName\":\"慈寿寺\",\"position\":[3221,3114],\"shape\":\"cicle\",\"lineIds\":[6,10],\"tagDirection\":5},{\"stationId\":135,\"stationName\":\"海淀五路居\",\"position\":[3031,3120],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":136,\"stationName\":\"田村\",\"position\":[2795,3151],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":137,\"stationName\":\"廖公庄\",\"position\":[2539,3122],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":138,\"stationName\":\"西黄村\",\"position\":[2335,3110],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":139,\"stationName\":\"杨庄\",\"position\":[2136,3168],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":3},{\"stationId\":140,\"stationName\":\"高楼金\",\"position\":[7109,3815],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":141,\"stationName\":\"群芳\",\"position\":[6974,3811],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":142,\"stationName\":\"万盛东\",\"position\":[6840,3811],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":0},{\"stationId\":143,\"stationName\":\"万盛西\",\"position\":[6588,3813],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":144,\"stationName\":\"黑庄户\",\"position\":[6257,3859],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":145,\"stationName\":\"郎辛庄\",\"position\":[5964,3881],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":146,\"stationName\":\"黄厂\",\"position\":[5804,3956],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":147,\"stationName\":\"焦化厂\",\"position\":[5639,3891],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":148,\"stationName\":\"双合\",\"position\":[5534,3849],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":149,\"stationName\":\"垡头\",\"position\":[5384,3839],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":150,\"stationName\":\"欢乐谷景区\",\"position\":[5267,3781],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":151,\"stationName\":\"南楼梓庄\",\"position\":[5277,3700],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":152,\"stationName\":\"化工\",\"position\":[5300,3573],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":153,\"stationName\":\"百子湾\",\"position\":[5244,3521],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":154,\"stationName\":\"大郊亭\",\"position\":[5145,3514],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":155,\"stationName\":\"九龙山\",\"position\":[5055,3514],\"shape\":\"cicle\",\"lineIds\":[7,13],\"tagDirection\":7},{\"stationId\":156,\"stationName\":\"双井\",\"position\":[4884,3511],\"shape\":\"cicle\",\"lineIds\":[7,10],\"tagDirection\":7},{\"stationId\":157,\"stationName\":\"广渠门外\",\"position\":[4756,3510],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":158,\"stationName\":\"广渠门内\",\"position\":[4605,3510],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":0},{\"stationId\":159,\"stationName\":\"桥湾\",\"position\":[4351,3519],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":160,\"stationName\":\"珠市口\",\"position\":[4250,3533],\"shape\":\"cicle\",\"lineIds\":[7,8]},{\"stationId\":161,\"stationName\":\"虎坊桥\",\"position\":[4112,3551],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":3},{\"stationId\":162,\"stationName\":\"广安门内\",\"position\":[3848,3552],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":163,\"stationName\":\"达官营\",\"position\":[3622,3547],\"shape\":\"cicle\",\"lineIds\":[7,15]},{\"stationId\":164,\"stationName\":\"湾子\",\"position\":[3544,3547],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":165,\"stationName\":\"北京西站\",\"position\":[3478,3499],\"shape\":\"cicle\",\"lineIds\":[7,9],\"tagDirection\":1},{\"stationId\":166,\"stationName\":\"瀛海\",\"position\":[4756,4839],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":167,\"stationName\":\"德茂\",\"position\":[4681,4720],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":168,\"stationName\":\"五福堂\",\"position\":[4505,4596],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":169,\"stationName\":\"火箭万源\",\"position\":[4452,4453],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":170,\"stationName\":\"东高地\",\"position\":[4360,4396],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":171,\"stationName\":\"和义\",\"position\":[4287,4298],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":172,\"stationName\":\"大红门南\",\"position\":[4276,4079],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":173,\"stationName\":\"海户屯\",\"position\":[4269,3928],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":174,\"stationName\":\"木樨园\",\"position\":[4264,3854],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":175,\"stationName\":\"永定门外\",\"position\":[4260,3772],\"shape\":\"cicle\",\"lineIds\":[8,13]},{\"stationId\":176,\"stationName\":\"天桥\",\"position\":[4253,3627],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":177,\"stationName\":\"金鱼胡同\",\"position\":[4378,3292],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":6},{\"stationId\":178,\"stationName\":\"中国美术馆\",\"position\":[4374,3209],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":6},{\"stationId\":179,\"stationName\":\"什刹海\",\"position\":[4228,3070],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":180,\"stationName\":\"安德里北街\",\"position\":[4218,2874],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":181,\"stationName\":\"安华桥\",\"position\":[4213,2761],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":182,\"stationName\":\"北土城\",\"position\":[4208,2677],\"shape\":\"cicle\",\"lineIds\":[8,10],\"tagDirection\":1},{\"stationId\":183,\"stationName\":\"奥体中心\",\"position\":[4204,2588],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":184,\"stationName\":\"奥林匹克公园\",\"position\":[4184,2424],\"shape\":\"cicle\",\"lineIds\":[8,14],\"tagDirection\":5},{\"stationId\":185,\"stationName\":\"森林公园南门\",\"position\":[4192,2345],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":186,\"stationName\":\"林萃桥\",\"position\":[3996,2227],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":187,\"stationName\":\"永泰庄\",\"position\":[3812,2069],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":188,\"stationName\":\"西小口\",\"position\":[3782,1978],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":189,\"stationName\":\"育新\",\"position\":[3739,1846],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":190,\"stationName\":\"霍营\",\"position\":[3869,1728],\"shape\":\"cicle\",\"lineIds\":[8,12]},{\"stationId\":191,\"stationName\":\"回龙观东大街\",\"position\":[3896,1634],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":192,\"stationName\":\"平西府\",\"position\":[3770,1540],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":193,\"stationName\":\"育知路\",\"position\":[3536,1568],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":194,\"stationName\":\"朱辛庄\",\"position\":[3403,1403],\"shape\":\"cicle\",\"lineIds\":[8,19]},{\"stationId\":195,\"stationName\":\"郭公庄\",\"position\":[3285,4303],\"shape\":\"cicle\",\"lineIds\":[9,21]},{\"stationId\":196,\"stationName\":\"丰台科技园\",\"position\":[3238,4194],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":197,\"stationName\":\"科怡路\",\"position\":[3240,4121],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":198,\"stationName\":\"丰台南路\",\"position\":[3232,4035],\"shape\":\"cicle\",\"lineIds\":[9,15]},{\"stationId\":199,\"stationName\":\"丰台东大街\",\"position\":[3205,3895],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":200,\"stationName\":\"七里庄\",\"position\":[3209,3776],\"shape\":\"cicle\",\"lineIds\":[9,13]},{\"stationId\":201,\"stationName\":\"六里桥\",\"position\":[3294,3644],\"shape\":\"cicle\",\"lineIds\":[9,10]},{\"stationId\":202,\"stationName\":\"六里桥东\",\"position\":[3417,3577],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":203,\"stationName\":\"白堆子\",\"position\":[3524,3208],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":6},{\"stationId\":204,\"stationName\":\"巴沟\",\"position\":[3200,2702],\"shape\":\"cicle\",\"lineIds\":[10,23],\"tagDirection\":6},{\"stationId\":205,\"stationName\":\"苏州街\",\"position\":[3329,2690],\"shape\":\"cicle\",\"lineIds\":[10,15],\"tagDirection\":5},{\"stationId\":206,\"stationName\":\"知春里\",\"position\":[3553,2683],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":207,\"stationName\":\"知春路\",\"position\":[3666,2681],\"shape\":\"cicle\",\"lineIds\":[10,12]},{\"stationId\":208,\"stationName\":\"西土城\",\"position\":[3809,2683],\"shape\":\"cicle\",\"lineIds\":[10,19],\"tagDirection\":1},{\"stationId\":209,\"stationName\":\"牡丹园\",\"position\":[3964,2680],\"shape\":\"cicle\",\"lineIds\":[10,18],\"tagDirection\":1},{\"stationId\":210,\"stationName\":\"健德门\",\"position\":[4080,2679],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":1},{\"stationId\":211,\"stationName\":\"安贞门\",\"position\":[4326,2676],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":1},{\"stationId\":212,\"stationName\":\"芍药居\",\"position\":[4625,2670],\"shape\":\"cicle\",\"lineIds\":[10,12]},{\"stationId\":213,\"stationName\":\"太阳宫\",\"position\":[4749,2709],\"shape\":\"cicle\",\"lineIds\":[10,17]},{\"stationId\":214,\"stationName\":\"三元桥\",\"position\":[4836,2831],\"shape\":\"cicle\",\"lineIds\":[10,22]},{\"stationId\":215,\"stationName\":\"亮马桥\",\"position\":[4884,2952],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":216,\"stationName\":\"农业展览馆\",\"position\":[4883,3033],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":217,\"stationName\":\"团结湖\",\"position\":[4884,3109],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":218,\"stationName\":\"金台夕照\",\"position\":[4883,3278],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":219,\"stationName\":\"劲松\",\"position\":[4879,3602],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":220,\"stationName\":\"潘家园\",\"position\":[4875,3692],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":221,\"stationName\":\"十里河\",\"position\":[4847,3785],\"shape\":\"cicle\",\"lineIds\":[10,13,16],\"tagDirection\":1},{\"stationId\":222,\"stationName\":\"分钟寺\",\"position\":[4806,3924],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":223,\"stationName\":\"成寿寺\",\"position\":[4741,3987],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":7},{\"stationId\":224,\"stationName\":\"石榴庄\",\"position\":[4407,3987],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":4},{\"stationId\":225,\"stationName\":\"大红门\",\"position\":[4258,3992],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":5},{\"stationId\":226,\"stationName\":\"角门东\",\"position\":[4123,3995],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":4},{\"stationId\":227,\"stationName\":\"草桥\",\"position\":[3780,3988],\"shape\":\"cicle\",\"lineIds\":[10,18,20]},{\"stationId\":228,\"stationName\":\"纪家庙\",\"position\":[3600,4002],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":229,\"stationName\":\"首经贸\",\"position\":[3468,4002],\"shape\":\"cicle\",\"lineIds\":[10,21]},{\"stationId\":230,\"stationName\":\"丰台站\",\"position\":[3311,3944],\"shape\":\"cicle\",\"lineIds\":[10,15]},{\"stationId\":231,\"stationName\":\"泥洼\",\"position\":[3308,3860],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":232,\"stationName\":\"西局\",\"position\":[3307,3779],\"shape\":\"cicle\",\"lineIds\":[10,13],\"tagDirection\":1},{\"stationId\":233,\"stationName\":\"莲花桥\",\"position\":[3370,3468],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":234,\"stationName\":\"西钓鱼台\",\"position\":[3247,3211],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":235,\"stationName\":\"车道沟\",\"position\":[3204,2967],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":236,\"stationName\":\"长春桥\",\"position\":[3209,2861],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":237,\"stationName\":\"火器营\",\"position\":[3157,2787],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":238,\"stationName\":\"模式口\",\"position\":[1828,3113],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":239,\"stationName\":\"北辛安\",\"position\":[1914,3292],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":240,\"stationName\":\"新首钢\",\"position\":[1914,3350],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":241,\"stationName\":\"大钟寺\",\"position\":[3717,2780],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":242,\"stationName\":\"五道口\",\"position\":[3643,2517],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":243,\"stationName\":\"上地\",\"position\":[3468,2116],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":244,\"stationName\":\"清河站\",\"position\":[3416,2035],\"shape\":\"cicle\",\"lineIds\":[12,19]},{\"stationId\":245,\"stationName\":\"西二旗\",\"position\":[3329,1916],\"shape\":\"cicle\",\"lineIds\":[12,19]},{\"stationId\":246,\"stationName\":\"龙泽\",\"position\":[3460,1737],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":247,\"stationName\":\"回龙观\",\"position\":[3627,1738],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":248,\"stationName\":\"北苑\",\"position\":[4611,2016],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":249,\"stationName\":\"望京西\",\"position\":[4765,2489],\"shape\":\"cicle\",\"lineIds\":[12,14]},{\"stationId\":250,\"stationName\":\"光熙门\",\"position\":[4584,2763],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":2},{\"stationId\":251,\"stationName\":\"柳芳\",\"position\":[4593,2865],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":2},{\"stationId\":252,\"stationName\":\"善各庄\",\"position\":[5048,2175],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":253,\"stationName\":\"来广营\",\"position\":[4936,2242],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":254,\"stationName\":\"东湖渠\",\"position\":[4940,2341],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":255,\"stationName\":\"望京\",\"position\":[4960,2461],\"shape\":\"cicle\",\"lineIds\":[13,14]},{\"stationId\":256,\"stationName\":\"阜通\",\"position\":[4981,2528],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":257,\"stationName\":\"望京南\",\"position\":[5085,2600],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":258,\"stationName\":\"将台\",\"position\":[5168,2736],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":259,\"stationName\":\"东风北桥\",\"position\":[5125,2862],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":260,\"stationName\":\"枣营\",\"position\":[5016,3005],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":2},{\"stationId\":261,\"stationName\":\"朝阳公园\",\"position\":[5049,3111],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":262,\"stationName\":\"平乐园\",\"position\":[5039,3593],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":263,\"stationName\":\"北工大西门\",\"position\":[5039,3693],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":264,\"stationName\":\"方庄\",\"position\":[4668,3788],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":0},{\"stationId\":265,\"stationName\":\"景泰\",\"position\":[4376,3794],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":266,\"stationName\":\"景风门\",\"position\":[3926,3820],\"shape\":\"cicle\",\"lineIds\":[13,18],\"tagDirection\":1},{\"stationId\":267,\"stationName\":\"西铁营\",\"position\":[3826,3833],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":268,\"stationName\":\"菜户营\",\"position\":[3690,3770],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":4},{\"stationId\":269,\"stationName\":\"丽泽商务区\",\"position\":[3579,3769],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":4},{\"stationId\":270,\"stationName\":\"东管头\",\"position\":[3478,3771],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":0},{\"stationId\":271,\"stationName\":\"大井\",\"position\":[3027,3794],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":7},{\"stationId\":272,\"stationName\":\"郭庄子\",\"position\":[2797,3798],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":273,\"stationName\":\"大瓦窑\",\"position\":[2671,3852],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":274,\"stationName\":\"园博园\",\"position\":[2282,3833],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":275,\"stationName\":\"张郭庄\",\"position\":[2138,3865],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":276,\"stationName\":\"俸伯\",\"position\":[7113,1121],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":277,\"stationName\":\"顺义\",\"position\":[6836,1146],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":0},{\"stationId\":278,\"stationName\":\"石门\",\"position\":[6677,1148],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":7},{\"stationId\":279,\"stationName\":\"南法信\",\"position\":[6361,1161],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":280,\"stationName\":\"后沙峪\",\"position\":[5908,1305],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":281,\"stationName\":\"花梨坎\",\"position\":[5842,1602],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":282,\"stationName\":\"国展\",\"position\":[5817,1746],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":283,\"stationName\":\"孙河\",\"position\":[5613,1995],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":284,\"stationName\":\"马泉营\",\"position\":[5301,2109],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":285,\"stationName\":\"崔各庄\",\"position\":[5196,2224],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":286,\"stationName\":\"望京东\",\"position\":[5137,2414],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":287,\"stationName\":\"关庄\",\"position\":[4576,2435],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":288,\"stationName\":\"安立路\",\"position\":[4344,2420],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":4},{\"stationId\":289,\"stationName\":\"北沙滩\",\"position\":[3947,2431],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":7},{\"stationId\":290,\"stationName\":\"六道口\",\"position\":[3794,2446],\"shape\":\"cicle\",\"lineIds\":[14,19]},{\"stationId\":291,\"stationName\":\"清华东路西口\",\"position\":[3661,2440],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":292,\"stationName\":\"北安河\",\"position\":[1570,1765],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":293,\"stationName\":\"温阳路\",\"position\":[1880,1761],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":294,\"stationName\":\"稻香湖路\",\"position\":[2148,1757],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":295,\"stationName\":\"屯佃\",\"position\":[2425,1762],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":296,\"stationName\":\"永丰\",\"position\":[2651,1728],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":297,\"stationName\":\"永丰南\",\"position\":[2748,1790],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":298,\"stationName\":\"西北旺\",\"position\":[2845,1959],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":299,\"stationName\":\"马连洼\",\"position\":[2991,2120],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":300,\"stationName\":\"农大南路\",\"position\":[3089,2232],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":301,\"stationName\":\"万泉河桥\",\"position\":[3268,2596],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":302,\"stationName\":\"苏州桥\",\"position\":[3347,2826],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":303,\"stationName\":\"万寿寺\",\"position\":[3365,2969],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":304,\"stationName\":\"甘家口\",\"position\":[3611,3212],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":2},{\"stationId\":305,\"stationName\":\"玉渊潭东门\",\"position\":[3612,3306],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":2},{\"stationId\":306,\"stationName\":\"红莲南路\",\"position\":[3633,3671],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":307,\"stationName\":\"东管头南\",\"position\":[3497,3890],\"shape\":\"cicle\",\"lineIds\":[15,21]},{\"stationId\":308,\"stationName\":\"富丰桥\",\"position\":[3136,4084],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":7},{\"stationId\":309,\"stationName\":\"看丹\",\"position\":[2991,4097],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":310,\"stationName\":\"榆树庄\",\"position\":[2856,4059],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":311,\"stationName\":\"洪泰庄\",\"position\":[2759,3961],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":312,\"stationName\":\"宛平城\",\"position\":[2562,3956],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":313,\"stationName\":\"周家庄\",\"position\":[5030,3879],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":314,\"stationName\":\"十八里店\",\"position\":[5225,4003],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":315,\"stationName\":\"北神树\",\"position\":[5794,4260],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":316,\"stationName\":\"次渠北\",\"position\":[6033,4352],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":317,\"stationName\":\"次渠\",\"position\":[6182,4411],\"shape\":\"cicle\",\"lineIds\":[16,25]},{\"stationId\":318,\"stationName\":\"嘉会湖\",\"position\":[6369,4521],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":319,\"stationName\":\"未来科学城北\",\"position\":[4957,1143],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":320,\"stationName\":\"未来科学城\",\"position\":[4934,1290],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":321,\"stationName\":\"天通苑东\",\"position\":[4689,1758],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":322,\"stationName\":\"清河营\",\"position\":[4687,1938],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":323,\"stationName\":\"红军营\",\"position\":[4684,2109],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":324,\"stationName\":\"西坝河\",\"position\":[4659,2798],\"shape\":\"cicle\",\"lineIds\":[17],\"tagDirection\":2},{\"stationId\":325,\"stationName\":\"左家庄\",\"position\":[4693,2947],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":326,\"stationName\":\"工人体育场\",\"position\":[4771,3104],\"shape\":\"cicle\",\"lineIds\":[17],\"tagDirection\":6},{\"stationId\":327,\"stationName\":\"新发地\",\"position\":[3729,4212],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":328,\"stationName\":\"牛街\",\"position\":[3901,3550],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":1},{\"stationId\":329,\"stationName\":\"太平桥\",\"position\":[3899,3349],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":7},{\"stationId\":330,\"stationName\":\"北太平庄\",\"position\":[3967,2758],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":331,\"stationName\":\"昌平西山口\",\"position\":[2220,0],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":332,\"stationName\":\"十三陵景区\",\"position\":[2343,44],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":333,\"stationName\":\"昌平\",\"position\":[2602,241],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":334,\"stationName\":\"昌平东关\",\"position\":[2887,229],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":335,\"stationName\":\"北邵洼\",\"position\":[3086,226],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":336,\"stationName\":\"南邵\",\"position\":[3141,371],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":337,\"stationName\":\"沙河高教园\",\"position\":[3071,800],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":338,\"stationName\":\"沙河\",\"position\":[3155,963],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":339,\"stationName\":\"巩华城\",\"position\":[3206,1137],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":340,\"stationName\":\"生命科学园\",\"position\":[3208,1498],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":341,\"stationName\":\"朱房北\",\"position\":[3599,2085],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":342,\"stationName\":\"清河小营桥\",\"position\":[3703,2099],\"shape\":\"cicle\",\"lineIds\":[19],\"tagDirection\":5},{\"stationId\":343,\"stationName\":\"学知园\",\"position\":[3788,2296],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":344,\"stationName\":\"学院桥\",\"position\":[3800,2564],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":345,\"stationName\":\"大兴新城\",\"position\":[3921,5090],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":346,\"stationName\":\"大兴机场\",\"position\":[4433,7332],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":347,\"stationName\":\"阎村东\",\"position\":[1274,5156],\"shape\":\"cicle\",\"lineIds\":[21,24]},{\"stationId\":348,\"stationName\":\"苏庄\",\"position\":[1519,5214],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":349,\"stationName\":\"良乡南关\",\"position\":[1674,5214],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":350,\"stationName\":\"良乡大学城西\",\"position\":[1829,5215],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":351,\"stationName\":\"良乡大学城\",\"position\":[2031,5215],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":352,\"stationName\":\"良乡大学城北\",\"position\":[2101,5147],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":353,\"stationName\":\"广阳城\",\"position\":[2116,4967],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":354,\"stationName\":\"篱笆房\",\"position\":[2161,4840],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":355,\"stationName\":\"长阳\",\"position\":[2393,4808],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":356,\"stationName\":\"稻田\",\"position\":[2454,4497],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":357,\"stationName\":\"大葆台\",\"position\":[3183,4368],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":358,\"stationName\":\"白盆窑\",\"position\":[3400,4250],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":359,\"stationName\":\"花乡东桥\",\"position\":[3467,4154],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":360,\"stationName\":\"3号航站楼\",\"position\":[6422,1920],\"shape\":\"cicle\",\"lineIds\":[22]},{\"stationId\":361,\"stationName\":\"2号航站楼\",\"position\":[6194,1653],\"shape\":\"cicle\",\"lineIds\":[22]},{\"stationId\":362,\"stationName\":\"颐和园西门\",\"position\":[2899,2589],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":363,\"stationName\":\"茶棚\",\"position\":[2747,2625],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":364,\"stationName\":\"万安\",\"position\":[2586,2606],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":365,\"stationName\":\"国家植物园\",\"position\":[2423,2511],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":366,\"stationName\":\"香山\",\"position\":[2311,2506],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":367,\"stationName\":\"紫草坞\",\"position\":[1133,5200],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":368,\"stationName\":\"阎村\",\"position\":[1068,5279],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":369,\"stationName\":\"星城\",\"position\":[880,5309],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":370,\"stationName\":\"大石河东\",\"position\":[665,5347],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":371,\"stationName\":\"马各庄\",\"position\":[432,5395],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":372,\"stationName\":\"饶乐府\",\"position\":[327,5432],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":373,\"stationName\":\"房山城关\",\"position\":[162,5386],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":374,\"stationName\":\"燕山\",\"position\":[0,5250],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":375,\"stationName\":\"肖村\",\"position\":[4750,4104],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":376,\"stationName\":\"小红门\",\"position\":[4858,4167],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":377,\"stationName\":\"旧宫\",\"position\":[4874,4377],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":378,\"stationName\":\"亦庄桥\",\"position\":[5069,4416],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":379,\"stationName\":\"亦庄文化园\",\"position\":[5172,4377],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":380,\"stationName\":\"万源街\",\"position\":[5320,4417],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":381,\"stationName\":\"荣京东街\",\"position\":[5399,4514],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":382,\"stationName\":\"荣昌东街\",\"position\":[5483,4618],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":383,\"stationName\":\"同济南路\",\"position\":[5665,4717],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":384,\"stationName\":\"经海路\",\"position\":[5889,4610],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":385,\"stationName\":\"次渠南\",\"position\":[6080,4495],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":386,\"stationName\":\"亦庄火车站\",\"position\":[6285,4320],\"shape\":\"cicle\",\"lineIds\":[25]}],\"lines\":[{\"lineId\":1,\"lineName\":\"S1线\",\"color\":\"#B35A1F\",\"stationIds\":[1,2,3,4,5,6,7,8],\"sign\":\"S1线\",\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"1号线八通线\",\"color\":\"#CC0000\",\"stationIds\":[9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],\"sign\":\"1\",\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":3,\"lineName\":\"2号线\",\"color\":\"#0065B3\",\"stationIds\":[44,45,46,47,48,49,50,25,51,52,53,54,55,56,19,57,58,59,44],\"sign\":\"2\",\"order\":3,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"4号线大兴线\",\"color\":\"#008187\",\"stationIds\":[60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,55,20,77,78,79,80,59,81,82,83,84,85,86,87,88,89,90,91],\"sign\":\"4\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":5,\"lineName\":\"5号线\",\"color\":\"#A61D7F\",\"stationIds\":[92,93,94,95,96,52,24,97,98,99,100,47,101,102,103,104,105,106,107,108,109,110,111],\"sign\":\"5\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":6,\"lineName\":\"6号线\",\"color\":\"#D0970A\",\"stationIds\":[112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,50,98,128,129,79,58,130,131,132,133,134,135,136,137,138,139,1,2],\"sign\":\"6\",\"order\":6,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"7号线\",\"color\":\"#F9BE58\",\"stationIds\":[43,42,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,96,159,160,161,76,162,163,164,165],\"sign\":\"7\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"8号线\",\"color\":\"#018237\",\"stationIds\":[166,167,168,169,170,171,172,173,174,175,176,160,53,23,177,178,128,179,45,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194],\"sign\":\"8\",\"order\":8,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":9,\"lineName\":\"9号线\",\"color\":\"#86B81C\",\"stationIds\":[195,196,197,198,199,200,201,202,165,16,203,132,82],\"sign\":\"9\",\"order\":9,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"10号线\",\"color\":\"#019AC3\",\"stationIds\":[204,205,85,206,207,208,209,210,182,211,103,212,213,214,215,216,217,126,218,27,156,219,220,221,222,223,92,224,225,226,72,227,228,229,230,231,232,201,233,15,234,134,235,236,237,204],\"sign\":\"10\",\"order\":10,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":11,\"lineName\":\"11号线\",\"color\":\"#EE3F42\",\"stationIds\":[238,2,239,240],\"sign\":\"11\",\"order\":11,\"bendFirst\":[true,true,true,true]},{\"lineId\":12,\"lineName\":\"13号线\",\"color\":\"#FCD600\",\"stationIds\":[59,241,207,242,243,244,245,246,247,190,108,248,249,212,250,251,48],\"sign\":\"13\",\"order\":12,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":13,\"lineName\":\"14号线\",\"color\":\"#E4A8A3\",\"stationIds\":[252,253,254,255,256,257,258,259,260,261,125,28,155,262,263,221,264,94,265,175,74,266,267,268,269,270,232,200,271,272,273,274,275],\"sign\":\"14\",\"order\":13,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":14,\"lineName\":\"15号线\",\"color\":\"#793E8C\",\"stationIds\":[276,277,278,279,280,281,282,283,284,285,286,255,249,287,105,288,184,289,290,291],\"sign\":\"15\",\"order\":14,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":15,\"lineName\":\"16号线\",\"color\":\"#6CB46B\",\"stationIds\":[292,293,294,295,296,297,298,299,300,89,301,205,302,303,82,131,304,305,17,163,306,307,230,198,308,309,310,311,312],\"sign\":\"16\",\"order\":15,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":16,\"lineName\":\"17号线\",\"color\":\"#00AD8E\",\"stationIds\":[221,313,314,315,316,317,318],\"sign\":\"17\",\"order\":16,\"bendFirst\":[true,true,true,true,true,true,true]},{\"lineId\":17,\"lineName\":\"17号线北段\",\"color\":\"#00AD8E\",\"stationIds\":[319,320,321,322,323,213,324,325,326],\"sign\":\"17\",\"order\":17,\"bendFirst\":[true,true,true,true,true,true,true,true,true]},{\"lineId\":18,\"lineName\":\"19号线\",\"color\":\"#EB81B9\",\"stationIds\":[70,327,227,266,328,329,79,44,330,209],\"sign\":\"19\",\"order\":18,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true]},{\"lineId\":19,\"lineName\":\"昌平线\",\"color\":\"#EB81B9\",\"stationIds\":[331,332,333,334,335,336,337,338,339,194,340,245,244,341,342,343,290,344,208],\"sign\":\"昌平线\",\"order\":19,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":20,\"lineName\":\"大兴国际机场线\",\"color\":\"#2249A3\",\"stationIds\":[227,345,346],\"sign\":\"大兴国际机场线\",\"order\":20,\"bendFirst\":[true,true,true]},{\"lineId\":21,\"lineName\":\"房山线\",\"color\":\"#EE782E\",\"stationIds\":[347,348,349,350,351,352,353,354,355,356,357,195,358,359,229,307],\"sign\":\"房山线\",\"order\":21,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":22,\"lineName\":\"首都机场线\",\"color\":\"#A49ABD\",\"stationIds\":[360,361,214,48,100],\"sign\":\"首都机场线\",\"order\":22,\"bendFirst\":[true,true,true,true,true]},{\"lineId\":23,\"lineName\":\"西郊线\",\"color\":\"#FC0601\",\"stationIds\":[204,362,363,364,365,366],\"sign\":\"西郊线\",\"order\":23,\"bendFirst\":[true,true,true,true,true,true]},{\"lineId\":24,\"lineName\":\"燕房线\",\"color\":\"#EE782E\",\"stationIds\":[347,367,368,369,370,371,372,373,374],\"sign\":\"燕房线\",\"order\":24,\"bendFirst\":[true,true,true,true,true,true,true,true,true]},{\"lineId\":25,\"lineName\":\"亦庄线\",\"color\":\"#F0087D\",\"stationIds\":[92,375,376,377,378,379,380,381,382,383,384,385,317,386],\"sign\":\"亦庄线\",\"order\":25,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true]}]}"
  },
  {
    "path": "public/changsha.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"开福区政府\",\"position\":[1496,328],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":2,\"stationName\":\"马厂\",\"position\":[1529,436],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":3,\"stationName\":\"北辰三角洲\",\"position\":[1477,586],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":4,\"stationName\":\"开福寺\",\"position\":[1437,724],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":5,\"stationName\":\"文昌阁\",\"position\":[1423,821],\"shape\":\"cicle\",\"lineIds\":[1,6]},{\"stationId\":6,\"stationName\":\"培元桥\",\"position\":[1406,887],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":7,\"stationName\":\"五一广场\",\"position\":[1406,995],\"shape\":\"cicle\",\"lineIds\":[1,2],\"tagDirection\":1},{\"stationId\":8,\"stationName\":\"黄兴广场\",\"position\":[1406,1054],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":6},{\"stationId\":9,\"stationName\":\"南门口\",\"position\":[1403,1114],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":6},{\"stationId\":10,\"stationName\":\"侯家塘\",\"position\":[1463,1211],\"shape\":\"cicle\",\"lineIds\":[1,3]},{\"stationId\":11,\"stationName\":\"南湖路\",\"position\":[1497,1288],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":6},{\"stationId\":12,\"stationName\":\"黄土岭\",\"position\":[1496,1343],\"shape\":\"cicle\",\"lineIds\":[1,4],\"tagDirection\":5},{\"stationId\":13,\"stationName\":\"涂家冲\",\"position\":[1489,1417],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":14,\"stationName\":\"铁道学院\",\"position\":[1515,1587],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":15,\"stationName\":\"友谊路\",\"position\":[1510,1712],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":16,\"stationName\":\"省政府·清风\",\"position\":[1517,1837],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":17,\"stationName\":\"桂花坪\",\"position\":[1525,1956],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":18,\"stationName\":\"大托\",\"position\":[1533,2123],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":19,\"stationName\":\"中信广场\",\"position\":[1539,2211],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":20,\"stationName\":\"尚双塘\",\"position\":[1564,2329],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":21,\"stationName\":\"梅溪湖西\",\"position\":[460,1089],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":22,\"stationName\":\"麓云路\",\"position\":[562,1040],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":23,\"stationName\":\"文化艺术中心\",\"position\":[646,981],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":24,\"stationName\":\"梅溪湖东\",\"position\":[723,932],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":25,\"stationName\":\"望城坡(汽车西站)\",\"position\":[778,874],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":26,\"stationName\":\"金星路\",\"position\":[927,888],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":27,\"stationName\":\"西湖公园\",\"position\":[1041,922],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":28,\"stationName\":\"溁湾镇\",\"position\":[1156,972],\"shape\":\"cicle\",\"lineIds\":[2,4]},{\"stationId\":29,\"stationName\":\"橘子洲\",\"position\":[1267,992],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":5},{\"stationId\":30,\"stationName\":\"湘江中路\",\"position\":[1335,996],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":31,\"stationName\":\"芙蓉广场\",\"position\":[1488,1000],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":4},{\"stationId\":32,\"stationName\":\"迎宾路口\",\"position\":[1563,1000],\"shape\":\"cicle\",\"lineIds\":[2,6],\"tagDirection\":1},{\"stationId\":33,\"stationName\":\"袁家岭\",\"position\":[1648,1003],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":4},{\"stationId\":34,\"stationName\":\"长沙火车站\",\"position\":[1751,1012],\"shape\":\"cicle\",\"lineIds\":[2,3]},{\"stationId\":35,\"stationName\":\"锦泰广场\",\"position\":[1817,1030],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":4},{\"stationId\":36,\"stationName\":\"万家丽广场\",\"position\":[1943,1033],\"shape\":\"cicle\",\"lineIds\":[2,5]},{\"stationId\":37,\"stationName\":\"人民东路\",\"position\":[2028,1107],\"shape\":\"cicle\",\"lineIds\":[2,6],\"tagDirection\":1},{\"stationId\":38,\"stationName\":\"长沙大道\",\"position\":[2086,1265],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":2},{\"stationId\":39,\"stationName\":\"沙湾公园\",\"position\":[2090,1372],\"shape\":\"cicle\",\"lineIds\":[2,4],\"tagDirection\":7},{\"stationId\":40,\"stationName\":\"杜花路\",\"position\":[2206,1485],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":5},{\"stationId\":41,\"stationName\":\"长沙火车南站\",\"position\":[2294,1480],\"shape\":\"cicle\",\"lineIds\":[2,4]},{\"stationId\":42,\"stationName\":\"光达\",\"position\":[2492,1464],\"shape\":\"cicle\",\"lineIds\":[2,4],\"tagDirection\":7},{\"stationId\":43,\"stationName\":\"山塘\",\"position\":[900,1961],\"shape\":\"cicle\",\"lineIds\":[3,7]},{\"stationId\":44,\"stationName\":\"洋湖湿地\",\"position\":[1029,1801],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":45,\"stationName\":\"洋湖新城\",\"position\":[1096,1663],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":46,\"stationName\":\"阳光\",\"position\":[1012,1534],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":47,\"stationName\":\"中南大学\",\"position\":[1018,1407],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":48,\"stationName\":\"阜埠河\",\"position\":[1117,1285],\"shape\":\"cicle\",\"lineIds\":[3,4]},{\"stationId\":49,\"stationName\":\"灵官渡\",\"position\":[1347,1156],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":5},{\"stationId\":50,\"stationName\":\"东塘\",\"position\":[1571,1252],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":0},{\"stationId\":51,\"stationName\":\"桂花公园\",\"position\":[1656,1243],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":52,\"stationName\":\"阿弥岭\",\"position\":[1723,1202],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":53,\"stationName\":\"朝阳村\",\"position\":[1749,1083],\"shape\":\"cicle\",\"lineIds\":[3,6],\"tagDirection\":5},{\"stationId\":54,\"stationName\":\"烈士公园东\",\"position\":[1731,867],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":55,\"stationName\":\"丝茅冲\",\"position\":[1711,711],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":56,\"stationName\":\"四方坪\",\"position\":[1712,640],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":57,\"stationName\":\"雅雀湖\",\"position\":[1780,575],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":58,\"stationName\":\"长沙大学\",\"position\":[1953,539],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":59,\"stationName\":\"月湖公园北\",\"position\":[2052,522],\"shape\":\"cicle\",\"lineIds\":[3,5]},{\"stationId\":60,\"stationName\":\"湘龙\",\"position\":[2251,492],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":61,\"stationName\":\"星沙\",\"position\":[2510,492],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":62,\"stationName\":\"松雅湖(南)\",\"position\":[2677,494],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":4},{\"stationId\":63,\"stationName\":\"星沙文体中心\",\"position\":[2757,494],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":64,\"stationName\":\"螺丝塘\",\"position\":[2873,494],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":65,\"stationName\":\"广生\",\"position\":[2997,499],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":66,\"stationName\":\"罐子岭\",\"position\":[873,0],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":67,\"stationName\":\"月亮岛西\",\"position\":[937,76],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":68,\"stationName\":\"湘江新城\",\"position\":[979,131],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":69,\"stationName\":\"汉王陵公园\",\"position\":[1117,271],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":70,\"stationName\":\"福元大桥西\",\"position\":[1229,416],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":71,\"stationName\":\"茶子山\",\"position\":[1237,522],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":72,\"stationName\":\"观沙岭\",\"position\":[1166,643],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":73,\"stationName\":\"六沟垅\",\"position\":[1184,735],\"shape\":\"cicle\",\"lineIds\":[4,6]},{\"stationId\":74,\"stationName\":\"望月湖\",\"position\":[1201,882],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":75,\"stationName\":\"湖南师大\",\"position\":[1123,1086],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":76,\"stationName\":\"湖南大学\",\"position\":[1107,1151],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":77,\"stationName\":\"碧沙湖\",\"position\":[1320,1304],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":78,\"stationName\":\"砂子塘\",\"position\":[1570,1325],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":1},{\"stationId\":79,\"stationName\":\"赤岗岭\",\"position\":[1694,1351],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":80,\"stationName\":\"树木岭\",\"position\":[1842,1389],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":81,\"stationName\":\"圭塘\",\"position\":[1952,1373],\"shape\":\"cicle\",\"lineIds\":[4,5]},{\"stationId\":82,\"stationName\":\"粟塘\",\"position\":[2165,1372],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":83,\"stationName\":\"平阳\",\"position\":[2212,1427],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":1},{\"stationId\":84,\"stationName\":\"杜家坪\",\"position\":[2579,1533],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":85,\"stationName\":\"水渡河\",\"position\":[2281,150],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":86,\"stationName\":\"土桥\",\"position\":[2202,310],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":87,\"stationName\":\"白茅铺\",\"position\":[2129,445],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":88,\"stationName\":\"马栏山\",\"position\":[2049,632],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":89,\"stationName\":\"鸭子铺\",\"position\":[2002,698],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":90,\"stationName\":\"火炬村\",\"position\":[1954,864],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":91,\"stationName\":\"马王堆\",\"position\":[1950,948],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":92,\"stationName\":\"芙蓉区政府\",\"position\":[1945,1095],\"shape\":\"cicle\",\"lineIds\":[5,6],\"tagDirection\":5},{\"stationId\":93,\"stationName\":\"高桥北\",\"position\":[1942,1186],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":94,\"stationName\":\"高桥南\",\"position\":[1938,1278],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":95,\"stationName\":\"木桥\",\"position\":[1950,1461],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":96,\"stationName\":\"雨花区政府\",\"position\":[1992,1573],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":97,\"stationName\":\"大塘\",\"position\":[2006,1639],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":98,\"stationName\":\"板塘冲\",\"position\":[2037,1786],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":99,\"stationName\":\"毛竹塘\",\"position\":[2007,1998],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":100,\"stationName\":\"谢家桥\",\"position\":[0,1228],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":101,\"stationName\":\"象鼻窝\",\"position\":[174,1223],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":102,\"stationName\":\"中塘\",\"position\":[279,1142],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":103,\"stationName\":\"一师范西校区\",\"position\":[290,1018],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":104,\"stationName\":\"长庆\",\"position\":[270,938],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":105,\"stationName\":\"和馨园\",\"position\":[257,803],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":106,\"stationName\":\"长丰\",\"position\":[359,741],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":107,\"stationName\":\"麓谷体育公园\",\"position\":[461,749],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":108,\"stationName\":\"麓谷公园\",\"position\":[605,767],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":109,\"stationName\":\"涧塘\",\"position\":[748,763],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":110,\"stationName\":\"湖南工商大学\",\"position\":[864,755],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":111,\"stationName\":\"白鸽咀\",\"position\":[982,770],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":112,\"stationName\":\"湘雅三医院\",\"position\":[1073,767],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":113,\"stationName\":\"湘雅医院\",\"position\":[1521,814],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":114,\"stationName\":\"烈士公园南\",\"position\":[1554,902],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":2},{\"stationId\":115,\"stationName\":\"窑岭湘雅二医院\",\"position\":[1612,1064],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":116,\"stationName\":\"花桥\",\"position\":[2128,1101],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":117,\"stationName\":\"隆平水稻博物馆\",\"position\":[2230,1043],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":118,\"stationName\":\"农科院农大\",\"position\":[2433,1035],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":119,\"stationName\":\"东湖\",\"position\":[2600,1013],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":120,\"stationName\":\"韶光\",\"position\":[2713,990],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":121,\"stationName\":\"龙华\",\"position\":[2930,947],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":122,\"stationName\":\"檀木桥\",\"position\":[3144,930],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":123,\"stationName\":\"曹家坪\",\"position\":[3356,913],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":124,\"stationName\":\"龙峰\",\"position\":[3481,927],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":125,\"stationName\":\"大路村\",\"position\":[3698,928],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":126,\"stationName\":\"木马塅\",\"position\":[3760,992],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":1},{\"stationId\":127,\"stationName\":\"黄花机场T1T2\",\"position\":[3821,1041],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":6},{\"stationId\":128,\"stationName\":\"大王山\",\"position\":[810,2061],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":129,\"stationName\":\"桐溪\",\"position\":[725,2193],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":130,\"stationName\":\"红桥\",\"position\":[735,2358],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":131,\"stationName\":\"坪塘\",\"position\":[766,2515],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":132,\"stationName\":\"双湖\",\"position\":[918,2685],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":133,\"stationName\":\"黄家湾\",\"position\":[1111,3046],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":134,\"stationName\":\"船形山\",\"position\":[1135,3154],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":135,\"stationName\":\"湘潭北站\",\"position\":[1073,3316],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":136,\"stationName\":\"磁浮机场站\",\"position\":[3832,1032],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":2},{\"stationId\":137,\"stationName\":\"磁浮榔梨\",\"position\":[2975,1341],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":138,\"stationName\":\"磁浮高铁站\",\"position\":[2316,1460],\"shape\":\"cicle\",\"lineIds\":[8]}],\"lines\":[{\"lineId\":1,\"lineName\":\"1号线\",\"color\":\"#CC0000\",\"stationIds\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],\"sign\":\"1\",\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"2号线\",\"color\":\"#52A8C9\",\"stationIds\":[21,22,23,24,25,26,27,28,29,30,7,31,32,33,34,35,36,37,38,39,40,41,42],\"sign\":\"2\",\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":3,\"lineName\":\"3号线\",\"color\":\"#86B81C\",\"stationIds\":[43,44,45,46,47,48,49,10,50,51,52,53,34,54,55,56,57,58,59,60,61,62,63,64,65],\"sign\":\"3\",\"order\":3,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"4号线\",\"color\":\"#D10195\",\"stationIds\":[66,67,68,69,70,71,72,73,74,28,75,76,48,77,12,78,79,80,81,39,82,83,41,42,84],\"sign\":\"4\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,true,true]},{\"lineId\":5,\"lineName\":\"5号线\",\"color\":\"#FCD600\",\"stationIds\":[85,86,87,59,88,89,90,91,36,92,93,94,81,95,96,97,98,99],\"sign\":\"5\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":6,\"lineName\":\"6号线\",\"color\":\"#0065B3\",\"stationIds\":[100,101,102,103,104,105,106,107,108,109,110,111,112,73,5,113,114,32,115,53,92,37,116,117,118,119,120,121,122,123,124,125,126,127],\"sign\":\"6\",\"order\":6,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":7,\"lineName\":\"长株潭西环线\",\"color\":\"#EB81B9\",\"stationIds\":[43,128,129,130,131,132,133,134,135],\"sign\":\"长株潭西环线\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"磁浮快线\",\"color\":\"#B97CAF\",\"stationIds\":[136,137,138],\"sign\":\"磁浮快线\",\"order\":8,\"bendFirst\":[true,true,true]}],\"title\":\"长沙\"}"
  },
  {
    "path": "public/guangzhou.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"西塱\",\"position\":[2254,5008],\"shape\":\"cicle\",\"lineIds\":[1,19],\"tagDirection\":4},{\"stationId\":2,\"stationName\":\"坑口\",\"position\":[2259,4874],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":3,\"stationName\":\"花地湾\",\"position\":[2275,4792],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":4,\"stationName\":\"芳村\",\"position\":[2292,4676],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":5,\"stationName\":\"黄沙\",\"position\":[2333,4557],\"shape\":\"cicle\",\"lineIds\":[1,8]},{\"stationId\":6,\"stationName\":\"长寿路\",\"position\":[2357,4478],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":7,\"stationName\":\"陈家祠\",\"position\":[2399,4405],\"shape\":\"cicle\",\"lineIds\":[1,10],\"tagDirection\":6},{\"stationId\":8,\"stationName\":\"西门口\",\"position\":[2493,4410],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":4},{\"stationId\":9,\"stationName\":\"公园前\",\"position\":[2578,4408],\"shape\":\"cicle\",\"lineIds\":[1,3],\"tagDirection\":7},{\"stationId\":10,\"stationName\":\"农讲所\",\"position\":[2691,4396],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":11,\"stationName\":\"烈士陵园\",\"position\":[2791,4395],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":12,\"stationName\":\"东山口\",\"position\":[2888,4423],\"shape\":\"cicle\",\"lineIds\":[1,8]},{\"stationId\":13,\"stationName\":\"杨箕\",\"position\":[3023,4381],\"shape\":\"cicle\",\"lineIds\":[1,7]},{\"stationId\":14,\"stationName\":\"体育西路\",\"position\":[3150,4351],\"shape\":\"cicle\",\"lineIds\":[1,4,5],\"tagDirection\":7},{\"stationId\":15,\"stationName\":\"体育中心\",\"position\":[3218,4313],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":0},{\"stationId\":16,\"stationName\":\"广州东站\",\"position\":[3183,4153],\"shape\":\"cicle\",\"lineIds\":[1,5]},{\"stationId\":17,\"stationName\":\"广州南站\",\"position\":[2633,5775],\"shape\":\"cicle\",\"lineIds\":[2,3,9,17]},{\"stationId\":18,\"stationName\":\"林岳东(2号线)\",\"position\":[2431,5723],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":19,\"stationName\":\"林岳西\",\"position\":[2306,5725],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":20,\"stationName\":\"石洲\",\"position\":[2096,5756],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":21,\"stationName\":\"仙涌\",\"position\":[1917,5832],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":22,\"stationName\":\"花卉世界\",\"position\":[1548,5928],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":23,\"stationName\":\"登洲\",\"position\":[1423,5869],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":24,\"stationName\":\"湾华\",\"position\":[1252,5742],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":25,\"stationName\":\"石梁\",\"position\":[1122,5735],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":26,\"stationName\":\"魁奇路\",\"position\":[1021,5723],\"shape\":\"cicle\",\"lineIds\":[2,19]},{\"stationId\":27,\"stationName\":\"沙岗\",\"position\":[877,5697],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":28,\"stationName\":\"石湾\",\"position\":[767,5609],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":29,\"stationName\":\"张槎\",\"position\":[612,5552],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":30,\"stationName\":\"智慧新城\",\"position\":[489,5551],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":31,\"stationName\":\"绿岛湖\",\"position\":[277,5643],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":32,\"stationName\":\"湖涌\",\"position\":[48,5633],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":33,\"stationName\":\"南庄\",\"position\":[0,5833],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":34,\"stationName\":\"石壁\",\"position\":[2714,5721],\"shape\":\"cicle\",\"lineIds\":[3,9]},{\"stationId\":35,\"stationName\":\"会江\",\"position\":[2798,5532],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":36,\"stationName\":\"南浦\",\"position\":[2866,5333],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":37,\"stationName\":\"洛溪\",\"position\":[2921,5233],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":38,\"stationName\":\"南洲\",\"position\":[2908,5014],\"shape\":\"cicle\",\"lineIds\":[3,19]},{\"stationId\":39,\"stationName\":\"东晓南\",\"position\":[2876,4949],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":40,\"stationName\":\"江泰路\",\"position\":[2740,4840],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":41,\"stationName\":\"昌岗\",\"position\":[2703,4756],\"shape\":\"cicle\",\"lineIds\":[3,10]},{\"stationId\":42,\"stationName\":\"江南西\",\"position\":[2674,4690],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":43,\"stationName\":\"市二宫\",\"position\":[2633,4602],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":44,\"stationName\":\"海珠广场\",\"position\":[2588,4514],\"shape\":\"cicle\",\"lineIds\":[3,8],\"tagDirection\":3},{\"stationId\":45,\"stationName\":\"纪念堂\",\"position\":[2569,4341],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":46,\"stationName\":\"越秀公园\",\"position\":[2548,4262],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":47,\"stationName\":\"广州火车站\",\"position\":[2501,4181],\"shape\":\"cicle\",\"lineIds\":[3,7]},{\"stationId\":48,\"stationName\":\"三元里\",\"position\":[2503,4068],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":49,\"stationName\":\"飞翔公园\",\"position\":[2572,3973],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":50,\"stationName\":\"白云公园\",\"position\":[2644,3846],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":51,\"stationName\":\"白云文化广场\",\"position\":[2691,3767],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":52,\"stationName\":\"萧岗\",\"position\":[2741,3677],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":53,\"stationName\":\"江夏\",\"position\":[2769,3549],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":54,\"stationName\":\"黄边\",\"position\":[2808,3446],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":55,\"stationName\":\"嘉禾望岗\",\"position\":[2827,3288],\"shape\":\"cicle\",\"lineIds\":[3,5,13]},{\"stationId\":56,\"stationName\":\"番禺广场\",\"position\":[3791,6308],\"shape\":\"cicle\",\"lineIds\":[4,15,17]},{\"stationId\":57,\"stationName\":\"市桥\",\"position\":[3552,6165],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":58,\"stationName\":\"汉溪长隆\",\"position\":[3236,5733],\"shape\":\"cicle\",\"lineIds\":[4,9]},{\"stationId\":59,\"stationName\":\"大石\",\"position\":[3152,5485],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":60,\"stationName\":\"厦滘\",\"position\":[3143,5282],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":61,\"stationName\":\"沥滘\",\"position\":[3125,5113],\"shape\":\"cicle\",\"lineIds\":[4,19]},{\"stationId\":62,\"stationName\":\"大塘\",\"position\":[3151,4883],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":63,\"stationName\":\"客村\",\"position\":[3138,4700],\"shape\":\"cicle\",\"lineIds\":[4,10],\"tagDirection\":3},{\"stationId\":64,\"stationName\":\"广州塔\",\"position\":[3171,4599],\"shape\":\"cicle\",\"lineIds\":[4,18]},{\"stationId\":65,\"stationName\":\"珠江新城\",\"position\":[3147,4469],\"shape\":\"cicle\",\"lineIds\":[4,7],\"tagDirection\":5},{\"stationId\":66,\"stationName\":\"石牌桥\",\"position\":[3256,4331],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":3},{\"stationId\":67,\"stationName\":\"岗顶\",\"position\":[3331,4314],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":68,\"stationName\":\"华师\",\"position\":[3388,4259],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":69,\"stationName\":\"五山\",\"position\":[3453,4134],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":70,\"stationName\":\"天河客运站\",\"position\":[3370,3952],\"shape\":\"cicle\",\"lineIds\":[4,8]},{\"stationId\":71,\"stationName\":\"机场北(2号航站楼)\",\"position\":[2991,1700],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":72,\"stationName\":\"机场南(1号航站楼)\",\"position\":[2965,1796],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":73,\"stationName\":\"高增\",\"position\":[2890,2111],\"shape\":\"cicle\",\"lineIds\":[5,11]},{\"stationId\":74,\"stationName\":\"人和\",\"position\":[2894,2310],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":75,\"stationName\":\"龙归\",\"position\":[2943,2775],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":76,\"stationName\":\"白云大道北\",\"position\":[2916,3439],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":4},{\"stationId\":77,\"stationName\":\"永泰\",\"position\":[2997,3460],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":78,\"stationName\":\"同和\",\"position\":[3197,3692],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":79,\"stationName\":\"京溪南方医院\",\"position\":[3196,3810],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":80,\"stationName\":\"梅花园\",\"position\":[3140,3910],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":81,\"stationName\":\"燕塘\",\"position\":[3206,4063],\"shape\":\"cicle\",\"lineIds\":[5,8]},{\"stationId\":82,\"stationName\":\"林和西\",\"position\":[3174,4247],\"shape\":\"cicle\",\"lineIds\":[5,18],\"tagDirection\":7},{\"stationId\":83,\"stationName\":\"黄村\",\"position\":[4007,4344],\"shape\":\"cicle\",\"lineIds\":[6,16]},{\"stationId\":84,\"stationName\":\"车陂\",\"position\":[3890,4418],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":85,\"stationName\":\"车陂南\",\"position\":[3830,4503],\"shape\":\"cicle\",\"lineIds\":[6,7]},{\"stationId\":86,\"stationName\":\"万胜围\",\"position\":[3782,4685],\"shape\":\"cicle\",\"lineIds\":[6,10]},{\"stationId\":87,\"stationName\":\"官洲\",\"position\":[3703,4994],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":88,\"stationName\":\"大学城北\",\"position\":[3791,5081],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":89,\"stationName\":\"大学城南\",\"position\":[3940,5229],\"shape\":\"cicle\",\"lineIds\":[6,9]},{\"stationId\":90,\"stationName\":\"新造\",\"position\":[4092,5381],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":91,\"stationName\":\"石碁\",\"position\":[4586,6090],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":92,\"stationName\":\"海傍\",\"position\":[4688,6267],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":93,\"stationName\":\"低涌\",\"position\":[4783,6467],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":94,\"stationName\":\"东涌\",\"position\":[4724,6806],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":95,\"stationName\":\"庆盛\",\"position\":[4839,6992],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":96,\"stationName\":\"黄阁汽车城\",\"position\":[5032,7304],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":97,\"stationName\":\"黄阁\",\"position\":[5122,7415],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":98,\"stationName\":\"蕉门\",\"position\":[5210,7655],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":99,\"stationName\":\"金洲\",\"position\":[5323,7741],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":100,\"stationName\":\"飞沙角\",\"position\":[5342,7844],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":101,\"stationName\":\"广隆\",\"position\":[5342,7941],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":102,\"stationName\":\"大涌\",\"position\":[5494,8072],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":103,\"stationName\":\"塘坑\",\"position\":[5665,8131],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":104,\"stationName\":\"南横\",\"position\":[5878,8183],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":105,\"stationName\":\"南沙客运港\",\"position\":[6044,7992],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":106,\"stationName\":\"滘口\",\"position\":[2019,4524],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":107,\"stationName\":\"坦尾\",\"position\":[2118,4410],\"shape\":\"cicle\",\"lineIds\":[7,8]},{\"stationId\":108,\"stationName\":\"中山八\",\"position\":[2262,4402],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":7},{\"stationId\":109,\"stationName\":\"西场\",\"position\":[2315,4289],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":110,\"stationName\":\"西村\",\"position\":[2356,4240],\"shape\":\"cicle\",\"lineIds\":[7,10]},{\"stationId\":111,\"stationName\":\"小北\",\"position\":[2704,4268],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":112,\"stationName\":\"淘金\",\"position\":[2800,4299],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":113,\"stationName\":\"区庄\",\"position\":[2902,4318],\"shape\":\"cicle\",\"lineIds\":[7,8]},{\"stationId\":114,\"stationName\":\"动物园\",\"position\":[3007,4317],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":0},{\"stationId\":115,\"stationName\":\"五羊邨\",\"position\":[3077,4464],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":6},{\"stationId\":116,\"stationName\":\"猎德\",\"position\":[3256,4477],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":3},{\"stationId\":117,\"stationName\":\"潭村\",\"position\":[3394,4489],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":118,\"stationName\":\"员村\",\"position\":[3571,4505],\"shape\":\"cicle\",\"lineIds\":[7,16]},{\"stationId\":119,\"stationName\":\"科韵路\",\"position\":[3707,4470],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":120,\"stationName\":\"东圃\",\"position\":[3950,4568],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":121,\"stationName\":\"三溪\",\"position\":[4092,4621],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":122,\"stationName\":\"鱼珠\",\"position\":[4257,4658],\"shape\":\"cicle\",\"lineIds\":[7,12]},{\"stationId\":123,\"stationName\":\"大沙地\",\"position\":[4395,4630],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":124,\"stationName\":\"大沙东\",\"position\":[4520,4600],\"shape\":\"cicle\",\"lineIds\":[7,9]},{\"stationId\":125,\"stationName\":\"文冲\",\"position\":[4625,4624],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":126,\"stationName\":\"双沙\",\"position\":[4777,4684],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":127,\"stationName\":\"庙头\",\"position\":[4962,4815],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":128,\"stationName\":\"夏园\",\"position\":[5118,4833],\"shape\":\"cicle\",\"lineIds\":[7,12]},{\"stationId\":129,\"stationName\":\"保盈大道\",\"position\":[5195,4920],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":130,\"stationName\":\"夏港\",\"position\":[5187,5027],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":131,\"stationName\":\"黄埔新港\",\"position\":[5183,5139],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":132,\"stationName\":\"香雪\",\"position\":[4947,3939],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":133,\"stationName\":\"萝岗\",\"position\":[4745,3906],\"shape\":\"cicle\",\"lineIds\":[8,9],\"tagDirection\":3},{\"stationId\":134,\"stationName\":\"苏元\",\"position\":[4619,3953],\"shape\":\"cicle\",\"lineIds\":[8,16]},{\"stationId\":135,\"stationName\":\"暹岗\",\"position\":[4536,3939],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":136,\"stationName\":\"金峰\",\"position\":[4446,3848],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":137,\"stationName\":\"黄陂\",\"position\":[4272,3779],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":138,\"stationName\":\"高塘石\",\"position\":[4039,3752],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":139,\"stationName\":\"柯木塱\",\"position\":[3894,3728],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":140,\"stationName\":\"龙洞\",\"position\":[3710,3753],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":141,\"stationName\":\"植物园\",\"position\":[3591,3761],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":142,\"stationName\":\"长湴\",\"position\":[3429,3877],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":143,\"stationName\":\"天平架\",\"position\":[3148,4067],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":144,\"stationName\":\"沙河顶\",\"position\":[3004,4190],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":145,\"stationName\":\"黄花岗\",\"position\":[2934,4251],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":146,\"stationName\":\"东湖\",\"position\":[2820,4511],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":147,\"stationName\":\"团一大广场\",\"position\":[2717,4481],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":4},{\"stationId\":148,\"stationName\":\"北京路\",\"position\":[2637,4475],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":0},{\"stationId\":149,\"stationName\":\"一德路\",\"position\":[2506,4532],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":150,\"stationName\":\"文化公园\",\"position\":[2424,4570],\"shape\":\"cicle\",\"lineIds\":[8,10]},{\"stationId\":151,\"stationName\":\"如意坊\",\"position\":[2247,4513],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":152,\"stationName\":\"河沙\",\"position\":[2109,4307],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":153,\"stationName\":\"沙贝\",\"position\":[2048,4138],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":154,\"stationName\":\"横沙\",\"position\":[2002,4080],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":155,\"stationName\":\"浔峰岗\",\"position\":[1954,4021],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":156,\"stationName\":\"燕山\",\"position\":[4685,3711],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":157,\"stationName\":\"水西\",\"position\":[4722,3787],\"shape\":\"cicle\",\"lineIds\":[9,16]},{\"stationId\":158,\"stationName\":\"科丰路\",\"position\":[4596,4034],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":159,\"stationName\":\"加庄\",\"position\":[4536,4184],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":160,\"stationName\":\"姬堂\",\"position\":[4494,4341],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":161,\"stationName\":\"裕丰围\",\"position\":[4492,4714],\"shape\":\"cicle\",\"lineIds\":[9,12]},{\"stationId\":162,\"stationName\":\"长洲\",\"position\":[4228,4900],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":163,\"stationName\":\"深井\",\"position\":[4030,4975],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":164,\"stationName\":\"板桥\",\"position\":[3816,5494],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":165,\"stationName\":\"员岗\",\"position\":[3591,5503],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":166,\"stationName\":\"南村万博\",\"position\":[3410,5614],\"shape\":\"cicle\",\"lineIds\":[9,15]},{\"stationId\":167,\"stationName\":\"钟村\",\"position\":[3104,5798],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":168,\"stationName\":\"谢村\",\"position\":[2893,5757],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":169,\"stationName\":\"大洲\",\"position\":[2507,5824],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":170,\"stationName\":\"陈村北\",\"position\":[2387,5901],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":171,\"stationName\":\"陈村\",\"position\":[2303,5982],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":172,\"stationName\":\"锦龙\",\"position\":[2349,6131],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":173,\"stationName\":\"南涌\",\"position\":[2316,6269],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":174,\"stationName\":\"美的\",\"position\":[2203,6327],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":175,\"stationName\":\"北滘公园\",\"position\":[2054,6363],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":176,\"stationName\":\"美的大道\",\"position\":[2012,6215],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":177,\"stationName\":\"滘心\",\"position\":[2104,3293],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":178,\"stationName\":\"亭岗\",\"position\":[2134,3436],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":179,\"stationName\":\"石井\",\"position\":[2252,3551],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":180,\"stationName\":\"小坪\",\"position\":[2365,3657],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":181,\"stationName\":\"石潭\",\"position\":[2345,3784],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":182,\"stationName\":\"聚龙\",\"position\":[2322,3850],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":183,\"stationName\":\"上步\",\"position\":[2292,3953],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":184,\"stationName\":\"同德\",\"position\":[2282,4027],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":185,\"stationName\":\"鹅掌坦\",\"position\":[2293,4099],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":186,\"stationName\":\"彩虹桥\",\"position\":[2388,4323],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":187,\"stationName\":\"华林寺\",\"position\":[2408,4486],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":188,\"stationName\":\"同福西\",\"position\":[2458,4645],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":189,\"stationName\":\"凤凰新村\",\"position\":[2494,4715],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":190,\"stationName\":\"沙园\",\"position\":[2540,4776],\"shape\":\"cicle\",\"lineIds\":[10,19]},{\"stationId\":191,\"stationName\":\"宝岗大道\",\"position\":[2631,4802],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":192,\"stationName\":\"晓港\",\"position\":[2753,4732],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":193,\"stationName\":\"中大\",\"position\":[2863,4741],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":194,\"stationName\":\"鹭江\",\"position\":[3017,4709],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":195,\"stationName\":\"赤岗\",\"position\":[3283,4698],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":196,\"stationName\":\"磨碟沙\",\"position\":[3347,4675],\"shape\":\"cicle\",\"lineIds\":[10,15]},{\"stationId\":197,\"stationName\":\"新港东\",\"position\":[3505,4675],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":198,\"stationName\":\"琶洲\",\"position\":[3601,4677],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":199,\"stationName\":\"清塘\",\"position\":[2563,1940],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":200,\"stationName\":\"清布\",\"position\":[2444,1881],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":201,\"stationName\":\"莲塘\",\"position\":[2386,1771],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":202,\"stationName\":\"马鞍山公园\",\"position\":[2313,1665],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":203,\"stationName\":\"花都广场\",\"position\":[2161,1649],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":204,\"stationName\":\"花果山公园\",\"position\":[2118,1791],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":205,\"stationName\":\"花城路\",\"position\":[2062,1866],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":206,\"stationName\":\"广州北站\",\"position\":[1950,1898],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":207,\"stationName\":\"花都汽车城\",\"position\":[1738,1866],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":208,\"stationName\":\"飞鹅岭\",\"position\":[1486,1879],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":209,\"stationName\":\"双岗\",\"position\":[4678,4718],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":210,\"stationName\":\"南海神庙\",\"position\":[4909,4825],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":5},{\"stationId\":211,\"stationName\":\"南岗\",\"position\":[5349,4710],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":212,\"stationName\":\"沙村\",\"position\":[5638,4556],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":213,\"stationName\":\"白江\",\"position\":[5891,4430],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":214,\"stationName\":\"新塘\",\"position\":[5979,4345],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":215,\"stationName\":\"官湖\",\"position\":[6300,4290],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":216,\"stationName\":\"新沙\",\"position\":[6429,4294],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":217,\"stationName\":\"白云东平\",\"position\":[3113,3151],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":218,\"stationName\":\"夏良\",\"position\":[3170,2885],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":219,\"stationName\":\"太和\",\"position\":[3406,2669],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":220,\"stationName\":\"竹料\",\"position\":[3618,2177],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":221,\"stationName\":\"钟落潭\",\"position\":[3941,1906],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":222,\"stationName\":\"马沥\",\"position\":[4438,1724],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":223,\"stationName\":\"新和\",\"position\":[4605,1530],\"shape\":\"cicle\",\"lineIds\":[13,14]},{\"stationId\":224,\"stationName\":\"太平\",\"position\":[4854,1141],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":225,\"stationName\":\"神岗\",\"position\":[5108,911],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":226,\"stationName\":\"赤草\",\"position\":[5537,650],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":227,\"stationName\":\"从化客运站\",\"position\":[5882,345],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":228,\"stationName\":\"东风\",\"position\":[5943,0],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":229,\"stationName\":\"红卫\",\"position\":[4809,1670],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":230,\"stationName\":\"新南\",\"position\":[4887,1890],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":231,\"stationName\":\"枫下\",\"position\":[5018,2032],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":232,\"stationName\":\"知识城\",\"position\":[5186,2169],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":233,\"stationName\":\"何棠下\",\"position\":[5371,2350],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":234,\"stationName\":\"旺村\",\"position\":[5452,2430],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":235,\"stationName\":\"汤村\",\"position\":[5581,2589],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":236,\"stationName\":\"镇龙北\",\"position\":[5704,2766],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":237,\"stationName\":\"镇龙\",\"position\":[5864,2817],\"shape\":\"cicle\",\"lineIds\":[14,16]},{\"stationId\":238,\"stationName\":\"冼村\",\"position\":[3216,4405],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":2},{\"stationId\":239,\"stationName\":\"龙潭\",\"position\":[3348,4844],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":240,\"stationName\":\"沙溪\",\"position\":[3316,5308],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":241,\"stationName\":\"横沥\",\"position\":[5045,8129],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":242,\"stationName\":\"万顷沙\",\"position\":[5505,8678],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":243,\"stationName\":\"天河公园\",\"position\":[3563,4409],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":244,\"stationName\":\"棠东\",\"position\":[3828,4353],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":245,\"stationName\":\"大观南路\",\"position\":[4004,4217],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":246,\"stationName\":\"天河智慧城\",\"position\":[3966,4030],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":247,\"stationName\":\"神舟路\",\"position\":[4248,4010],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":248,\"stationName\":\"科学城\",\"position\":[4427,4006],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":249,\"stationName\":\"长平\",\"position\":[4832,3559],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":250,\"stationName\":\"金坑\",\"position\":[5202,3169],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":251,\"stationName\":\"镇龙西\",\"position\":[5672,2881],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":252,\"stationName\":\"中新\",\"position\":[6066,2809],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":253,\"stationName\":\"坑贝\",\"position\":[6361,2875],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":254,\"stationName\":\"凤岗\",\"position\":[6641,2903],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":255,\"stationName\":\"朱村\",\"position\":[6949,2939],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":256,\"stationName\":\"山田\",\"position\":[7380,2898],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":257,\"stationName\":\"钟岗\",\"position\":[7855,2869],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":258,\"stationName\":\"增城广场\",\"position\":[8079,2882],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":259,\"stationName\":\"陈头岗\",\"position\":[2591,5530],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":260,\"stationName\":\"市广路\",\"position\":[3304,5949],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":261,\"stationName\":\"海心沙\",\"position\":[3179,4547],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":2},{\"stationId\":262,\"stationName\":\"大剧院\",\"position\":[3179,4501],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":2},{\"stationId\":263,\"stationName\":\"花城大道\",\"position\":[3182,4470],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":2},{\"stationId\":264,\"stationName\":\"妇儿中心\",\"position\":[3180,4437],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":265,\"stationName\":\"黄埔大道\",\"position\":[3179,4392],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":266,\"stationName\":\"天河南\",\"position\":[3179,4348],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":267,\"stationName\":\"体育中心南\",\"position\":[3178,4320],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":7},{\"stationId\":268,\"stationName\":\"石溪\",\"position\":[2794,4983],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":269,\"stationName\":\"燕岗\",\"position\":[2654,4911],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":270,\"stationName\":\"沙涌\",\"position\":[2402,4831],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":271,\"stationName\":\"鹤洞\",\"position\":[2336,4937],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":272,\"stationName\":\"菊树\",\"position\":[2063,5004],\"shape\":\"cicle\",\"lineIds\":[19],\"tagDirection\":4},{\"stationId\":273,\"stationName\":\"龙溪\",\"position\":[1858,5002],\"shape\":\"cicle\",\"lineIds\":[19],\"tagDirection\":4},{\"stationId\":274,\"stationName\":\"金融高新区\",\"position\":[1520,5004],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":275,\"stationName\":\"千灯湖\",\"position\":[1488,5114],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":276,\"stationName\":\"礌岗\",\"position\":[1489,5236],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":277,\"stationName\":\"南桂路\",\"position\":[1476,5321],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":278,\"stationName\":\"桂城\",\"position\":[1349,5346],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":279,\"stationName\":\"朝安\",\"position\":[1270,5386],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":280,\"stationName\":\"普君北路\",\"position\":[1157,5386],\"shape\":\"cicle\",\"lineIds\":[19],\"tagDirection\":0},{\"stationId\":281,\"stationName\":\"祖庙\",\"position\":[1055,5392],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":282,\"stationName\":\"同济路\",\"position\":[1020,5470],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":283,\"stationName\":\"季华园\",\"position\":[1020,5591],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":284,\"stationName\":\"澜石\",\"position\":[1006,5822],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":285,\"stationName\":\"世纪莲\",\"position\":[1084,6011],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":286,\"stationName\":\"东平\",\"position\":[1226,6010],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":287,\"stationName\":\"新城东\",\"position\":[1335,6076],\"shape\":\"cicle\",\"lineIds\":[19]}],\"lines\":[{\"lineId\":1,\"lineName\":\"1号线\",\"color\":\"#FCD600\",\"stationIds\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],\"sign\":\"1\",\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"佛山2号线\",\"color\":\"#FC0601\",\"stationIds\":[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33],\"sign\":\"佛山2\",\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":3,\"lineName\":\"2号线\",\"color\":\"#0065B3\",\"stationIds\":[17,34,35,36,37,38,39,40,41,42,43,44,9,45,46,47,48,49,50,51,52,53,54,55],\"sign\":\"2\",\"order\":3,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"3号线\",\"color\":\"#FFA500\",\"stationIds\":[56,57,58,59,60,61,62,63,64,65,14,66,67,68,69,70],\"sign\":\"3\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":5,\"lineName\":\"3号线(北延段)\",\"color\":\"#FFA500\",\"stationIds\":[71,72,73,74,75,55,76,77,78,79,80,81,16,82,14],\"sign\":\"3\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":6,\"lineName\":\"4号线\",\"color\":\"#018237\",\"stationIds\":[83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105],\"sign\":\"4\",\"order\":6,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"5号线\",\"color\":\"#C5003E\",\"stationIds\":[106,107,108,109,110,47,111,112,113,114,13,115,65,116,117,118,119,85,120,121,122,123,124,125,126,127,128,129,130,131],\"sign\":\"5\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"6号线\",\"color\":\"#741D51\",\"stationIds\":[132,133,134,135,136,137,138,139,140,141,142,70,81,143,144,145,113,12,146,147,148,44,149,150,5,151,107,152,153,154,155],\"sign\":\"6\",\"order\":8,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":9,\"lineName\":\"7号线\",\"color\":\"#86B81C\",\"stationIds\":[156,157,133,158,159,160,124,161,162,163,89,164,165,166,58,167,168,34,17,169,170,171,172,173,174,175,176],\"sign\":\"7\",\"order\":9,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"8号线\",\"color\":\"#008187\",\"stationIds\":[177,178,179,180,181,182,183,184,185,110,186,7,187,150,188,189,190,191,41,192,193,194,63,195,196,197,198,86],\"sign\":\"8\",\"order\":10,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":11,\"lineName\":\"9号线\",\"color\":\"#64BD91\",\"stationIds\":[73,199,200,201,202,203,204,205,206,207,208],\"sign\":\"9\",\"order\":11,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":12,\"lineName\":\"13号线\",\"color\":\"#818530\",\"stationIds\":[122,161,209,210,128,211,212,213,214,215,216],\"sign\":\"13\",\"order\":12,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":13,\"lineName\":\"14号线\",\"color\":\"#871C2A\",\"stationIds\":[55,217,218,219,220,221,222,223,224,225,226,227,228],\"sign\":\"14\",\"order\":13,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":14,\"lineName\":\"14号线支线(知识城线)\",\"color\":\"#871C2A\",\"stationIds\":[223,229,230,231,232,233,234,235,236,237],\"sign\":\"14\",\"order\":14,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true]},{\"lineId\":15,\"lineName\":\"18号线\",\"color\":\"#2249A3\",\"stationIds\":[238,196,239,240,166,56,241,242],\"sign\":\"18\",\"order\":15,\"bendFirst\":[false,true,true,true,true,true,true,true]},{\"lineId\":16,\"lineName\":\"21号线\",\"color\":\"#0C1335\",\"stationIds\":[118,243,244,83,245,246,247,248,134,157,249,250,251,237,252,253,254,255,256,257,258],\"sign\":\"21\",\"order\":16,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":17,\"lineName\":\"22号线\",\"color\":\"#B35A1F\",\"stationIds\":[259,17,260,56],\"sign\":\"22\",\"order\":17,\"bendFirst\":[true,true,true,true]},{\"lineId\":18,\"lineName\":\"APM线\",\"color\":\"#02B6E3\",\"stationIds\":[64,261,262,263,264,265,266,267,82],\"sign\":\"APM线\",\"order\":18,\"bendFirst\":[true,true,true,true,true,true,true,true,true]},{\"lineId\":19,\"lineName\":\"广佛线\",\"color\":\"#B8D201\",\"stationIds\":[61,38,268,269,190,270,271,1,272,273,274,275,276,277,278,279,280,281,282,283,26,284,285,286,287],\"sign\":\"广佛线\",\"order\":19,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]}],\"title\":\"广州\"}"
  },
  {
    "path": "public/hongkong.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"迪士尼\",\"position\":[1084,2120],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":2,\"stationName\":\"欣澳\",\"position\":[928,1949],\"shape\":\"cicle\",\"lineIds\":[1,4]},{\"stationId\":3,\"stationName\":\"金钟\",\"position\":[2290,2486],\"shape\":\"cicle\",\"lineIds\":[2,5,10,12]},{\"stationId\":4,\"stationName\":\"会展\",\"position\":[2368,2458],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":7},{\"stationId\":5,\"stationName\":\"红磡\",\"position\":[2452,2256],\"shape\":\"cicle\",\"lineIds\":[2,11]},{\"stationId\":6,\"stationName\":\"旺角东\",\"position\":[2362,2058],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":2},{\"stationId\":7,\"stationName\":\"九龙塘\",\"position\":[2392,1899],\"shape\":\"cicle\",\"lineIds\":[2,6]},{\"stationId\":8,\"stationName\":\"大围\",\"position\":[2420,1549],\"shape\":\"cicle\",\"lineIds\":[2,11]},{\"stationId\":9,\"stationName\":\"沙田\",\"position\":[2505,1457],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":10,\"stationName\":\"火炭\",\"position\":[2616,1326],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":11,\"stationName\":\"大学\",\"position\":[2735,1140],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":12,\"stationName\":\"大埔墟\",\"position\":[2338,831],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":13,\"stationName\":\"太和\",\"position\":[2249,770],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":14,\"stationName\":\"粉岭\",\"position\":[2022,355],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":15,\"stationName\":\"上水\",\"position\":[1913,262],\"shape\":\"cicle\",\"lineIds\":[2,13]},{\"stationId\":16,\"stationName\":\"落马洲\",\"position\":[1294,131],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":17,\"stationName\":\"罗湖\",\"position\":[1771,0],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":18,\"stationName\":\"东涌\",\"position\":[48,2388],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":19,\"stationName\":\"青衣\",\"position\":[1711,1700],\"shape\":\"cicle\",\"lineIds\":[4,7]},{\"stationId\":20,\"stationName\":\"荔景\",\"position\":[1896,1790],\"shape\":\"cicle\",\"lineIds\":[4,12],\"tagDirection\":7},{\"stationId\":21,\"stationName\":\"南昌\",\"position\":[2171,2011],\"shape\":\"cicle\",\"lineIds\":[4,11]},{\"stationId\":22,\"stationName\":\"奥运\",\"position\":[2235,2097],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":6},{\"stationId\":23,\"stationName\":\"九龙\",\"position\":[2251,2227],\"shape\":\"cicle\",\"lineIds\":[4,7],\"tagDirection\":6},{\"stationId\":24,\"stationName\":\"香港\",\"position\":[2215,2429],\"shape\":\"cicle\",\"lineIds\":[4,7]},{\"stationId\":25,\"stationName\":\"坚尼地城\",\"position\":[1924,2464],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":26,\"stationName\":\"香港大学\",\"position\":[1993,2436],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":4},{\"stationId\":27,\"stationName\":\"西营盘\",\"position\":[2061,2423],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":28,\"stationName\":\"上环\",\"position\":[2163,2413],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":0},{\"stationId\":29,\"stationName\":\"中环\",\"position\":[2226,2460],\"shape\":\"cicle\",\"lineIds\":[5,12],\"tagDirection\":4},{\"stationId\":30,\"stationName\":\"湾仔\",\"position\":[2364,2506],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":31,\"stationName\":\"铜锣湾\",\"position\":[2471,2475],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":32,\"stationName\":\"天后\",\"position\":[2553,2450],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":33,\"stationName\":\"炮台山\",\"position\":[2575,2393],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":34,\"stationName\":\"北角\",\"position\":[2640,2368],\"shape\":\"cicle\",\"lineIds\":[5,9]},{\"stationId\":35,\"stationName\":\"鲗鱼涌\",\"position\":[2732,2400],\"shape\":\"cicle\",\"lineIds\":[5,9]},{\"stationId\":36,\"stationName\":\"太古\",\"position\":[2795,2432],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":5},{\"stationId\":37,\"stationName\":\"西湾河\",\"position\":[2857,2457],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":38,\"stationName\":\"筲箕湾\",\"position\":[2924,2488],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":39,\"stationName\":\"杏花邨\",\"position\":[3031,2512],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":40,\"stationName\":\"柴湾\",\"position\":[3005,2632],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":41,\"stationName\":\"黄埔\",\"position\":[2531,2228],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":42,\"stationName\":\"何文田\",\"position\":[2463,2184],\"shape\":\"cicle\",\"lineIds\":[6,11]},{\"stationId\":43,\"stationName\":\"油麻地\",\"position\":[2342,2147],\"shape\":\"cicle\",\"lineIds\":[6,12],\"tagDirection\":1},{\"stationId\":44,\"stationName\":\"旺角\",\"position\":[2328,2082],\"shape\":\"cicle\",\"lineIds\":[6,12],\"tagDirection\":6},{\"stationId\":45,\"stationName\":\"太子\",\"position\":[2317,2031],\"shape\":\"cicle\",\"lineIds\":[6,12]},{\"stationId\":46,\"stationName\":\"石硖尾\",\"position\":[2322,1959],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":3},{\"stationId\":47,\"stationName\":\"乐富\",\"position\":[2507,1899],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":48,\"stationName\":\"黄大仙\",\"position\":[2575,1861],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":7},{\"stationId\":49,\"stationName\":\"钻石山\",\"position\":[2647,1876],\"shape\":\"cicle\",\"lineIds\":[6,11]},{\"stationId\":50,\"stationName\":\"彩虹\",\"position\":[2724,1931],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":51,\"stationName\":\"九龙湾\",\"position\":[2774,2042],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":52,\"stationName\":\"牛头角\",\"position\":[2825,2124],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":53,\"stationName\":\"观塘\",\"position\":[2898,2156],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":54,\"stationName\":\"蓝田\",\"position\":[2963,2213],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":55,\"stationName\":\"油塘\",\"position\":[3005,2299],\"shape\":\"cicle\",\"lineIds\":[6,9]},{\"stationId\":56,\"stationName\":\"调景岭\",\"position\":[3157,2237],\"shape\":\"cicle\",\"lineIds\":[6,9]},{\"stationId\":57,\"stationName\":\"机场\",\"position\":[0,2121],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":58,\"stationName\":\"博览馆\",\"position\":[65,2057],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":59,\"stationName\":\"康城\",\"position\":[3326,2325],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":60,\"stationName\":\"将军澳\",\"position\":[3232,2204],\"shape\":\"cicle\",\"lineIds\":[8,9]},{\"stationId\":61,\"stationName\":\"坑口\",\"position\":[3277,2124],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":62,\"stationName\":\"宝琳\",\"position\":[3211,2052],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":63,\"stationName\":\"海洋公园\",\"position\":[2380,2790],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":64,\"stationName\":\"黄竹坑\",\"position\":[2316,2797],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":65,\"stationName\":\"利东\",\"position\":[2201,2850],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":66,\"stationName\":\"海怡半岛\",\"position\":[2125,2850],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":67,\"stationName\":\"屯门\",\"position\":[367,1327],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":68,\"stationName\":\"兆康\",\"position\":[424,1159],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":69,\"stationName\":\"天水围\",\"position\":[678,802],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":70,\"stationName\":\"朗屏\",\"position\":[889,802],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":71,\"stationName\":\"元朗\",\"position\":[989,816],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":72,\"stationName\":\"锦上路\",\"position\":[1269,928],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":73,\"stationName\":\"荃湾西\",\"position\":[1737,1594],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":74,\"stationName\":\"美孚\",\"position\":[2013,1898],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":75,\"stationName\":\"柯士甸\",\"position\":[2300,2230],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":4},{\"stationId\":76,\"stationName\":\"尖东\",\"position\":[2384,2323],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":77,\"stationName\":\"土瓜湾\",\"position\":[2514,2115],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":78,\"stationName\":\"宋皇台\",\"position\":[2545,2020],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":79,\"stationName\":\"启德\",\"position\":[2628,1973],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":80,\"stationName\":\"显径\",\"position\":[2343,1636],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":81,\"stationName\":\"车公庙\",\"position\":[2499,1530],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":3},{\"stationId\":82,\"stationName\":\"沙田围\",\"position\":[2583,1508],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":83,\"stationName\":\"第一城\",\"position\":[2669,1448],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":84,\"stationName\":\"石门\",\"position\":[2718,1401],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":85,\"stationName\":\"大水坑\",\"position\":[2861,1194],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":86,\"stationName\":\"恒安\",\"position\":[2893,1097],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":87,\"stationName\":\"马鞍山\",\"position\":[2951,1030],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":88,\"stationName\":\"乌溪沙\",\"position\":[3071,987],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":89,\"stationName\":\"荃湾\",\"position\":[1813,1539],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":90,\"stationName\":\"大窝口\",\"position\":[1885,1567],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":91,\"stationName\":\"葵兴\",\"position\":[1948,1644],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":92,\"stationName\":\"葵芳\",\"position\":[1916,1707],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":93,\"stationName\":\"美孚\",\"position\":[1999,1889],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":94,\"stationName\":\"荔枝角\",\"position\":[2118,1903],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":95,\"stationName\":\"长沙湾\",\"position\":[2198,1923],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":96,\"stationName\":\"深水埗\",\"position\":[2259,1969],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":0},{\"stationId\":97,\"stationName\":\"佐敦\",\"position\":[2351,2229],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":3},{\"stationId\":98,\"stationName\":\"尖沙咀\",\"position\":[2357,2303],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":6}],\"lines\":[{\"lineId\":1,\"lineName\":\"迪士尼\",\"color\":\"#EB81B9\",\"stationIds\":[1,2],\"sign\":\"迪士尼\",\"order\":1,\"bendFirst\":[true,true]},{\"lineId\":2,\"lineName\":\"东铁线\",\"color\":\"#69C7F4\",\"stationIds\":[3,4,5,6,7,8,9,10,11,12,13,14,15,16],\"sign\":\"东铁线\",\"order\":2,\"bendFirst\":[true,true,false,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"东涌线\",\"color\":\"#FFA500\",\"stationIds\":[18,2,19,20,21,22,23,24],\"sign\":\"东涌线\",\"order\":8,\"bendFirst\":[true,true,true,true,true,true,false,true]},{\"lineId\":5,\"lineName\":\"港岛线\",\"color\":\"#3080B7\",\"stationIds\":[25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,40],\"sign\":\"港岛线\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":6,\"lineName\":\"观塘线\",\"color\":\"#00AB4F\",\"stationIds\":[41,42,43,44,45,46,7,47,48,49,50,51,52,53,54,55,56],\"sign\":\"观塘线\",\"order\":10,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"机场快线\",\"color\":\"#008187\",\"stationIds\":[24,23,19,57,58],\"sign\":\"机场快线\",\"order\":7,\"bendFirst\":[true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"将军澳线\",\"color\":\"#793E8C\",\"stationIds\":[59,60],\"sign\":\"将军澳线\",\"order\":8,\"bendFirst\":[true,true],\"subLine\":true},{\"lineId\":9,\"lineName\":\"将军澳线\",\"color\":\"#793E8C\",\"stationIds\":[34,35,55,56,60,61,62],\"sign\":\"将军澳线\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"南港岛线\",\"color\":\"#B8D201\",\"stationIds\":[3,63,64,65,66],\"sign\":\"南港岛线\",\"order\":10,\"bendFirst\":[true,true,true,true,true]},{\"lineId\":11,\"lineName\":\"屯马线\",\"color\":\"#871C2A\",\"stationIds\":[67,68,69,70,71,72,73,74,21,75,76,5,42,77,78,79,49,80,8,81,82,83,84,85,86,87,88],\"sign\":\"屯马线\",\"order\":11,\"bendFirst\":[true,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true]},{\"lineId\":12,\"lineName\":\"荃湾线\",\"color\":\"#FC0601\",\"stationIds\":[89,90,91,92,20,93,94,95,96,45,44,43,97,98,3,29],\"sign\":\"荃湾线\",\"order\":12,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":13,\"lineName\":\"东铁线\",\"color\":\"#69C7F4\",\"stationIds\":[17,15],\"sign\":\"东铁线\",\"order\":13,\"bendFirst\":[true,true],\"subLine\":true}],\"title\":\"香港\"}"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <!-- <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi\" /> -->\n  \n    <meta id=\"theme-color\" name=\"theme-color\" content=\"#fffee0\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/app-icon.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>Mini Metro Web</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "public/manifest.json",
    "content": "{\n  \"short_name\": \"Mini Metro Web\",\n  \"name\": \"Mini Metro Web\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"app-icon.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"app-icon.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#ffffff\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "public/shanghai.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"莘庄\",\"position\":[3658,2970],\"shape\":\"cicle\",\"lineIds\":[1,5]},{\"stationId\":2,\"stationName\":\"外环路\",\"position\":[3735,2872],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":3,\"stationName\":\"莲花路\",\"position\":[3834,2772],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":4,\"stationName\":\"锦江乐园\",\"position\":[3946,2659],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":5,\"stationName\":\"上海南站\",\"position\":[4105,2535],\"shape\":\"cicle\",\"lineIds\":[1,3,18]},{\"stationId\":6,\"stationName\":\"漕宝路\",\"position\":[4136,2398],\"shape\":\"cicle\",\"lineIds\":[1,15],\"tagDirection\":3},{\"stationId\":7,\"stationName\":\"上海体育馆\",\"position\":[4179,2253],\"shape\":\"cicle\",\"lineIds\":[1,4],\"tagDirection\":5},{\"stationId\":8,\"stationName\":\"徐家汇\",\"position\":[4171,2126],\"shape\":\"cicle\",\"lineIds\":[1,10,14]},{\"stationId\":9,\"stationName\":\"衡山路\",\"position\":[4269,2036],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":4},{\"stationId\":10,\"stationName\":\"常熟路\",\"position\":[4296,1946],\"shape\":\"cicle\",\"lineIds\":[1,8]},{\"stationId\":11,\"stationName\":\"陕西南路\",\"position\":[4392,1930],\"shape\":\"cicle\",\"lineIds\":[1,11,15]},{\"stationId\":12,\"stationName\":\"黄陂南路\",\"position\":[4534,1842],\"shape\":\"cicle\",\"lineIds\":[1,17],\"tagDirection\":7},{\"stationId\":13,\"stationName\":\"人民广场\",\"position\":[4556,1754],\"shape\":\"cicle\",\"lineIds\":[1,2,9]},{\"stationId\":14,\"stationName\":\"新闸路\",\"position\":[4486,1697],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":4},{\"stationId\":15,\"stationName\":\"汉中路\",\"position\":[4392,1662],\"shape\":\"cicle\",\"lineIds\":[1,15,16],\"tagDirection\":7},{\"stationId\":16,\"stationName\":\"上海火车站\",\"position\":[4384,1585],\"shape\":\"cicle\",\"lineIds\":[1,3,4],\"tagDirection\":3},{\"stationId\":17,\"stationName\":\"中山北路\",\"position\":[4397,1492],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":18,\"stationName\":\"延长路\",\"position\":[4358,1364],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":19,\"stationName\":\"上海马戏城\",\"position\":[4325,1282],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":20,\"stationName\":\"汶水路\",\"position\":[4307,1156],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":21,\"stationName\":\"彭浦新村\",\"position\":[4291,1015],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":22,\"stationName\":\"共康路\",\"position\":[4275,892],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":23,\"stationName\":\"通河新村\",\"position\":[4220,770],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":24,\"stationName\":\"呼兰路\",\"position\":[4182,684],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":25,\"stationName\":\"共富新村\",\"position\":[4145,530],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":26,\"stationName\":\"宝安公路\",\"position\":[4114,386],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":27,\"stationName\":\"友谊西路\",\"position\":[4084,268],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":28,\"stationName\":\"富锦路\",\"position\":[4051,159],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":29,\"stationName\":\"浦东国际机场\",\"position\":[7861,2572],\"shape\":\"cicle\",\"lineIds\":[2,22]},{\"stationId\":30,\"stationName\":\"海天三路\",\"position\":[7773,2397],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":31,\"stationName\":\"远东大道\",\"position\":[7358,2087],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":32,\"stationName\":\"凌空路\",\"position\":[7046,2153],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":33,\"stationName\":\"川沙\",\"position\":[6787,2214],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":34,\"stationName\":\"华夏东路\",\"position\":[6614,2115],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":35,\"stationName\":\"创新中路\",\"position\":[6542,1942],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":36,\"stationName\":\"唐镇\",\"position\":[6367,1940],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":37,\"stationName\":\"广兰路\",\"position\":[6015,1971],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":38,\"stationName\":\"金科路\",\"position\":[5825,2039],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":39,\"stationName\":\"张江高科\",\"position\":[5680,2062],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":40,\"stationName\":\"龙阳路\",\"position\":[5381,2045],\"shape\":\"cicle\",\"lineIds\":[2,8,19,21,22]},{\"stationId\":41,\"stationName\":\"世纪公园\",\"position\":[5314,1987],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":42,\"stationName\":\"上海科技馆\",\"position\":[5249,1893],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":5},{\"stationId\":43,\"stationName\":\"世纪大道\",\"position\":[5077,1794],\"shape\":\"cicle\",\"lineIds\":[2,4,7,10]},{\"stationId\":44,\"stationName\":\"东昌路\",\"position\":[4960,1748],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":6},{\"stationId\":45,\"stationName\":\"陆家嘴\",\"position\":[4826,1699],\"shape\":\"cicle\",\"lineIds\":[2,17]},{\"stationId\":46,\"stationName\":\"南京东路\",\"position\":[4651,1700],\"shape\":\"cicle\",\"lineIds\":[2,11]},{\"stationId\":47,\"stationName\":\"南京西路\",\"position\":[4404,1783],\"shape\":\"cicle\",\"lineIds\":[2,15,16]},{\"stationId\":48,\"stationName\":\"静安寺\",\"position\":[4270,1849],\"shape\":\"cicle\",\"lineIds\":[2,8,17],\"tagDirection\":1},{\"stationId\":49,\"stationName\":\"江苏路\",\"position\":[4111,1877],\"shape\":\"cicle\",\"lineIds\":[2,14]},{\"stationId\":50,\"stationName\":\"中山公园\",\"position\":[3962,1902],\"shape\":\"cicle\",\"lineIds\":[2,3,4]},{\"stationId\":51,\"stationName\":\"娄山关路\",\"position\":[3845,1970],\"shape\":\"cicle\",\"lineIds\":[2,18]},{\"stationId\":52,\"stationName\":\"威宁路\",\"position\":[3678,1932],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":53,\"stationName\":\"北新泾\",\"position\":[3545,1917],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":54,\"stationName\":\"淞虹路\",\"position\":[3400,1899],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":55,\"stationName\":\"虹桥2号航站楼\",\"position\":[3068,2139],\"shape\":\"cicle\",\"lineIds\":[2,11],\"tagDirection\":4},{\"stationId\":56,\"stationName\":\"虹桥火车站\",\"position\":[2994,2141],\"shape\":\"cicle\",\"lineIds\":[2,20,11],\"tagDirection\":7},{\"stationId\":57,\"stationName\":\"徐泾东\",\"position\":[2797,2198],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":4},{\"stationId\":58,\"stationName\":\"江杨北路\",\"position\":[4203,3],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":59,\"stationName\":\"铁力路\",\"position\":[4416,0],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":60,\"stationName\":\"友谊路\",\"position\":[4564,41],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":61,\"stationName\":\"宝杨路\",\"position\":[4600,128],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":62,\"stationName\":\"水产路\",\"position\":[4687,268],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":63,\"stationName\":\"淞滨路\",\"position\":[4733,372],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":64,\"stationName\":\"张华浜\",\"position\":[4791,501],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":65,\"stationName\":\"淞发路\",\"position\":[4809,630],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":66,\"stationName\":\"长江南路\",\"position\":[4719,761],\"shape\":\"cicle\",\"lineIds\":[3,21]},{\"stationId\":67,\"stationName\":\"殷高西路\",\"position\":[4653,881],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":68,\"stationName\":\"江湾镇\",\"position\":[4655,1026],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":6},{\"stationId\":69,\"stationName\":\"大柏树\",\"position\":[4637,1187],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":70,\"stationName\":\"赤峰路\",\"position\":[4629,1269],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":71,\"stationName\":\"虹口足球场\",\"position\":[4596,1367],\"shape\":\"cicle\",\"lineIds\":[3,9]},{\"stationId\":72,\"stationName\":\"东宝兴路\",\"position\":[4607,1482],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":6},{\"stationId\":73,\"stationName\":\"宝山路\",\"position\":[4568,1566],\"shape\":\"cicle\",\"lineIds\":[3,4],\"tagDirection\":4},{\"stationId\":74,\"stationName\":\"中潭路\",\"position\":[4215,1536],\"shape\":\"cicle\",\"lineIds\":[3,4]},{\"stationId\":75,\"stationName\":\"镇坪路\",\"position\":[4102,1618],\"shape\":\"cicle\",\"lineIds\":[3,4,8]},{\"stationId\":76,\"stationName\":\"曹杨路\",\"position\":[3982,1688],\"shape\":\"cicle\",\"lineIds\":[3,4,14,17]},{\"stationId\":77,\"stationName\":\"金沙江路\",\"position\":[3937,1760],\"shape\":\"cicle\",\"lineIds\":[3,4,16],\"tagDirection\":5},{\"stationId\":78,\"stationName\":\"延安西路\",\"position\":[3975,1985],\"shape\":\"cicle\",\"lineIds\":[3,4]},{\"stationId\":79,\"stationName\":\"虹桥路\",\"position\":[4013,2106],\"shape\":\"cicle\",\"lineIds\":[3,4,11],\"tagDirection\":1},{\"stationId\":80,\"stationName\":\"宜山路\",\"position\":[4077,2214],\"shape\":\"cicle\",\"lineIds\":[3,4,10],\"tagDirection\":2},{\"stationId\":81,\"stationName\":\"漕溪路\",\"position\":[4189,2314],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":5},{\"stationId\":82,\"stationName\":\"龙漕路\",\"position\":[4248,2387],\"shape\":\"cicle\",\"lineIds\":[3,15]},{\"stationId\":83,\"stationName\":\"石龙路\",\"position\":[4237,2502],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":84,\"stationName\":\"海伦路\",\"position\":[4692,1488],\"shape\":\"cicle\",\"lineIds\":[4,11]},{\"stationId\":85,\"stationName\":\"临平路\",\"position\":[4812,1472],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":86,\"stationName\":\"大连路\",\"position\":[4936,1502],\"shape\":\"cicle\",\"lineIds\":[4,15]},{\"stationId\":87,\"stationName\":\"杨树浦路\",\"position\":[4977,1562],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":2},{\"stationId\":88,\"stationName\":\"浦东大道\",\"position\":[4998,1678],\"shape\":\"cicle\",\"lineIds\":[4,17],\"tagDirection\":1},{\"stationId\":89,\"stationName\":\"浦电路(4号线)\",\"position\":[5125,1858],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":2},{\"stationId\":90,\"stationName\":\"蓝村路\",\"position\":[5081,1964],\"shape\":\"cicle\",\"lineIds\":[4,7]},{\"stationId\":91,\"stationName\":\"塘桥\",\"position\":[4992,1984],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":7},{\"stationId\":92,\"stationName\":\"南浦大桥\",\"position\":[4802,1996],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":93,\"stationName\":\"西藏南路\",\"position\":[4700,2062],\"shape\":\"cicle\",\"lineIds\":[4,9],\"tagDirection\":3},{\"stationId\":94,\"stationName\":\"鲁班路\",\"position\":[4556,2089],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":95,\"stationName\":\"大木桥路\",\"position\":[4437,2141],\"shape\":\"cicle\",\"lineIds\":[4,15],\"tagDirection\":3},{\"stationId\":96,\"stationName\":\"东安路\",\"position\":[4354,2173],\"shape\":\"cicle\",\"lineIds\":[4,8]},{\"stationId\":97,\"stationName\":\"上海体育场\",\"position\":[4240,2225],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":0},{\"stationId\":98,\"stationName\":\"闵行开发区\",\"position\":[3502,4075],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":99,\"stationName\":\"文井路\",\"position\":[3612,4045],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":100,\"stationName\":\"华宁路\",\"position\":[3757,4007],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":101,\"stationName\":\"金平路\",\"position\":[3907,3968],\"shape\":\"cicle\",\"lineIds\":[24]},{\"stationId\":102,\"stationName\":\"东川路\",\"position\":[4004,3899],\"shape\":\"cicle\",\"lineIds\":[5,24]},{\"stationId\":103,\"stationName\":\"剑川路\",\"position\":[3970,3816],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":104,\"stationName\":\"北桥\",\"position\":[3905,3630],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":105,\"stationName\":\"颛桥\",\"position\":[3823,3411],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":106,\"stationName\":\"银都路\",\"position\":[3707,3188],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":107,\"stationName\":\"春申路\",\"position\":[3663,3099],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":108,\"stationName\":\"江川路\",\"position\":[4039,4027],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":109,\"stationName\":\"西渡\",\"position\":[4129,4188],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":110,\"stationName\":\"萧塘\",\"position\":[4223,4422],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":111,\"stationName\":\"奉浦大道\",\"position\":[4295,4661],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":112,\"stationName\":\"环城东路\",\"position\":[4437,4770],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":113,\"stationName\":\"望园路\",\"position\":[4640,4762],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":0},{\"stationId\":114,\"stationName\":\"金海湖\",\"position\":[4730,4793],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":115,\"stationName\":\"奉贤新城\",\"position\":[4768,4942],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":116,\"stationName\":\"东方体育中心\",\"position\":[4608,2548],\"shape\":\"cicle\",\"lineIds\":[7,9,14]},{\"stationId\":117,\"stationName\":\"灵岩南路\",\"position\":[4758,2595],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":118,\"stationName\":\"上南路\",\"position\":[4869,2593],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":0},{\"stationId\":119,\"stationName\":\"华夏西路\",\"position\":[4950,2582],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":2},{\"stationId\":120,\"stationName\":\"高青路\",\"position\":[4963,2482],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":121,\"stationName\":\"东明路\",\"position\":[4913,2355],\"shape\":\"cicle\",\"lineIds\":[7,16]},{\"stationId\":122,\"stationName\":\"高科西路\",\"position\":[4903,2224],\"shape\":\"cicle\",\"lineIds\":[7,8],\"tagDirection\":7},{\"stationId\":123,\"stationName\":\"临沂新村\",\"position\":[4972,2149],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":124,\"stationName\":\"上海儿童医学中心\",\"position\":[5039,2048],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":125,\"stationName\":\"浦电路(6号线)\",\"position\":[5098,1880],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":6},{\"stationId\":126,\"stationName\":\"源深体育中心\",\"position\":[5151,1751],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":2},{\"stationId\":127,\"stationName\":\"民生路\",\"position\":[5240,1723],\"shape\":\"cicle\",\"lineIds\":[7,21]},{\"stationId\":128,\"stationName\":\"北洋泾路\",\"position\":[5328,1690],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":129,\"stationName\":\"德平路\",\"position\":[5447,1627],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":4},{\"stationId\":130,\"stationName\":\"云山路\",\"position\":[5516,1572],\"shape\":\"cicle\",\"lineIds\":[7,17]},{\"stationId\":131,\"stationName\":\"金桥路\",\"position\":[5623,1510],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":132,\"stationName\":\"博兴路\",\"position\":[5672,1446],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":133,\"stationName\":\"五莲路\",\"position\":[5683,1361],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":134,\"stationName\":\"巨峰路\",\"position\":[5688,1274],\"shape\":\"cicle\",\"lineIds\":[7,15],\"tagDirection\":1},{\"stationId\":135,\"stationName\":\"东靖路\",\"position\":[5692,1174],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":136,\"stationName\":\"五洲大道\",\"position\":[5697,1056],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":137,\"stationName\":\"洲海路\",\"position\":[5699,959],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":138,\"stationName\":\"外高桥保税区南\",\"position\":[5824,865],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":139,\"stationName\":\"航津路\",\"position\":[5744,727],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":140,\"stationName\":\"外高桥保税区北\",\"position\":[5674,603],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":5},{\"stationId\":141,\"stationName\":\"港城路\",\"position\":[5555,549],\"shape\":\"cicle\",\"lineIds\":[7,11],\"tagDirection\":1},{\"stationId\":142,\"stationName\":\"花木路\",\"position\":[5432,1969],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":2},{\"stationId\":143,\"stationName\":\"芳华路\",\"position\":[5306,2150],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":7},{\"stationId\":144,\"stationName\":\"锦绣路\",\"position\":[5205,2205],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":145,\"stationName\":\"杨高南路\",\"position\":[5050,2205],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":146,\"stationName\":\"云台路\",\"position\":[4809,2259],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":3},{\"stationId\":147,\"stationName\":\"耀华路\",\"position\":[4751,2296],\"shape\":\"cicle\",\"lineIds\":[8,9],\"tagDirection\":3},{\"stationId\":148,\"stationName\":\"长清路\",\"position\":[4682,2337],\"shape\":\"cicle\",\"lineIds\":[8,16]},{\"stationId\":149,\"stationName\":\"后滩\",\"position\":[4542,2362],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":150,\"stationName\":\"龙华中路\",\"position\":[4375,2237],\"shape\":\"cicle\",\"lineIds\":[8,15]},{\"stationId\":151,\"stationName\":\"肇嘉浜路\",\"position\":[4307,2087],\"shape\":\"cicle\",\"lineIds\":[8,10],\"tagDirection\":3},{\"stationId\":152,\"stationName\":\"昌平路\",\"position\":[4231,1744],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":153,\"stationName\":\"长寿路\",\"position\":[4187,1673],\"shape\":\"cicle\",\"lineIds\":[8,16]},{\"stationId\":154,\"stationName\":\"岚皋路\",\"position\":[4024,1519],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":155,\"stationName\":\"新村路\",\"position\":[4031,1443],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":156,\"stationName\":\"大华三路\",\"position\":[4034,1341],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":157,\"stationName\":\"行知路\",\"position\":[4022,1236],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":158,\"stationName\":\"大场镇\",\"position\":[3966,1149],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":159,\"stationName\":\"场中路\",\"position\":[3939,1044],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":160,\"stationName\":\"上大路\",\"position\":[3892,932],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":161,\"stationName\":\"南陈路\",\"position\":[3789,864],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":162,\"stationName\":\"上海大学\",\"position\":[3694,875],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":0},{\"stationId\":163,\"stationName\":\"祁华路\",\"position\":[3540,857],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":164,\"stationName\":\"顾村公园\",\"position\":[3535,635],\"shape\":\"cicle\",\"lineIds\":[8,18]},{\"stationId\":165,\"stationName\":\"刘行\",\"position\":[3428,505],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":166,\"stationName\":\"潘广路\",\"position\":[3363,439],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":167,\"stationName\":\"罗南新村\",\"position\":[3379,193],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":168,\"stationName\":\"美兰湖\",\"position\":[3304,62],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":169,\"stationName\":\"沈杜公路\",\"position\":[4927,3467],\"shape\":\"cicle\",\"lineIds\":[9,23]},{\"stationId\":170,\"stationName\":\"联航路\",\"position\":[4911,3346],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":171,\"stationName\":\"江月路\",\"position\":[4891,3239],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":172,\"stationName\":\"浦江镇\",\"position\":[4867,3115],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":173,\"stationName\":\"芦恒路\",\"position\":[4787,2890],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":174,\"stationName\":\"凌兆新村\",\"position\":[4701,2668],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":175,\"stationName\":\"杨思\",\"position\":[4739,2471],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":176,\"stationName\":\"成山路\",\"position\":[4767,2374],\"shape\":\"cicle\",\"lineIds\":[9,16]},{\"stationId\":177,\"stationName\":\"中华艺术宫\",\"position\":[4741,2229],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":178,\"stationName\":\"陆家浜路\",\"position\":[4666,1963],\"shape\":\"cicle\",\"lineIds\":[9,10]},{\"stationId\":179,\"stationName\":\"老西门\",\"position\":[4643,1891],\"shape\":\"cicle\",\"lineIds\":[9,11]},{\"stationId\":180,\"stationName\":\"大世界\",\"position\":[4596,1807],\"shape\":\"cicle\",\"lineIds\":[9,17],\"tagDirection\":1},{\"stationId\":181,\"stationName\":\"曲阜路\",\"position\":[4520,1658],\"shape\":\"cicle\",\"lineIds\":[9,15]},{\"stationId\":182,\"stationName\":\"中兴路\",\"position\":[4495,1549],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":1},{\"stationId\":183,\"stationName\":\"西藏北路\",\"position\":[4493,1447],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":184,\"stationName\":\"曲阳路\",\"position\":[4716,1316],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":185,\"stationName\":\"四平路\",\"position\":[4820,1332],\"shape\":\"cicle\",\"lineIds\":[9,11]},{\"stationId\":186,\"stationName\":\"鞍山新村\",\"position\":[4902,1349],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":187,\"stationName\":\"江浦路\",\"position\":[4988,1332],\"shape\":\"cicle\",\"lineIds\":[9,21]},{\"stationId\":188,\"stationName\":\"黄兴路\",\"position\":[5089,1293],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":189,\"stationName\":\"延吉中路\",\"position\":[5154,1196],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":190,\"stationName\":\"黄兴公园\",\"position\":[5138,1127],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":191,\"stationName\":\"翔殷路\",\"position\":[5124,1031],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":2},{\"stationId\":192,\"stationName\":\"嫩江路\",\"position\":[5124,933],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":2},{\"stationId\":193,\"stationName\":\"市光路\",\"position\":[5124,854],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":2},{\"stationId\":194,\"stationName\":\"曹路\",\"position\":[6636,1368],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":195,\"stationName\":\"民雷路\",\"position\":[6486,1398],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":196,\"stationName\":\"顾唐路\",\"position\":[6369,1420],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":197,\"stationName\":\"金海路\",\"position\":[6191,1450],\"shape\":\"cicle\",\"lineIds\":[10,15],\"tagDirection\":1},{\"stationId\":198,\"stationName\":\"金吉路\",\"position\":[6092,1438],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":199,\"stationName\":\"金桥\",\"position\":[5918,1473],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":200,\"stationName\":\"台儿庄路\",\"position\":[5779,1553],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":3},{\"stationId\":201,\"stationName\":\"蓝天路\",\"position\":[5585,1671],\"shape\":\"cicle\",\"lineIds\":[10,17]},{\"stationId\":202,\"stationName\":\"芳甸路\",\"position\":[5389,1763],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":203,\"stationName\":\"杨高中路\",\"position\":[5291,1806],\"shape\":\"cicle\",\"lineIds\":[10,21],\"tagDirection\":6},{\"stationId\":204,\"stationName\":\"商城路\",\"position\":[4967,1779],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":6},{\"stationId\":205,\"stationName\":\"小南门\",\"position\":[4789,1913],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":206,\"stationName\":\"马当路\",\"position\":[4577,1986],\"shape\":\"cicle\",\"lineIds\":[10,16]},{\"stationId\":207,\"stationName\":\"打浦桥\",\"position\":[4491,2018],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":208,\"stationName\":\"嘉善路\",\"position\":[4412,2053],\"shape\":\"cicle\",\"lineIds\":[10,15]},{\"stationId\":209,\"stationName\":\"桂林路\",\"position\":[3985,2333],\"shape\":\"cicle\",\"lineIds\":[10,18]},{\"stationId\":210,\"stationName\":\"漕河泾开发区\",\"position\":[3782,2375],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":211,\"stationName\":\"合川路\",\"position\":[3652,2416],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":212,\"stationName\":\"星中路\",\"position\":[3494,2500],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":213,\"stationName\":\"七宝\",\"position\":[3297,2528],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":214,\"stationName\":\"中春路\",\"position\":[3182,2587],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":215,\"stationName\":\"九亭\",\"position\":[2999,2709],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":216,\"stationName\":\"泗泾\",\"position\":[2407,2898],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":217,\"stationName\":\"佘山\",\"position\":[2102,3040],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":218,\"stationName\":\"洞泾\",\"position\":[2109,3236],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":219,\"stationName\":\"松江大学城\",\"position\":[2130,3541],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":220,\"stationName\":\"松江新城\",\"position\":[2112,3778],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":221,\"stationName\":\"松江体育中心\",\"position\":[2110,3921],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":222,\"stationName\":\"醉白池\",\"position\":[2098,4070],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":223,\"stationName\":\"松江南站\",\"position\":[2114,4233],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":224,\"stationName\":\"基隆路\",\"position\":[5709,568],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":225,\"stationName\":\"高桥\",\"position\":[5434,555],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":0},{\"stationId\":226,\"stationName\":\"高桥西\",\"position\":[5297,566],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":227,\"stationName\":\"双江路\",\"position\":[5199,545],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":228,\"stationName\":\"国帆路\",\"position\":[4936,686],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":3},{\"stationId\":229,\"stationName\":\"新江湾城\",\"position\":[4874,796],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":230,\"stationName\":\"殷高东路\",\"position\":[4873,864],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":231,\"stationName\":\"三门路\",\"position\":[4888,949],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":1},{\"stationId\":232,\"stationName\":\"江湾体育场\",\"position\":[4938,1038],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":2},{\"stationId\":233,\"stationName\":\"五角场\",\"position\":[4951,1101],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":234,\"stationName\":\"国权路\",\"position\":[4905,1188],\"shape\":\"cicle\",\"lineIds\":[11,21]},{\"stationId\":235,\"stationName\":\"同济大学\",\"position\":[4868,1260],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":236,\"stationName\":\"邮电新村\",\"position\":[4747,1397],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":237,\"stationName\":\"四川北路\",\"position\":[4647,1561],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":2},{\"stationId\":238,\"stationName\":\"天潼路\",\"position\":[4628,1643],\"shape\":\"cicle\",\"lineIds\":[11,15]},{\"stationId\":239,\"stationName\":\"豫园\",\"position\":[4679,1801],\"shape\":\"cicle\",\"lineIds\":[11,17]},{\"stationId\":240,\"stationName\":\"新天地\",\"position\":[4556,1918],\"shape\":\"cicle\",\"lineIds\":[11,16],\"tagDirection\":0},{\"stationId\":241,\"stationName\":\"上海图书馆\",\"position\":[4248,2002],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":242,\"stationName\":\"交通大学\",\"position\":[4157,2059],\"shape\":\"cicle\",\"lineIds\":[11,14]},{\"stationId\":243,\"stationName\":\"宋园路\",\"position\":[3925,2116],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":3},{\"stationId\":244,\"stationName\":\"伊犁路\",\"position\":[3844,2092],\"shape\":\"cicle\",\"lineIds\":[11],\"tagDirection\":0},{\"stationId\":245,\"stationName\":\"水城路\",\"position\":[3727,2086],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":246,\"stationName\":\"龙溪路\",\"position\":[3605,2137],\"shape\":\"cicle\",\"lineIds\":[11,25]},{\"stationId\":247,\"stationName\":\"龙柏新村\",\"position\":[3509,2312],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":248,\"stationName\":\"紫藤路\",\"position\":[3453,2384],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":249,\"stationName\":\"航中路\",\"position\":[3358,2427],\"shape\":\"cicle\",\"lineIds\":[25]},{\"stationId\":250,\"stationName\":\"上海动物园\",\"position\":[3486,2179],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":251,\"stationName\":\"虹桥1号航站楼\",\"position\":[3278,2168],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":252,\"stationName\":\"嘉定北\",\"position\":[2178,166],\"shape\":\"cicle\",\"lineIds\":[26]},{\"stationId\":253,\"stationName\":\"嘉定西\",\"position\":[2083,310],\"shape\":\"cicle\",\"lineIds\":[26]},{\"stationId\":254,\"stationName\":\"白银路\",\"position\":[2258,628],\"shape\":\"cicle\",\"lineIds\":[26]},{\"stationId\":255,\"stationName\":\"嘉定新城\",\"position\":[2348,781],\"shape\":\"cicle\",\"lineIds\":[14,26]},{\"stationId\":256,\"stationName\":\"马陆\",\"position\":[2574,884],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":257,\"stationName\":\"陈翔公路\",\"position\":[2873,1016],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":258,\"stationName\":\"南翔\",\"position\":[3036,1112],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":259,\"stationName\":\"桃浦新村\",\"position\":[3301,1265],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":260,\"stationName\":\"武威路\",\"position\":[3451,1315],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":261,\"stationName\":\"祁连山路\",\"position\":[3565,1365],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":262,\"stationName\":\"李子园\",\"position\":[3704,1391],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":263,\"stationName\":\"上海西站\",\"position\":[3814,1454],\"shape\":\"cicle\",\"lineIds\":[14,18]},{\"stationId\":264,\"stationName\":\"真如\",\"position\":[3877,1574],\"shape\":\"cicle\",\"lineIds\":[14,17]},{\"stationId\":265,\"stationName\":\"枫桥路\",\"position\":[3919,1663],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":6},{\"stationId\":266,\"stationName\":\"隆德路\",\"position\":[4040,1776],\"shape\":\"cicle\",\"lineIds\":[14,16]},{\"stationId\":267,\"stationName\":\"上海游泳馆\",\"position\":[4219,2290],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":1},{\"stationId\":268,\"stationName\":\"龙华\",\"position\":[4334,2354],\"shape\":\"cicle\",\"lineIds\":[14,15]},{\"stationId\":269,\"stationName\":\"云锦路\",\"position\":[4390,2416],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":270,\"stationName\":\"龙耀路\",\"position\":[4402,2484],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":271,\"stationName\":\"三林\",\"position\":[4923,2649],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":272,\"stationName\":\"三林东\",\"position\":[5035,2617],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":3},{\"stationId\":273,\"stationName\":\"浦三路\",\"position\":[5195,2573],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":274,\"stationName\":\"御桥\",\"position\":[5514,2500],\"shape\":\"cicle\",\"lineIds\":[14,21],\"tagDirection\":7},{\"stationId\":275,\"stationName\":\"罗山路\",\"position\":[5736,2549],\"shape\":\"cicle\",\"lineIds\":[14,19]},{\"stationId\":276,\"stationName\":\"秀沿路\",\"position\":[5789,2700],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":277,\"stationName\":\"康新公路\",\"position\":[5977,2777],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":278,\"stationName\":\"迪士尼\",\"position\":[6484,2669],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":279,\"stationName\":\"上海赛车场\",\"position\":[2066,762],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":280,\"stationName\":\"昌吉东路\",\"position\":[1809,1145],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":281,\"stationName\":\"上海汽车城\",\"position\":[1612,1227],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":282,\"stationName\":\"安亭\",\"position\":[1425,1196],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":283,\"stationName\":\"兆丰路\",\"position\":[1308,1191],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":284,\"stationName\":\"光明路\",\"position\":[977,1119],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":285,\"stationName\":\"花桥\",\"position\":[849,1093],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":286,\"stationName\":\"七莘路\",\"position\":[3429,2765],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":287,\"stationName\":\"虹莘路\",\"position\":[3608,2707],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":288,\"stationName\":\"顾戴路\",\"position\":[3723,2672],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":289,\"stationName\":\"东兰路\",\"position\":[3724,2523],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":290,\"stationName\":\"虹梅路\",\"position\":[3777,2478],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":291,\"stationName\":\"虹漕路\",\"position\":[3910,2441],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":292,\"stationName\":\"桂林公园\",\"position\":[4001,2411],\"shape\":\"cicle\",\"lineIds\":[15,18],\"tagDirection\":1},{\"stationId\":293,\"stationName\":\"国际客运中心\",\"position\":[4786,1580],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":294,\"stationName\":\"提篮桥\",\"position\":[4873,1546],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":7},{\"stationId\":295,\"stationName\":\"江浦公园\",\"position\":[5042,1436],\"shape\":\"cicle\",\"lineIds\":[15,21]},{\"stationId\":296,\"stationName\":\"宁国路\",\"position\":[5128,1395],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":297,\"stationName\":\"隆昌路\",\"position\":[5252,1329],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":298,\"stationName\":\"爱国路\",\"position\":[5331,1283],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":299,\"stationName\":\"复兴岛\",\"position\":[5418,1273],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":300,\"stationName\":\"东陆路\",\"position\":[5596,1256],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":301,\"stationName\":\"杨高北路\",\"position\":[5834,1280],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":302,\"stationName\":\"金京路\",\"position\":[5959,1283],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":303,\"stationName\":\"申江路\",\"position\":[6073,1279],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":304,\"stationName\":\"金运路\",\"position\":[2998,1671],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":305,\"stationName\":\"金沙江西路\",\"position\":[3156,1670],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":306,\"stationName\":\"丰庄\",\"position\":[3356,1656],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":307,\"stationName\":\"祁连山南路\",\"position\":[3477,1705],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":308,\"stationName\":\"真北路\",\"position\":[3624,1759],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":309,\"stationName\":\"大渡河路\",\"position\":[3749,1764],\"shape\":\"cicle\",\"lineIds\":[16,18],\"tagDirection\":5},{\"stationId\":310,\"stationName\":\"武宁路\",\"position\":[4110,1738],\"shape\":\"cicle\",\"lineIds\":[16,17]},{\"stationId\":311,\"stationName\":\"江宁路\",\"position\":[4253,1638],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":312,\"stationName\":\"自然博物馆\",\"position\":[4428,1717],\"shape\":\"cicle\",\"lineIds\":[16],\"tagDirection\":6},{\"stationId\":313,\"stationName\":\"淮海中路\",\"position\":[4448,1881],\"shape\":\"cicle\",\"lineIds\":[16],\"tagDirection\":6},{\"stationId\":314,\"stationName\":\"世博会博物馆\",\"position\":[4621,2105],\"shape\":\"cicle\",\"lineIds\":[16],\"tagDirection\":4},{\"stationId\":315,\"stationName\":\"世博大道\",\"position\":[4648,2253],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":316,\"stationName\":\"华鹏路\",\"position\":[5070,2318],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":317,\"stationName\":\"下南路\",\"position\":[5207,2288],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":318,\"stationName\":\"北蔡\",\"position\":[5325,2280],\"shape\":\"cicle\",\"lineIds\":[16],\"tagDirection\":0},{\"stationId\":319,\"stationName\":\"陈春路\",\"position\":[5387,2330],\"shape\":\"cicle\",\"lineIds\":[16],\"tagDirection\":5},{\"stationId\":320,\"stationName\":\"莲溪路\",\"position\":[5469,2390],\"shape\":\"cicle\",\"lineIds\":[16,21]},{\"stationId\":321,\"stationName\":\"华夏中路\",\"position\":[5636,2324],\"shape\":\"cicle\",\"lineIds\":[16,19]},{\"stationId\":322,\"stationName\":\"中科路\",\"position\":[5829,2293],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":323,\"stationName\":\"学林路\",\"position\":[5948,2246],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":324,\"stationName\":\"张江路\",\"position\":[6096,2190],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":325,\"stationName\":\"封浜\",\"position\":[2775,1406],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":326,\"stationName\":\"乐秀路\",\"position\":[2946,1428],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":327,\"stationName\":\"临洮路\",\"position\":[3113,1451],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":328,\"stationName\":\"嘉怡路\",\"position\":[3262,1489],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":329,\"stationName\":\"定边路\",\"position\":[3429,1517],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":330,\"stationName\":\"真新新村\",\"position\":[3524,1526],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":331,\"stationName\":\"真光路\",\"position\":[3646,1548],\"shape\":\"cicle\",\"lineIds\":[17],\"tagDirection\":5},{\"stationId\":332,\"stationName\":\"铜川路\",\"position\":[3775,1574],\"shape\":\"cicle\",\"lineIds\":[17,18],\"tagDirection\":7},{\"stationId\":333,\"stationName\":\"中宁路\",\"position\":[3950,1631],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":334,\"stationName\":\"武定路\",\"position\":[4166,1808],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":335,\"stationName\":\"浦东南路\",\"position\":[4929,1696],\"shape\":\"cicle\",\"lineIds\":[17],\"tagDirection\":7},{\"stationId\":336,\"stationName\":\"源深路\",\"position\":[5115,1668],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":337,\"stationName\":\"昌邑路\",\"position\":[5206,1642],\"shape\":\"cicle\",\"lineIds\":[17,21]},{\"stationId\":338,\"stationName\":\"歇浦路\",\"position\":[5320,1574],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":339,\"stationName\":\"黄杨路\",\"position\":[5715,1741],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":340,\"stationName\":\"云顺路\",\"position\":[5808,1711],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":341,\"stationName\":\"浦东足球场\",\"position\":[5959,1665],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":342,\"stationName\":\"金粤路\",\"position\":[6095,1660],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":343,\"stationName\":\"桂桥路\",\"position\":[6156,1587],\"shape\":\"cicle\",\"lineIds\":[17]},{\"stationId\":344,\"stationName\":\"锦秋路\",\"position\":[3622,879],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":345,\"stationName\":\"丰翔路\",\"position\":[3613,999],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":346,\"stationName\":\"南大路\",\"position\":[3608,1089],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":347,\"stationName\":\"祁安路\",\"position\":[3653,1166],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":348,\"stationName\":\"古浪路\",\"position\":[3727,1236],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":349,\"stationName\":\"武威东路\",\"position\":[3726,1325],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":2},{\"stationId\":350,\"stationName\":\"梅岭北路\",\"position\":[3775,1648],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":6},{\"stationId\":351,\"stationName\":\"长风公园\",\"position\":[3768,1829],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":352,\"stationName\":\"红宝石路\",\"position\":[3788,2093],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":353,\"stationName\":\"姚虹路\",\"position\":[3869,2166],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":5},{\"stationId\":354,\"stationName\":\"吴中路\",\"position\":[3944,2238],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":5},{\"stationId\":355,\"stationName\":\"华东理工大学\",\"position\":[4095,2639],\"shape\":\"cicle\",\"lineIds\":[18],\"tagDirection\":2},{\"stationId\":356,\"stationName\":\"罗秀路\",\"position\":[4163,2766],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":357,\"stationName\":\"朱梅路\",\"position\":[4183,2838],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":358,\"stationName\":\"华泾西\",\"position\":[4206,2947],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":359,\"stationName\":\"虹梅南路\",\"position\":[4135,3043],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":360,\"stationName\":\"景西路\",\"position\":[3992,3084],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":361,\"stationName\":\"曙建路\",\"position\":[3984,3175],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":362,\"stationName\":\"双柏路\",\"position\":[4022,3249],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":363,\"stationName\":\"元江路\",\"position\":[4124,3453],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":364,\"stationName\":\"永德路\",\"position\":[4237,3690],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":365,\"stationName\":\"紫竹高新区\",\"position\":[4317,3849],\"shape\":\"cicle\",\"lineIds\":[18]},{\"stationId\":366,\"stationName\":\"周浦东\",\"position\":[5874,2981],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":367,\"stationName\":\"鹤沙航城\",\"position\":[5917,3303],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":368,\"stationName\":\"航头东\",\"position\":[5980,3532],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":369,\"stationName\":\"新场\",\"position\":[6294,3626],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":370,\"stationName\":\"野生动物园\",\"position\":[6797,3578],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":371,\"stationName\":\"惠南\",\"position\":[7421,3543],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":372,\"stationName\":\"惠南东\",\"position\":[7743,3817],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":373,\"stationName\":\"书院\",\"position\":[8310,4489],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":374,\"stationName\":\"临港大道\",\"position\":[8913,4846],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":375,\"stationName\":\"滴水湖\",\"position\":[9100,5009],\"shape\":\"cicle\",\"lineIds\":[19]},{\"stationId\":376,\"stationName\":\"诸光路\",\"position\":[2735,2164],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":377,\"stationName\":\"蟠龙路\",\"position\":[2591,2218],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":378,\"stationName\":\"徐盈路\",\"position\":[2344,2300],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":379,\"stationName\":\"徐泾北城\",\"position\":[2221,2326],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":380,\"stationName\":\"嘉松中路\",\"position\":[2044,2440],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":381,\"stationName\":\"赵巷\",\"position\":[1727,2469],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":382,\"stationName\":\"汇金路\",\"position\":[1321,2469],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":383,\"stationName\":\"青浦新城\",\"position\":[1061,2492],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":384,\"stationName\":\"漕盈路\",\"position\":[774,2477],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":385,\"stationName\":\"淀山湖大道\",\"position\":[626,2737],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":386,\"stationName\":\"朱家角\",\"position\":[295,3075],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":387,\"stationName\":\"东方绿舟\",\"position\":[0,3096],\"shape\":\"cicle\",\"lineIds\":[20]},{\"stationId\":388,\"stationName\":\"殷高路\",\"position\":[4760,864],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":389,\"stationName\":\"上海财经大学\",\"position\":[4768,1004],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":2},{\"stationId\":390,\"stationName\":\"复旦大学\",\"position\":[4800,1118],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":391,\"stationName\":\"抚顺路\",\"position\":[4963,1245],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":392,\"stationName\":\"平凉路\",\"position\":[5072,1491],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":2},{\"stationId\":393,\"stationName\":\"丹阳路\",\"position\":[5116,1543],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":2},{\"stationId\":394,\"stationName\":\"迎春路\",\"position\":[5315,1871],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":1},{\"stationId\":395,\"stationName\":\"芳芯路\",\"position\":[5397,2170],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":2},{\"stationId\":396,\"stationName\":\"北中路\",\"position\":[5418,2254],\"shape\":\"cicle\",\"lineIds\":[21],\"tagDirection\":2},{\"stationId\":397,\"stationName\":\"康桥\",\"position\":[5478,2739],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":398,\"stationName\":\"周浦\",\"position\":[5481,2940],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":399,\"stationName\":\"繁荣路\",\"position\":[5510,3056],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":400,\"stationName\":\"沈梅路\",\"position\":[5611,3170],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":401,\"stationName\":\"鹤涛路\",\"position\":[5664,3363],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":402,\"stationName\":\"下沙\",\"position\":[5695,3537],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":403,\"stationName\":\"航头\",\"position\":[5765,3708],\"shape\":\"cicle\",\"lineIds\":[21]},{\"stationId\":404,\"stationName\":\"三鲁公路\",\"position\":[5079,3520],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":405,\"stationName\":\"闵瑞路\",\"position\":[5108,3602],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":406,\"stationName\":\"浦航路\",\"position\":[5111,3671],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":407,\"stationName\":\"东城一路\",\"position\":[5126,3777],\"shape\":\"cicle\",\"lineIds\":[23]},{\"stationId\":408,\"stationName\":\"汇臻路\",\"position\":[5050,3829],\"shape\":\"cicle\",\"lineIds\":[23]}],\"lines\":[{\"lineId\":1,\"lineName\":\"1号线\",\"color\":\"#E3002A\",\"stationIds\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],\"sign\":1,\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"2号线\",\"color\":\"#86B81C\",\"stationIds\":[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,13,47,48,49,50,51,52,53,54,55,56,57],\"sign\":2,\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":3,\"lineName\":\"3号线\",\"color\":\"#FCD600\",\"stationIds\":[58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,16,74,75,76,77,50,78,79,80,81,82,83,5],\"sign\":3,\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,true,false,false,false,false,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"4号线\",\"color\":\"#5A2B8D\",\"stationIds\":[80,79,78,50,77,76,75,74,16,73,84,85,86,87,88,43,89,90,91,92,93,94,95,96,97,7,80],\"sign\":4,\"order\":3,\"bendFirst\":[true,true,true,true,false,true,true,false,false,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":5,\"lineName\":\"5号线\",\"color\":\"#96499A\",\"stationIds\":[115,114,113,112,111,110,109,108,102,103,104,105,106,107,1],\"sign\":5,\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"6号线\",\"color\":\"#F0087D\",\"stationIds\":[116,117,118,119,120,121,122,123,124,90,125,43,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141],\"sign\":\"6\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":8,\"lineName\":\"7号线\",\"color\":\"#EE782E\",\"stationIds\":[142,40,143,144,145,122,146,147,148,149,150,96,151,10,48,152,153,75,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],\"sign\":\"7\",\"order\":8,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":9,\"lineName\":\"8号线\",\"color\":\"#01A2E2\",\"stationIds\":[169,170,171,172,173,174,116,175,176,147,177,93,178,179,180,13,181,182,183,71,184,185,186,187,188,189,190,191,192,193],\"sign\":\"8\",\"order\":9,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"9号线\",\"color\":\"#69C7F4\",\"stationIds\":[194,195,196,197,198,199,200,201,202,203,43,204,205,178,206,207,208,151,8,80,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223],\"sign\":\"9\",\"order\":10,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":11,\"lineName\":\"10号线\",\"color\":\"#C6AFD4\",\"stationIds\":[224,141,225,226,227,228,229,230,231,232,233,234,235,185,236,84,237,238,46,239,179,240,11,241,242,79,243,244,245,246,250,251,55,56],\"sign\":\"10\",\"order\":11,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":14,\"lineName\":\"11号线\",\"color\":\"#871C2A\",\"stationIds\":[278,277,276,275,274,273,272,271,116,270,269,268,267,8,242,49,266,76,265,264,263,262,261,260,259,258,257,256,255,279,280,281,282,283,284,285],\"sign\":\"11\",\"order\":14,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":15,\"lineName\":\"12号线\",\"color\":\"#007A61\",\"stationIds\":[286,287,288,289,290,291,292,6,82,268,150,95,208,11,47,15,181,238,293,294,86,295,296,297,298,299,300,134,301,302,303,197],\"sign\":\"12\",\"order\":15,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":16,\"lineName\":\"13号线\",\"color\":\"#EB81B9\",\"stationIds\":[304,305,306,307,308,309,77,266,310,153,311,15,312,47,313,240,206,314,315,148,176,121,316,317,318,319,320,321,322,323,324],\"sign\":\"13\",\"order\":16,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":17,\"lineName\":\"14号线\",\"color\":\"#818530\",\"stationIds\":[325,326,327,328,329,330,331,332,264,333,76,310,334,48,12,180,239,45,335,88,336,337,338,130,201,339,340,341,342,343],\"sign\":\"14\",\"order\":17,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":18,\"lineName\":\"15号线\",\"color\":\"#DAC17D\",\"stationIds\":[164,344,345,346,347,348,349,263,332,350,309,351,51,352,353,354,209,292,5,355,356,357,358,359,360,361,362,363,364,365],\"sign\":\"15\",\"order\":18,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":19,\"lineName\":\"16号线\",\"color\":\"#98D1C0\",\"stationIds\":[40,321,275,366,367,368,369,370,371,372,373,374,375],\"sign\":\"16\",\"order\":19,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":20,\"lineName\":\"17号线\",\"color\":\"#B85A4E\",\"stationIds\":[56,376,377,378,379,380,381,382,383,384,385,386,387],\"sign\":\"17\",\"order\":20,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":21,\"lineName\":\"18号线\",\"color\":\"#D0970A\",\"stationIds\":[66,388,389,390,234,391,187,295,392,393,337,127,203,394,40,395,396,320,274,397,398,399,400,401,402,403],\"sign\":\"18\",\"order\":21,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":22,\"lineName\":\"磁悬浮\",\"color\":\"#008187\",\"stationIds\":[29,40],\"sign\":\"磁浮线\",\"order\":22,\"bendFirst\":[true,true]},{\"lineId\":23,\"lineName\":\"浦江线\",\"color\":\"#B5B5B6\",\"stationIds\":[169,404,405,406,407,408],\"sign\":\"浦江线\",\"order\":23,\"bendFirst\":[true,true,true,true,true,true]},{\"lineId\":24,\"lineName\":\"5号线支线\",\"color\":\"#96499A\",\"stationIds\":[98,99,100,101,102],\"sign\":\"5\",\"order\":24,\"bendFirst\":[true,true,true,true,true],\"subLine\":true},{\"lineId\":25,\"lineName\":\"10号线支线\",\"color\":\"#C6AFD4\",\"stationIds\":[249,248,247,246],\"sign\":\"10\",\"order\":25,\"bendFirst\":[true,true,true,true],\"subLine\":true},{\"lineId\":26,\"lineName\":\"11号线支线\",\"color\":\"#871C2A\",\"stationIds\":[255,254,253,252],\"sign\":\"11\",\"order\":26,\"bendFirst\":[false,true,true,true],\"subLine\":true}],\"title\":\"上海\"}"
  },
  {
    "path": "public/shenzhen.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"罗湖\",\"position\":[3489,2743],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":6},{\"stationId\":2,\"stationName\":\"国贸\",\"position\":[3491,2667],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":3,\"stationName\":\"老街\",\"position\":[3472,2621],\"shape\":\"cicle\",\"lineIds\":[1,4],\"tagDirection\":7},{\"stationId\":4,\"stationName\":\"大剧院\",\"position\":[3380,2646],\"shape\":\"cicle\",\"lineIds\":[1,3]},{\"stationId\":5,\"stationName\":\"科学馆\",\"position\":[3254,2658],\"shape\":\"cicle\",\"lineIds\":[1,7],\"tagDirection\":5},{\"stationId\":6,\"stationName\":\"华强路\",\"position\":[3154,2659],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":7,\"stationName\":\"岗厦\",\"position\":[2984,2715],\"shape\":\"cicle\",\"lineIds\":[1,11],\"tagDirection\":3},{\"stationId\":8,\"stationName\":\"会展中心\",\"position\":[2913,2716],\"shape\":\"cicle\",\"lineIds\":[1,5],\"tagDirection\":4},{\"stationId\":9,\"stationName\":\"购物公园\",\"position\":[2848,2717],\"shape\":\"cicle\",\"lineIds\":[1,4]},{\"stationId\":10,\"stationName\":\"香蜜湖\",\"position\":[2689,2675],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":4},{\"stationId\":11,\"stationName\":\"车公庙\",\"position\":[2561,2701],\"shape\":\"cicle\",\"lineIds\":[1,9,10,12],\"tagDirection\":3},{\"stationId\":12,\"stationName\":\"竹子林\",\"position\":[2441,2730],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":13,\"stationName\":\"侨城东\",\"position\":[2269,2740],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":14,\"stationName\":\"华侨城\",\"position\":[2156,2729],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":4},{\"stationId\":15,\"stationName\":\"世界之窗\",\"position\":[2044,2695],\"shape\":\"cicle\",\"lineIds\":[1,3],\"tagDirection\":5},{\"stationId\":16,\"stationName\":\"白石洲\",\"position\":[1973,2668],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":0},{\"stationId\":17,\"stationName\":\"高新园\",\"position\":[1841,2661],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":18,\"stationName\":\"深大\",\"position\":[1744,2677],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":19,\"stationName\":\"桃园\",\"position\":[1550,2749],\"shape\":\"cicle\",\"lineIds\":[1,13]},{\"stationId\":20,\"stationName\":\"大新\",\"position\":[1453,2741],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":21,\"stationName\":\"鲤鱼门\",\"position\":[1333,2744],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":22,\"stationName\":\"前海湾\",\"position\":[1282,2693],\"shape\":\"cicle\",\"lineIds\":[1,6,12]},{\"stationId\":23,\"stationName\":\"新安\",\"position\":[1248,2589],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":24,\"stationName\":\"宝安中心\",\"position\":[1175,2518],\"shape\":\"cicle\",\"lineIds\":[1,6],\"tagDirection\":2},{\"stationId\":25,\"stationName\":\"宝体\",\"position\":[1109,2456],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":26,\"stationName\":\"坪洲\",\"position\":[1009,2375],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":27,\"stationName\":\"西乡\",\"position\":[933,2312],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":1},{\"stationId\":28,\"stationName\":\"固戍\",\"position\":[770,2050],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":29,\"stationName\":\"后瑞\",\"position\":[657,1775],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":30,\"stationName\":\"机场东\",\"position\":[529,1594],\"shape\":\"cicle\",\"lineIds\":[1,13]},{\"stationId\":31,\"stationName\":\"比亚迪北\",\"position\":[5913,1242],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":2},{\"stationId\":32,\"stationName\":\"龙背\",\"position\":[5897,1191],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":1},{\"stationId\":33,\"stationName\":\"自然博物馆西\",\"position\":[5884,1145],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":1},{\"stationId\":34,\"stationName\":\"未来城\",\"position\":[5828,1080],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":2},{\"stationId\":35,\"stationName\":\"燕子岭\",\"position\":[5918,1035],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":36,\"stationName\":\"综合保税区\",\"position\":[5914,971],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":37,\"stationName\":\"中芯国际\",\"position\":[5860,948],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":38,\"stationName\":\"坪山中心\",\"position\":[5818,954],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":3},{\"stationId\":39,\"stationName\":\"文化聚落\",\"position\":[5758,962],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":40,\"stationName\":\"站前路东\",\"position\":[5707,979],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":0},{\"stationId\":41,\"stationName\":\"坪山高铁站\",\"position\":[5577,1009],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":42,\"stationName\":\"赤湾\",\"position\":[1277,3272],\"shape\":\"cicle\",\"lineIds\":[3,6]},{\"stationId\":43,\"stationName\":\"蛇口港\",\"position\":[1426,3298],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":44,\"stationName\":\"海上世界\",\"position\":[1453,3213],\"shape\":\"cicle\",\"lineIds\":[3,13],\"tagDirection\":3},{\"stationId\":45,\"stationName\":\"水湾\",\"position\":[1499,3180],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":46,\"stationName\":\"东角头\",\"position\":[1614,3201],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":47,\"stationName\":\"湾厦\",\"position\":[1688,3130],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":48,\"stationName\":\"海月\",\"position\":[1679,3060],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":49,\"stationName\":\"登良\",\"position\":[1678,2972],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":50,\"stationName\":\"后海\",\"position\":[1727,2880],\"shape\":\"cicle\",\"lineIds\":[3,12]},{\"stationId\":51,\"stationName\":\"科苑\",\"position\":[1764,2794],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":6},{\"stationId\":52,\"stationName\":\"红树湾\",\"position\":[1987,2812],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":7},{\"stationId\":53,\"stationName\":\"侨城北\",\"position\":[2194,2624],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":54,\"stationName\":\"深康\",\"position\":[2291,2599],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":55,\"stationName\":\"安托山\",\"position\":[2365,2576],\"shape\":\"cicle\",\"lineIds\":[3,9],\"tagDirection\":0},{\"stationId\":56,\"stationName\":\"侨香\",\"position\":[2446,2566],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":57,\"stationName\":\"香蜜\",\"position\":[2541,2536],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":58,\"stationName\":\"香梅北\",\"position\":[2629,2525],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":0},{\"stationId\":59,\"stationName\":\"景田\",\"position\":[2736,2530],\"shape\":\"cicle\",\"lineIds\":[3,10]},{\"stationId\":60,\"stationName\":\"莲花西\",\"position\":[2803,2597],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":61,\"stationName\":\"福田\",\"position\":[2831,2663],\"shape\":\"cicle\",\"lineIds\":[3,4,12]},{\"stationId\":62,\"stationName\":\"市民中心\",\"position\":[2914,2646],\"shape\":\"cicle\",\"lineIds\":[3,5]},{\"stationId\":63,\"stationName\":\"岗厦北\",\"position\":[2982,2681],\"shape\":\"cicle\",\"lineIds\":[3,11,12,14],\"tagDirection\":3},{\"stationId\":64,\"stationName\":\"华强北\",\"position\":[3156,2619],\"shape\":\"cicle\",\"lineIds\":[3,9],\"tagDirection\":7},{\"stationId\":65,\"stationName\":\"燕南\",\"position\":[3228,2618],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":0},{\"stationId\":66,\"stationName\":\"湖贝\",\"position\":[3557,2621],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":2},{\"stationId\":67,\"stationName\":\"黄贝岭\",\"position\":[3666,2603],\"shape\":\"cicle\",\"lineIds\":[3,6]},{\"stationId\":68,\"stationName\":\"新秀\",\"position\":[3790,2587],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":69,\"stationName\":\"莲塘口岸\",\"position\":[3858,2529],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":70,\"stationName\":\"仙湖路\",\"position\":[3966,2423],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":71,\"stationName\":\"莲塘\",\"position\":[4045,2423],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":72,\"stationName\":\"梧桐山南\",\"position\":[4134,2485],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":73,\"stationName\":\"沙头角\",\"position\":[4534,2521],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":74,\"stationName\":\"海山\",\"position\":[4679,2508],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":75,\"stationName\":\"盐田港西\",\"position\":[4771,2438],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":76,\"stationName\":\"深外高中\",\"position\":[4748,2223],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":77,\"stationName\":\"盐田路\",\"position\":[4865,2167],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":78,\"stationName\":\"鸿安围\",\"position\":[4944,2158],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":79,\"stationName\":\"盐田墟\",\"position\":[5066,2191],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":80,\"stationName\":\"大梅沙\",\"position\":[5380,2123],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":81,\"stationName\":\"小梅沙\",\"position\":[5567,2042],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":82,\"stationName\":\"福保\",\"position\":[2858,2985],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":83,\"stationName\":\"益田\",\"position\":[2812,2901],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":3},{\"stationId\":84,\"stationName\":\"石厦\",\"position\":[2838,2827],\"shape\":\"cicle\",\"lineIds\":[4,9],\"tagDirection\":7},{\"stationId\":85,\"stationName\":\"少年宫\",\"position\":[2904,2578],\"shape\":\"cicle\",\"lineIds\":[4,5],\"tagDirection\":1},{\"stationId\":86,\"stationName\":\"莲花村\",\"position\":[2981,2577],\"shape\":\"cicle\",\"lineIds\":[4,11],\"tagDirection\":1},{\"stationId\":87,\"stationName\":\"华新\",\"position\":[3169,2574],\"shape\":\"cicle\",\"lineIds\":[4,9],\"tagDirection\":1},{\"stationId\":88,\"stationName\":\"通新岭\",\"position\":[3265,2573],\"shape\":\"cicle\",\"lineIds\":[4,7],\"tagDirection\":3},{\"stationId\":89,\"stationName\":\"红岭\",\"position\":[3348,2580],\"shape\":\"cicle\",\"lineIds\":[4,10]},{\"stationId\":90,\"stationName\":\"晒布\",\"position\":[3529,2571],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":7},{\"stationId\":91,\"stationName\":\"翠竹\",\"position\":[3601,2502],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":92,\"stationName\":\"田贝\",\"position\":[3603,2391],\"shape\":\"cicle\",\"lineIds\":[4,9]},{\"stationId\":93,\"stationName\":\"水贝\",\"position\":[3552,2324],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":94,\"stationName\":\"草埔\",\"position\":[3467,2219],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":95,\"stationName\":\"布吉\",\"position\":[3514,2040],\"shape\":\"cicle\",\"lineIds\":[4,6,14]},{\"stationId\":96,\"stationName\":\"木棉湾\",\"position\":[3605,1994],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":97,\"stationName\":\"大芬\",\"position\":[3686,1922],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":98,\"stationName\":\"丹竹头\",\"position\":[3783,1866],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":99,\"stationName\":\"六约\",\"position\":[4109,1721],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":100,\"stationName\":\"塘坑\",\"position\":[4229,1672],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":101,\"stationName\":\"横岗\",\"position\":[4392,1579],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":102,\"stationName\":\"永湖\",\"position\":[4483,1474],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":103,\"stationName\":\"荷坳\",\"position\":[4545,1333],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":104,\"stationName\":\"大运\",\"position\":[4584,1207],\"shape\":\"cicle\",\"lineIds\":[4,14,15]},{\"stationId\":105,\"stationName\":\"爱联\",\"position\":[4646,1089],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":106,\"stationName\":\"吉祥\",\"position\":[4745,969],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":107,\"stationName\":\"龙城广场\",\"position\":[4848,895],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":108,\"stationName\":\"南联\",\"position\":[4958,844],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":109,\"stationName\":\"双龙\",\"position\":[5076,776],\"shape\":\"cicle\",\"lineIds\":[4,15]},{\"stationId\":110,\"stationName\":\"福田口岸\",\"position\":[2975,2895],\"shape\":\"cicle\",\"lineIds\":[5,11]},{\"stationId\":111,\"stationName\":\"福民\",\"position\":[2961,2832],\"shape\":\"cicle\",\"lineIds\":[5,9,11]},{\"stationId\":112,\"stationName\":\"莲花北\",\"position\":[2896,2458],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":113,\"stationName\":\"上梅林\",\"position\":[2897,2359],\"shape\":\"cicle\",\"lineIds\":[5,10]},{\"stationId\":114,\"stationName\":\"民乐\",\"position\":[2790,2122],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":115,\"stationName\":\"白石龙\",\"position\":[2727,2049],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":116,\"stationName\":\"深圳北站\",\"position\":[2605,1959],\"shape\":\"cicle\",\"lineIds\":[5,6,7]},{\"stationId\":117,\"stationName\":\"红山\",\"position\":[2537,1845],\"shape\":\"cicle\",\"lineIds\":[5,7]},{\"stationId\":118,\"stationName\":\"上塘\",\"position\":[2430,1692],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":119,\"stationName\":\"龙胜\",\"position\":[2422,1616],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":120,\"stationName\":\"龙华\",\"position\":[2526,1547],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":121,\"stationName\":\"清湖\",\"position\":[2668,1423],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":122,\"stationName\":\"清湖北\",\"position\":[2706,1343],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":123,\"stationName\":\"竹村\",\"position\":[2705,1197],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":124,\"stationName\":\"茜坑\",\"position\":[2713,1091],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":125,\"stationName\":\"长湖\",\"position\":[2750,956],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":126,\"stationName\":\"观澜\",\"position\":[2850,912],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":127,\"stationName\":\"松元厦\",\"position\":[2951,858],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":128,\"stationName\":\"观澜湖\",\"position\":[3065,848],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":129,\"stationName\":\"牛湖\",\"position\":[3195,818],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":130,\"stationName\":\"荔湾\",\"position\":[1237,3086],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":131,\"stationName\":\"铁路公园\",\"position\":[1202,3035],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":132,\"stationName\":\"妈湾\",\"position\":[1162,2985],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":133,\"stationName\":\"前湾公园\",\"position\":[1198,2903],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":134,\"stationName\":\"前湾\",\"position\":[1260,2840],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":135,\"stationName\":\"桂湾\",\"position\":[1282,2740],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":136,\"stationName\":\"临海\",\"position\":[1195,2622],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":137,\"stationName\":\"宝华\",\"position\":[1153,2567],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":138,\"stationName\":\"翻身\",\"position\":[1235,2467],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":139,\"stationName\":\"灵芝\",\"position\":[1344,2374],\"shape\":\"cicle\",\"lineIds\":[6,13]},{\"stationId\":140,\"stationName\":\"洪浪北\",\"position\":[1408,2318],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":141,\"stationName\":\"兴东\",\"position\":[1492,2246],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":142,\"stationName\":\"留仙洞\",\"position\":[1738,2258],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":143,\"stationName\":\"西丽\",\"position\":[1846,2257],\"shape\":\"cicle\",\"lineIds\":[6,9]},{\"stationId\":144,\"stationName\":\"大学城\",\"position\":[1955,2244],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":145,\"stationName\":\"塘朗\",\"position\":[2299,2163],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":146,\"stationName\":\"长岭陂\",\"position\":[2405,2070],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":147,\"stationName\":\"民治\",\"position\":[2711,1888],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":148,\"stationName\":\"五和\",\"position\":[2909,1795],\"shape\":\"cicle\",\"lineIds\":[6,11]},{\"stationId\":149,\"stationName\":\"坂田\",\"position\":[3011,1789],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":150,\"stationName\":\"杨美\",\"position\":[3102,1796],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":151,\"stationName\":\"上水径\",\"position\":[3356,1843],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":152,\"stationName\":\"下水径\",\"position\":[3409,1915],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":153,\"stationName\":\"长龙\",\"position\":[3440,1983],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":154,\"stationName\":\"百鸽笼\",\"position\":[3606,2109],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":155,\"stationName\":\"布心\",\"position\":[3683,2254],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":156,\"stationName\":\"太安\",\"position\":[3673,2329],\"shape\":\"cicle\",\"lineIds\":[6,9]},{\"stationId\":157,\"stationName\":\"怡景\",\"position\":[3703,2505],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":158,\"stationName\":\"松岗\",\"position\":[599,341],\"shape\":\"cicle\",\"lineIds\":[7,12]},{\"stationId\":159,\"stationName\":\"溪头\",\"position\":[679,317],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":160,\"stationName\":\"松岗公园\",\"position\":[785,285],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":161,\"stationName\":\"薯田埔\",\"position\":[979,254],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":162,\"stationName\":\"合水口\",\"position\":[1112,248],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":163,\"stationName\":\"公明广场\",\"position\":[1216,289],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":164,\"stationName\":\"红花山\",\"position\":[1375,287],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":165,\"stationName\":\"楼村\",\"position\":[1536,305],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":166,\"stationName\":\"科学公园\",\"position\":[1643,289],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":167,\"stationName\":\"光明\",\"position\":[1755,347],\"shape\":\"cicle\",\"lineIds\":[7,8]},{\"stationId\":168,\"stationName\":\"光明大街\",\"position\":[1729,444],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":169,\"stationName\":\"凤凰城\",\"position\":[1631,589],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":170,\"stationName\":\"长圳\",\"position\":[1611,800],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":171,\"stationName\":\"上屋\",\"position\":[1688,1173],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":172,\"stationName\":\"官田\",\"position\":[1799,1231],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":173,\"stationName\":\"阳台山东\",\"position\":[2220,1383],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":174,\"stationName\":\"元芬\",\"position\":[2354,1501],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":175,\"stationName\":\"上芬\",\"position\":[2469,1660],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":176,\"stationName\":\"梅林关\",\"position\":[2834,2119],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":177,\"stationName\":\"翰岭\",\"position\":[2991,2322],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":1},{\"stationId\":178,\"stationName\":\"银湖\",\"position\":[3201,2381],\"shape\":\"cicle\",\"lineIds\":[7,10]},{\"stationId\":179,\"stationName\":\"八卦岭\",\"position\":[3249,2444],\"shape\":\"cicle\",\"lineIds\":[7,9],\"tagDirection\":6},{\"stationId\":180,\"stationName\":\"体育中心\",\"position\":[3263,2517],\"shape\":\"cicle\",\"lineIds\":[7],\"tagDirection\":3},{\"stationId\":181,\"stationName\":\"圳美\",\"position\":[1795,186],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":182,\"stationName\":\"中大\",\"position\":[1838,96],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":183,\"stationName\":\"深理工\",\"position\":[1988,0],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":184,\"stationName\":\"西丽湖\",\"position\":[1959,2128],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":185,\"stationName\":\"茶光\",\"position\":[1845,2322],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":186,\"stationName\":\"珠光\",\"position\":[1908,2381],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":187,\"stationName\":\"龙井\",\"position\":[2049,2424],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":188,\"stationName\":\"桃源村\",\"position\":[2122,2465],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":189,\"stationName\":\"深云\",\"position\":[2240,2498],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":190,\"stationName\":\"农林\",\"position\":[2484,2660],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":191,\"stationName\":\"上沙\",\"position\":[2657,2818],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":192,\"stationName\":\"沙尾\",\"position\":[2728,2856],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":193,\"stationName\":\"皇岗村\",\"position\":[2900,2832],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":4},{\"stationId\":194,\"stationName\":\"皇岗口岸\",\"position\":[3042,2846],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":195,\"stationName\":\"赤尾\",\"position\":[3138,2750],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":3},{\"stationId\":196,\"stationName\":\"华强南\",\"position\":[3170,2692],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":3},{\"stationId\":197,\"stationName\":\"黄木岗\",\"position\":[3175,2507],\"shape\":\"cicle\",\"lineIds\":[9,14]},{\"stationId\":198,\"stationName\":\"红岭北\",\"position\":[3345,2443],\"shape\":\"cicle\",\"lineIds\":[9,10],\"tagDirection\":0},{\"stationId\":199,\"stationName\":\"笋岗\",\"position\":[3415,2430],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":200,\"stationName\":\"洪湖\",\"position\":[3527,2403],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":201,\"stationName\":\"前湾\",\"position\":[1260,2840],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":202,\"stationName\":\"梦海\",\"position\":[1290,2875],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":203,\"stationName\":\"怡海\",\"position\":[1340,2914],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":204,\"stationName\":\"荔林\",\"position\":[1434,2945],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":205,\"stationName\":\"南油西\",\"position\":[1486,2973],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":206,\"stationName\":\"南油\",\"position\":[1560,2961],\"shape\":\"cicle\",\"lineIds\":[10,13]},{\"stationId\":207,\"stationName\":\"南山书城\",\"position\":[1589,2870],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":3},{\"stationId\":208,\"stationName\":\"深大南\",\"position\":[1659,2804],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":209,\"stationName\":\"粤海门\",\"position\":[1758,2737],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":4},{\"stationId\":210,\"stationName\":\"高新南\",\"position\":[1803,2736],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":211,\"stationName\":\"红树湾南\",\"position\":[2017,2834],\"shape\":\"cicle\",\"lineIds\":[10,12],\"tagDirection\":4},{\"stationId\":212,\"stationName\":\"深湾\",\"position\":[2088,2833],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":213,\"stationName\":\"深圳湾公园\",\"position\":[2233,2848],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":214,\"stationName\":\"下沙\",\"position\":[2546,2775],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":215,\"stationName\":\"香梅\",\"position\":[2699,2610],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":216,\"stationName\":\"梅景\",\"position\":[2682,2453],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":217,\"stationName\":\"下梅林\",\"position\":[2720,2407],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":218,\"stationName\":\"梅村\",\"position\":[2826,2379],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":219,\"stationName\":\"孖岭\",\"position\":[2980,2379],\"shape\":\"cicle\",\"lineIds\":[10,11]},{\"stationId\":220,\"stationName\":\"泥岗\",\"position\":[3279,2386],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":221,\"stationName\":\"园岭\",\"position\":[3347,2501],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":222,\"stationName\":\"红岭南\",\"position\":[3350,2664],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":223,\"stationName\":\"鹿丹村\",\"position\":[3388,2707],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":224,\"stationName\":\"人民南\",\"position\":[3484,2709],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":2},{\"stationId\":225,\"stationName\":\"向西村\",\"position\":[3560,2666],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":3},{\"stationId\":226,\"stationName\":\"文锦\",\"position\":[3612,2641],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":3},{\"stationId\":227,\"stationName\":\"双拥街\",\"position\":[3632,1077],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":228,\"stationName\":\"平湖\",\"position\":[3560,1127],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":229,\"stationName\":\"禾花\",\"position\":[3513,1203],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":230,\"stationName\":\"华南城\",\"position\":[3525,1304],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":231,\"stationName\":\"木古\",\"position\":[3527,1370],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":232,\"stationName\":\"上李朗\",\"position\":[3573,1523],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":233,\"stationName\":\"凉帽山\",\"position\":[3492,1601],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":234,\"stationName\":\"甘坑\",\"position\":[3360,1585],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":235,\"stationName\":\"雪象\",\"position\":[3092,1495],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":236,\"stationName\":\"岗头\",\"position\":[3021,1493],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":237,\"stationName\":\"华为\",\"position\":[2974,1559],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":238,\"stationName\":\"贝尔路\",\"position\":[2966,1647],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":239,\"stationName\":\"坂田北\",\"position\":[2936,1715],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":240,\"stationName\":\"光雅园\",\"position\":[2911,1900],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":241,\"stationName\":\"南坑\",\"position\":[2908,1955],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":242,\"stationName\":\"雅宝\",\"position\":[2905,2018],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":243,\"stationName\":\"冬瓜岭\",\"position\":[2978,2459],\"shape\":\"cicle\",\"lineIds\":[11]},{\"stationId\":244,\"stationName\":\"碧头\",\"position\":[502,219],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":245,\"stationName\":\"后亭\",\"position\":[571,538],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":246,\"stationName\":\"沙井\",\"position\":[547,755],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":247,\"stationName\":\"马安山\",\"position\":[472,894],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":248,\"stationName\":\"塘尾\",\"position\":[481,1043],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":249,\"stationName\":\"桥头\",\"position\":[412,1182],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":250,\"stationName\":\"福永\",\"position\":[363,1328],\"shape\":\"cicle\",\"lineIds\":[12,13]},{\"stationId\":251,\"stationName\":\"机场北\",\"position\":[284,1552],\"shape\":\"cicle\",\"lineIds\":[12,16]},{\"stationId\":252,\"stationName\":\"机场\",\"position\":[439,1824],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":253,\"stationName\":\"碧海湾\",\"position\":[863,2313],\"shape\":\"cicle\",\"lineIds\":[12]},{\"stationId\":254,\"stationName\":\"宝安\",\"position\":[1106,2518],\"shape\":\"cicle\",\"lineIds\":[12],\"tagDirection\":5},{\"stationId\":255,\"stationName\":\"南山\",\"position\":[1537,2823],\"shape\":\"cicle\",\"lineIds\":[12,13]},{\"stationId\":256,\"stationName\":\"海上田园东\",\"position\":[115,752],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":257,\"stationName\":\"海上田园南\",\"position\":[46,881],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":2},{\"stationId\":258,\"stationName\":\"国展北\",\"position\":[71,1032],\"shape\":\"cicle\",\"lineIds\":[13,16]},{\"stationId\":259,\"stationName\":\"国展\",\"position\":[82,1104],\"shape\":\"cicle\",\"lineIds\":[13,16]},{\"stationId\":260,\"stationName\":\"福海西\",\"position\":[197,1180],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":261,\"stationName\":\"桥头西\",\"position\":[277,1233],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":262,\"stationName\":\"怀德\",\"position\":[491,1397],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":263,\"stationName\":\"福围\",\"position\":[514,1495],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":264,\"stationName\":\"兴围\",\"position\":[647,1635],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":265,\"stationName\":\"黄田\",\"position\":[759,1762],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":1},{\"stationId\":266,\"stationName\":\"钟屋南\",\"position\":[894,1878],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":267,\"stationName\":\"西乡桃源\",\"position\":[926,1954],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":268,\"stationName\":\"平峦山\",\"position\":[1000,2032],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":269,\"stationName\":\"宝田一路\",\"position\":[1087,2119],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":270,\"stationName\":\"宝安客运站\",\"position\":[1139,2170],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":271,\"stationName\":\"流塘\",\"position\":[1195,2226],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":272,\"stationName\":\"上川\",\"position\":[1254,2285],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":273,\"stationName\":\"新安公园\",\"position\":[1411,2441],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":274,\"stationName\":\"同乐南\",\"position\":[1490,2500],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":275,\"stationName\":\"中山公园\",\"position\":[1534,2594],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":276,\"stationName\":\"南头古城\",\"position\":[1544,2679],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":277,\"stationName\":\"南光\",\"position\":[1545,2897],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":278,\"stationName\":\"四海\",\"position\":[1522,3060],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":279,\"stationName\":\"花果山\",\"position\":[1493,3120],\"shape\":\"cicle\",\"lineIds\":[13],\"tagDirection\":6},{\"stationId\":280,\"stationName\":\"太子湾\",\"position\":[1413,3336],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":281,\"stationName\":\"左炮台东\",\"position\":[1281,3369],\"shape\":\"cicle\",\"lineIds\":[13]},{\"stationId\":282,\"stationName\":\"罗湖北\",\"position\":[3432,2256],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":283,\"stationName\":\"石芽岭\",\"position\":[3682,1779],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":284,\"stationName\":\"六约北\",\"position\":[4060,1638],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":285,\"stationName\":\"四联\",\"position\":[4231,1580],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":286,\"stationName\":\"坳背\",\"position\":[4437,1377],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":287,\"stationName\":\"嶂背\",\"position\":[4798,1141],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":288,\"stationName\":\"南约\",\"position\":[5083,1183],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":289,\"stationName\":\"宝龙\",\"position\":[5280,1181],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":290,\"stationName\":\"锦龙\",\"position\":[5641,1262],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":291,\"stationName\":\"坪山围\",\"position\":[5739,1150],\"shape\":\"cicle\",\"lineIds\":[14,15]},{\"stationId\":292,\"stationName\":\"坪山广场\",\"position\":[5790,1058],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":293,\"stationName\":\"坪山中心\",\"position\":[5818,995],\"shape\":\"cicle\",\"lineIds\":[14],\"tagDirection\":5},{\"stationId\":294,\"stationName\":\"坑梓\",\"position\":[6012,610],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":295,\"stationName\":\"沙田\",\"position\":[6308,502],\"shape\":\"cicle\",\"lineIds\":[14]},{\"stationId\":296,\"stationName\":\"大运中心\",\"position\":[4510,1111],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":297,\"stationName\":\"龙城公园\",\"position\":[4486,1019],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":298,\"stationName\":\"黄阁坑\",\"position\":[4484,873],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":299,\"stationName\":\"愉园\",\"position\":[4536,781],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":300,\"stationName\":\"回龙埔\",\"position\":[4661,772],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":301,\"stationName\":\"尚景\",\"position\":[4738,770],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":302,\"stationName\":\"盛平\",\"position\":[4829,748],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":303,\"stationName\":\"龙园\",\"position\":[4966,754],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":304,\"stationName\":\"新塘围\",\"position\":[5167,809],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":305,\"stationName\":\"龙东\",\"position\":[5266,849],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":306,\"stationName\":\"宝龙同乐\",\"position\":[5425,972],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":307,\"stationName\":\"坪山\",\"position\":[5577,1007],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":4},{\"stationId\":308,\"stationName\":\"新和\",\"position\":[5657,1032],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":309,\"stationName\":\"六和\",\"position\":[5680,1104],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":310,\"stationName\":\"坪环\",\"position\":[5769,1210],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":5},{\"stationId\":311,\"stationName\":\"东纵纪念馆\",\"position\":[5854,1204],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":4},{\"stationId\":312,\"stationName\":\"沙壆\",\"position\":[5952,1199],\"shape\":\"cicle\",\"lineIds\":[15],\"tagDirection\":2},{\"stationId\":313,\"stationName\":\"燕子湖\",\"position\":[6056,1179],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":314,\"stationName\":\"石井\",\"position\":[6133,1145],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":315,\"stationName\":\"技术大学\",\"position\":[6314,1080],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":316,\"stationName\":\"田心\",\"position\":[6444,1126],\"shape\":\"cicle\",\"lineIds\":[15]},{\"stationId\":317,\"stationName\":\"国展南\",\"position\":[86,1226],\"shape\":\"cicle\",\"lineIds\":[16]},{\"stationId\":318,\"stationName\":\"会展城\",\"position\":[0,942],\"shape\":\"cicle\",\"lineIds\":[16]}],\"lines\":[{\"lineId\":1,\"lineName\":\"1号线/罗宝线\",\"color\":\"#00AB4F\",\"stationIds\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30],\"sign\":\"1\",\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"坪山云巴1号线\",\"color\":\"#2249A3\",\"stationIds\":[31,32,33,34,35,36,37,38,39,40,41],\"sign\":\"坪山云巴1\",\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":3,\"lineName\":\"2号线/8号线\",\"color\":\"#B35A1F\",\"stationIds\":[42,43,44,45,46,47,48,49,50,51,52,15,53,54,55,56,57,58,59,60,61,62,63,64,65,4,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81],\"sign\":\"2\",\"order\":3,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"3号线/龙岗线\",\"color\":\"#01A2E2\",\"stationIds\":[82,83,84,9,61,85,86,87,88,89,3,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109],\"sign\":\"3\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":5,\"lineName\":\"4号线/龙华线\",\"color\":\"#CC0000\",\"stationIds\":[110,111,8,62,85,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129],\"sign\":\"4\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":6,\"lineName\":\"5号线/环中线\",\"color\":\"#96499A\",\"stationIds\":[42,130,131,132,133,134,135,22,136,137,24,138,139,140,141,142,143,144,145,146,116,147,148,149,150,151,152,153,95,154,155,156,157,67],\"sign\":\"5\",\"order\":6,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"6号线/光明线\",\"color\":\"#008187\",\"stationIds\":[158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,117,116,176,177,178,179,180,88,5],\"sign\":\"6\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"6号线支线\",\"color\":\"#00AD8E\",\"stationIds\":[167,181,182,183],\"sign\":\"6\",\"order\":8,\"bendFirst\":[true,true,true,true]},{\"lineId\":9,\"lineName\":\"7号线/西丽线\",\"color\":\"#2249A3\",\"stationIds\":[184,143,185,186,187,188,189,55,190,11,191,192,84,193,111,194,195,196,64,87,197,179,198,199,200,92,156],\"sign\":\"7\",\"order\":9,\"bendFirst\":[true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"9号线/梅林线\",\"color\":\"#86656D\",\"stationIds\":[201,202,203,204,205,206,207,208,209,210,211,212,213,214,11,215,59,216,217,218,113,219,178,220,198,221,89,222,223,224,225,226],\"sign\":\"9\",\"order\":10,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":11,\"lineName\":\"10号线/坂田线\",\"color\":\"#EA6183\",\"stationIds\":[227,228,229,230,231,232,233,234,235,236,237,238,239,148,240,241,242,219,243,86,63,7,111,110],\"sign\":\"10\",\"order\":11,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":12,\"lineName\":\"11号线/机场线\",\"color\":\"#741D51\",\"stationIds\":[244,158,245,246,247,248,249,250,251,252,253,254,22,255,50,211,11,61,63],\"sign\":\"11\",\"order\":12,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true]},{\"lineId\":13,\"lineName\":\"12号线/南宝线\",\"color\":\"#A49ABD\",\"stationIds\":[256,257,258,259,260,261,250,262,263,30,264,265,266,267,268,269,270,271,272,139,273,274,275,276,19,255,277,206,278,279,44,280,281],\"sign\":\"12\",\"order\":13,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":14,\"lineName\":\"14号线/东部快线\",\"color\":\"#DAC17D\",\"stationIds\":[63,197,282,95,283,284,285,286,104,287,288,289,290,291,292,293,294,295],\"sign\":\"14\",\"order\":14,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":15,\"lineName\":\"16号线/龙坪线\",\"color\":\"#1C24A4\",\"stationIds\":[104,296,297,298,299,300,301,302,303,109,304,305,306,307,308,309,291,310,311,312,313,314,315,316],\"sign\":\"16\",\"order\":15,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":16,\"lineName\":\"20号线\",\"color\":\"#019AC3\",\"stationIds\":[251,317,259,258,318],\"sign\":\"20\",\"order\":16,\"bendFirst\":[true,true,true,true,true]}],\"title\":\"深圳\"}"
  },
  {
    "path": "public/tianjing.json",
    "content": "{\"stations\":[{\"stationId\":1,\"stationName\":\"刘园\",\"position\":[538,599],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":2,\"stationName\":\"瑞景新苑\",\"position\":[598,677],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":3,\"stationName\":\"佳园里\",\"position\":[661,759],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":4,\"stationName\":\"本溪路\",\"position\":[774,824],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":5,\"stationName\":\"勤俭道\",\"position\":[916,895],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":6,\"stationName\":\"洪湖里\",\"position\":[998,970],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":7,\"stationName\":\"西站\",\"position\":[1047,1109],\"shape\":\"cicle\",\"lineIds\":[1,6],\"tagDirection\":4},{\"stationId\":8,\"stationName\":\"西北角\",\"position\":[1096,1213],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":9,\"stationName\":\"西南角\",\"position\":[1099,1305],\"shape\":\"cicle\",\"lineIds\":[1,2]},{\"stationId\":10,\"stationName\":\"二纬路\",\"position\":[1126,1376],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":11,\"stationName\":\"海光寺\",\"position\":[1154,1455],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":12,\"stationName\":\"鞍山道\",\"position\":[1252,1475],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":13,\"stationName\":\"营口道\",\"position\":[1356,1492],\"shape\":\"cicle\",\"lineIds\":[1,3]},{\"stationId\":14,\"stationName\":\"小白楼\",\"position\":[1533,1530],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":5},{\"stationId\":15,\"stationName\":\"下瓦房\",\"position\":[1608,1627],\"shape\":\"cicle\",\"lineIds\":[1,5]},{\"stationId\":16,\"stationName\":\"南楼\",\"position\":[1618,1719],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":2},{\"stationId\":17,\"stationName\":\"土城\",\"position\":[1702,1787],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":18,\"stationName\":\"陈塘庄\",\"position\":[1864,1844],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":19,\"stationName\":\"复兴门\",\"position\":[1981,1907],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":20,\"stationName\":\"华山里\",\"position\":[1998,2017],\"shape\":\"cicle\",\"lineIds\":[1],\"tagDirection\":2},{\"stationId\":21,\"stationName\":\"财经大学\",\"position\":[2148,2039],\"shape\":\"cicle\",\"lineIds\":[1,9]},{\"stationId\":22,\"stationName\":\"双林\",\"position\":[2300,2105],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":23,\"stationName\":\"李楼\",\"position\":[2551,2134],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":24,\"stationName\":\"洪泥河东\",\"position\":[2828,2203],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":25,\"stationName\":\"高庄子\",\"position\":[2987,2248],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":26,\"stationName\":\"国家会展中心\",\"position\":[3219,2389],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":27,\"stationName\":\"国瑞路\",\"position\":[3286,2459],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":28,\"stationName\":\"东沽路\",\"position\":[3463,2555],\"shape\":\"cicle\",\"lineIds\":[1]},{\"stationId\":29,\"stationName\":\"滨海国际机场\",\"position\":[3005,1358],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":30,\"stationName\":\"空港经济区\",\"position\":[2729,1102],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":31,\"stationName\":\"国山路\",\"position\":[2479,1138],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":32,\"stationName\":\"登州路\",\"position\":[2339,1174],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":33,\"stationName\":\"屿东城\",\"position\":[2177,1207],\"shape\":\"cicle\",\"lineIds\":[2,9]},{\"stationId\":34,\"stationName\":\"翠阜新村\",\"position\":[1959,1239],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":3},{\"stationId\":35,\"stationName\":\"靖江路\",\"position\":[1821,1254],\"shape\":\"cicle\",\"lineIds\":[2,5],\"tagDirection\":3},{\"stationId\":36,\"stationName\":\"顺驰桥\",\"position\":[1719,1265],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":37,\"stationName\":\"远洋国际中心\",\"position\":[1589,1314],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":3},{\"stationId\":38,\"stationName\":\"天津站\",\"position\":[1496,1301],\"shape\":\"cicle\",\"lineIds\":[2,3,8],\"tagDirection\":3},{\"stationId\":39,\"stationName\":\"建国道\",\"position\":[1389,1289],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":40,\"stationName\":\"东南角\",\"position\":[1282,1310],\"shape\":\"cicle\",\"lineIds\":[2,4]},{\"stationId\":41,\"stationName\":\"鼓楼\",\"position\":[1191,1307],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":42,\"stationName\":\"广开四马路\",\"position\":[999,1302],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":43,\"stationName\":\"长虹公园\",\"position\":[873,1301],\"shape\":\"cicle\",\"lineIds\":[2,6]},{\"stationId\":44,\"stationName\":\"咸阳路\",\"position\":[729,1301],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":45,\"stationName\":\"芥园西道\",\"position\":[579,1252],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":46,\"stationName\":\"卞兴\",\"position\":[469,1217],\"shape\":\"cicle\",\"lineIds\":[2],\"tagDirection\":7},{\"stationId\":47,\"stationName\":\"曹庄\",\"position\":[289,1222],\"shape\":\"cicle\",\"lineIds\":[2]},{\"stationId\":48,\"stationName\":\"小淀\",\"position\":[1955,287],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":49,\"stationName\":\"丰产河\",\"position\":[1739,297],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":50,\"stationName\":\"华北集团\",\"position\":[1659,403],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":51,\"stationName\":\"天士力\",\"position\":[1529,620],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":2},{\"stationId\":52,\"stationName\":\"宜兴埠\",\"position\":[1569,703],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":2},{\"stationId\":53,\"stationName\":\"张兴庄\",\"position\":[1527,759],\"shape\":\"cicle\",\"lineIds\":[3,5]},{\"stationId\":54,\"stationName\":\"铁东路\",\"position\":[1449,880],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":55,\"stationName\":\"北站\",\"position\":[1453,1012],\"shape\":\"cicle\",\"lineIds\":[3,6],\"tagDirection\":1},{\"stationId\":56,\"stationName\":\"中山路\",\"position\":[1439,1061],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":57,\"stationName\":\"金狮桥\",\"position\":[1459,1168],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":58,\"stationName\":\"津湾广场\",\"position\":[1459,1359],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":6},{\"stationId\":59,\"stationName\":\"和平路\",\"position\":[1426,1410],\"shape\":\"cicle\",\"lineIds\":[3,4]},{\"stationId\":60,\"stationName\":\"西康路\",\"position\":[1259,1557],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":61,\"stationName\":\"吴家窑\",\"position\":[1239,1681],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":62,\"stationName\":\"天塔\",\"position\":[1159,1721],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":63,\"stationName\":\"周邓纪念馆\",\"position\":[1019,1752],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":64,\"stationName\":\"红旗南路\",\"position\":[860,1751],\"shape\":\"cicle\",\"lineIds\":[3,6],\"tagDirection\":1},{\"stationId\":65,\"stationName\":\"王顶堤\",\"position\":[769,1758],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":66,\"stationName\":\"华苑\",\"position\":[669,1807],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":67,\"stationName\":\"大学城\",\"position\":[499,1955],\"shape\":\"cicle\",\"lineIds\":[3],\"tagDirection\":3},{\"stationId\":68,\"stationName\":\"高新区\",\"position\":[369,1960],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":69,\"stationName\":\"学府工业区\",\"position\":[169,1960],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":70,\"stationName\":\"杨伍庄\",\"position\":[79,1996],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":71,\"stationName\":\"南站\",\"position\":[0,2108],\"shape\":\"cicle\",\"lineIds\":[3]},{\"stationId\":72,\"stationName\":\"金街\",\"position\":[1301,1361],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":73,\"stationName\":\"徐州道\",\"position\":[1564,1524],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":0},{\"stationId\":74,\"stationName\":\"六纬路\",\"position\":[1654,1522],\"shape\":\"cicle\",\"lineIds\":[4],\"tagDirection\":4},{\"stationId\":75,\"stationName\":\"成林道\",\"position\":[1835,1376],\"shape\":\"cicle\",\"lineIds\":[4,5]},{\"stationId\":76,\"stationName\":\"泰昌路\",\"position\":[1944,1456],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":77,\"stationName\":\"万东路\",\"position\":[2053,1484],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":78,\"stationName\":\"沙柳南路\",\"position\":[2268,1505],\"shape\":\"cicle\",\"lineIds\":[4,9],\"tagDirection\":1},{\"stationId\":79,\"stationName\":\"登州南路\",\"position\":[2433,1513],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":80,\"stationName\":\"跃进北路\",\"position\":[2567,1539],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":81,\"stationName\":\"航双路\",\"position\":[2718,1568],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":82,\"stationName\":\"民航大学\",\"position\":[2870,1590],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":83,\"stationName\":\"新兴村\",\"position\":[3084,1663],\"shape\":\"cicle\",\"lineIds\":[4]},{\"stationId\":84,\"stationName\":\"李七庄南\",\"position\":[1086,2314],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":85,\"stationName\":\"中医一附院\",\"position\":[1226,2210],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":86,\"stationName\":\"昌凌路\",\"position\":[1226,2112],\"shape\":\"cicle\",\"lineIds\":[5,9]},{\"stationId\":87,\"stationName\":\"凌宾路\",\"position\":[1099,1998],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":88,\"stationName\":\"体育中心\",\"position\":[1104,1931],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":89,\"stationName\":\"肿瘤医院\",\"position\":[1224,1889],\"shape\":\"cicle\",\"lineIds\":[5,6]},{\"stationId\":90,\"stationName\":\"天津宾馆\",\"position\":[1364,1825],\"shape\":\"cicle\",\"lineIds\":[5,6]},{\"stationId\":91,\"stationName\":\"文化中心\",\"position\":[1448,1780],\"shape\":\"cicle\",\"lineIds\":[5,6],\"tagDirection\":7},{\"stationId\":92,\"stationName\":\"西南楼\",\"position\":[1540,1724],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":7},{\"stationId\":93,\"stationName\":\"直沽\",\"position\":[1718,1569],\"shape\":\"cicle\",\"lineIds\":[5,8]},{\"stationId\":94,\"stationName\":\"津塘路\",\"position\":[1793,1513],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":95,\"stationName\":\"幸福公园\",\"position\":[1821,1138],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":96,\"stationName\":\"月牙河\",\"position\":[1837,1031],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":97,\"stationName\":\"金钟河大街\",\"position\":[1798,957],\"shape\":\"cicle\",\"lineIds\":[5,6]},{\"stationId\":98,\"stationName\":\"建昌道\",\"position\":[1725,882],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":5},{\"stationId\":99,\"stationName\":\"思源路\",\"position\":[1654,845],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":100,\"stationName\":\"志成路\",\"position\":[1570,808],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":101,\"stationName\":\"宜兴埠北\",\"position\":[1433,648],\"shape\":\"cicle\",\"lineIds\":[5],\"tagDirection\":5},{\"stationId\":102,\"stationName\":\"辽河北道\",\"position\":[1379,581],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":103,\"stationName\":\"淮河道\",\"position\":[1304,493],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":104,\"stationName\":\"职业大学\",\"position\":[1199,368],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":105,\"stationName\":\"北辰道\",\"position\":[1116,272],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":106,\"stationName\":\"丹河北道\",\"position\":[1016,154],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":107,\"stationName\":\"北辰科技园北\",\"position\":[878,0],\"shape\":\"cicle\",\"lineIds\":[5]},{\"stationId\":108,\"stationName\":\"南孙庄\",\"position\":[2563,613],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":109,\"stationName\":\"南何庄\",\"position\":[2289,615],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":110,\"stationName\":\"大毕庄\",\"position\":[2170,649],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":111,\"stationName\":\"金钟街\",\"position\":[2040,680],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":112,\"stationName\":\"徐庄子\",\"position\":[1921,770],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":113,\"stationName\":\"民权门\",\"position\":[1713,992],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":114,\"stationName\":\"北宁公园\",\"position\":[1611,1016],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":115,\"stationName\":\"新开河\",\"position\":[1407,990],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":116,\"stationName\":\"外院附中\",\"position\":[1297,966],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":117,\"stationName\":\"天泰路\",\"position\":[1212,997],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":118,\"stationName\":\"北竹林\",\"position\":[1106,1077],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":3},{\"stationId\":119,\"stationName\":\"复兴路\",\"position\":[958,1117],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":120,\"stationName\":\"人民医院\",\"position\":[876,1205],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":121,\"stationName\":\"宜宾道\",\"position\":[872,1415],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":122,\"stationName\":\"鞍山西道\",\"position\":[873,1513],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":123,\"stationName\":\"天拖\",\"position\":[873,1587],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":124,\"stationName\":\"一中心医院\",\"position\":[874,1647],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":125,\"stationName\":\"迎风道\",\"position\":[874,1817],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":126,\"stationName\":\"南翠屏\",\"position\":[965,1879],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":127,\"stationName\":\"水上公园东路\",\"position\":[1110,1884],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":0},{\"stationId\":128,\"stationName\":\"乐园道\",\"position\":[1554,1766],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":5},{\"stationId\":129,\"stationName\":\"尖山路\",\"position\":[1619,1806],\"shape\":\"cicle\",\"lineIds\":[6],\"tagDirection\":5},{\"stationId\":130,\"stationName\":\"医大二院\",\"position\":[1619,1867],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":131,\"stationName\":\"梅江道\",\"position\":[1635,1991],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":132,\"stationName\":\"左江道\",\"position\":[1556,2079],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":133,\"stationName\":\"梅江公园\",\"position\":[1555,2155],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":134,\"stationName\":\"梅江会展中心\",\"position\":[1556,2236],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":135,\"stationName\":\"解放南路\",\"position\":[1719,2271],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":136,\"stationName\":\"洞庭路\",\"position\":[1838,2243],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":137,\"stationName\":\"梅林路\",\"position\":[1927,2231],\"shape\":\"cicle\",\"lineIds\":[6]},{\"stationId\":138,\"stationName\":\"渌水道\",\"position\":[2079,2223],\"shape\":\"cicle\",\"lineIds\":[6,7]},{\"stationId\":139,\"stationName\":\"双港\",\"position\":[2155,2376],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":140,\"stationName\":\"景荷道\",\"position\":[2220,2479],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":141,\"stationName\":\"景荔道\",\"position\":[2275,2565],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":142,\"stationName\":\"天津大学北洋园校区\",\"position\":[2465,2752],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":143,\"stationName\":\"海河教育园区\",\"position\":[2601,2789],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":144,\"stationName\":\"南开大学津南校区\",\"position\":[2795,2851],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":145,\"stationName\":\"和慧南路\",\"position\":[2982,2866],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":146,\"stationName\":\"咸水沽西\",\"position\":[3117,2873],\"shape\":\"cicle\",\"lineIds\":[7]},{\"stationId\":147,\"stationName\":\"东海路\",\"position\":[6752,2273],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":148,\"stationName\":\"会展中心\",\"position\":[6696,2379],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":149,\"stationName\":\"太湖路\",\"position\":[6613,2480],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":150,\"stationName\":\"市民广场\",\"position\":[6410,2497],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":151,\"stationName\":\"泰达\",\"position\":[6173,2424],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":152,\"stationName\":\"塘沽\",\"position\":[5989,2383],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":153,\"stationName\":\"胡家园\",\"position\":[5453,2274],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":7},{\"stationId\":154,\"stationName\":\"钢管公司\",\"position\":[4418,2281],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":155,\"stationName\":\"军粮城\",\"position\":[3940,2198],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":156,\"stationName\":\"小东庄\",\"position\":[3412,2035],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":157,\"stationName\":\"东丽开发区\",\"position\":[2953,1885],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":158,\"stationName\":\"新立\",\"position\":[2739,1820],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":159,\"stationName\":\"张贵庄\",\"position\":[2457,1758],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":160,\"stationName\":\"二号桥\",\"position\":[2310,1727],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":161,\"stationName\":\"一号桥\",\"position\":[2208,1718],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":162,\"stationName\":\"中山门\",\"position\":[2022,1670],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":163,\"stationName\":\"东兴路\",\"position\":[1805,1645],\"shape\":\"cicle\",\"lineIds\":[8]},{\"stationId\":164,\"stationName\":\"十一经路\",\"position\":[1619,1465],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":165,\"stationName\":\"大王庄\",\"position\":[1564,1407],\"shape\":\"cicle\",\"lineIds\":[8],\"tagDirection\":1},{\"stationId\":166,\"stationName\":\"崂山道\",\"position\":[2215,1292],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":167,\"stationName\":\"香山道\",\"position\":[2244,1362],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":168,\"stationName\":\"万山道\",\"position\":[2255,1431],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":169,\"stationName\":\"方山道\",\"position\":[2273,1577],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":2},{\"stationId\":170,\"stationName\":\"金贸产业园\",\"position\":[2254,1651],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":2},{\"stationId\":171,\"stationName\":\"龙涵道\",\"position\":[2250,1734],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":172,\"stationName\":\"环宇道\",\"position\":[2237,1836],\"shape\":\"cicle\",\"lineIds\":[9,10]},{\"stationId\":173,\"stationName\":\"柳林路\",\"position\":[2227,1957],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":174,\"stationName\":\"微山路\",\"position\":[1976,2050],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":4},{\"stationId\":175,\"stationName\":\"玛钢厂\",\"position\":[1906,2053],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":5},{\"stationId\":176,\"stationName\":\"春海路\",\"position\":[1810,2049],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":177,\"stationName\":\"南珠桥\",\"position\":[1653,2042],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":178,\"stationName\":\"友谊南路\",\"position\":[1554,2041],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":179,\"stationName\":\"江湾二支路\",\"position\":[1438,2041],\"shape\":\"cicle\",\"lineIds\":[9],\"tagDirection\":0},{\"stationId\":180,\"stationName\":\"丽江道\",\"position\":[1321,2051],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":181,\"stationName\":\"瑶环路\",\"position\":[1129,2132],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":182,\"stationName\":\"于台\",\"position\":[1005,2214],\"shape\":\"cicle\",\"lineIds\":[9]},{\"stationId\":183,\"stationName\":\"东江道\",\"position\":[1978,1996],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":7},{\"stationId\":184,\"stationName\":\"学苑北路\",\"position\":[2101,1937],\"shape\":\"cicle\",\"lineIds\":[10],\"tagDirection\":3},{\"stationId\":185,\"stationName\":\"海河东路\",\"position\":[2144,1851],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":186,\"stationName\":\"雪莲南路\",\"position\":[2378,1849],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":187,\"stationName\":\"招远路\",\"position\":[2486,1869],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":188,\"stationName\":\"东丽文体中心\",\"position\":[2666,1889],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":189,\"stationName\":\"驯海路\",\"position\":[2767,1916],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":190,\"stationName\":\"东丽一经路\",\"position\":[2878,1947],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":191,\"stationName\":\"东丽三经路\",\"position\":[2963,1976],\"shape\":\"cicle\",\"lineIds\":[10]},{\"stationId\":192,\"stationName\":\"东丽六经路\",\"position\":[3124,2027],\"shape\":\"cicle\",\"lineIds\":[10]}],\"lines\":[{\"lineId\":1,\"lineName\":\"1号线\",\"color\":\"#CC0000\",\"stationIds\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],\"sign\":\"1\",\"order\":1,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":2,\"lineName\":\"2号线\",\"color\":\"#FCD600\",\"stationIds\":[29,30,31,32,33,34,35,36,37,38,39,40,41,9,42,43,44,45,46,47],\"sign\":\"2\",\"order\":2,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":3,\"lineName\":\"3号线\",\"color\":\"#019AC3\",\"stationIds\":[48,49,50,51,52,53,54,55,56,57,38,58,59,13,60,61,62,63,64,65,66,67,68,69,70,71],\"sign\":\"3\",\"order\":3,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":4,\"lineName\":\"4号线\",\"color\":\"#018237\",\"stationIds\":[40,72,59,73,74,75,76,77,78,79,80,81,82,83],\"sign\":\"4\",\"order\":4,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":5,\"lineName\":\"5号线\",\"color\":\"#EE782E\",\"stationIds\":[84,85,86,87,88,89,90,91,92,15,93,94,75,35,95,96,97,98,99,100,53,101,102,103,104,105,106,107],\"sign\":\"5\",\"order\":5,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":6,\"lineName\":\"6号线\",\"color\":\"#A61D7F\",\"stationIds\":[108,109,110,111,112,97,113,114,55,115,116,117,118,7,119,120,43,121,122,123,124,64,125,126,127,89,90,91,128,129,130,131,132,133,134,135,136,137,138],\"sign\":\"6\",\"order\":6,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":7,\"lineName\":\"6号线\",\"color\":\"#A61D7F\",\"stationIds\":[138,139,140,141,142,143,144,145,146],\"sign\":\"6\",\"order\":7,\"bendFirst\":[true,true,true,true,true,true,true,true,true]},{\"lineId\":8,\"lineName\":\"9号线\",\"color\":\"#2249A3\",\"stationIds\":[147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,93,164,165,38],\"sign\":\"9\",\"order\":8,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":9,\"lineName\":\"10号线\",\"color\":\"#B8D201\",\"stationIds\":[33,166,167,168,78,169,170,171,172,173,21,174,175,176,177,178,179,180,86,181,182],\"sign\":\"10\",\"order\":9,\"bendFirst\":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]},{\"lineId\":10,\"lineName\":\"11号线\",\"color\":\"#2249A3\",\"stationIds\":[183,184,185,172,186,187,188,189,190,191,192],\"sign\":\"11\",\"order\":10,\"bendFirst\":[false,true,true,false,false,false,false,false,false,false,true]}],\"title\":\"天津\"}"
  },
  {
    "path": "src/Common/AutoGrowthInput.scss",
    "content": ".auto-growth-container {\n    position: relative;\n    width: fit-content;\n    .auto-growth-span {\n        // font-size: 36px;\n        border: none;\n        // font-weight: 500;\n        // width: 100px;\n        // display: inline-block;\n        // margin-top: 14px;\n        opacity: 0;\n        background-color: transparent;\n        white-space: nowrap;\n    }\n    .auto-growth-input {\n        // font-size: 36px;\n        white-space: nowrap;\n\n        border: none;\n        // font-weight: 500;\n        width: calc(100% + 18px);\n        // margin-top: 14px;\n        position: absolute;\n        left: 0;\n        padding: 0;\n        background-color: transparent;\n        &:disabled{\n            appearance: none;\n            color: inherit;\n            opacity: inherit;\n            cursor: default;\n            border: none;\n            &:focus,&:focus-visible{\n                outline: none;\n            }\n        }\n    }\n    .click-panel{\n        position: absolute;\n        left: 0;\n        width: calc(100% + 18px);\n        height: 100%;\n        top: 0;\n        // cursor: pointer;\n    }\n\n    &.disabled{\n        .auto-growth-span{\n            opacity: 1;\n        }\n        .auto-growth-input{\n            // opacity: 0;\n            display: none;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Common/AutoGrowthInput.tsx",
    "content": "import classNames from \"classnames\";\nimport React, {\n  CSSProperties,\n  Dispatch,\n  LegacyRef,\n  RefAttributes,\n  RefObject,\n  SetStateAction,\n  StyleHTMLAttributes,\n  forwardRef,\n  useEffect,\n  useState,\n} from \"react\";\nimport \"./AutoGrowthInput.scss\";\ntype InputProps = {\n  value?: number | string;\n  onInput?: (x: any) => void;\n  className?: string;\n  type?: string;\n  disabled?: boolean;\n  style?: CSSProperties;\n  onClick?: (x: any) => void;\n}\nexport const AutoGrowthInput = forwardRef<HTMLInputElement, InputProps>(function ({\n  value,\n  onInput,\n  className = \"\",\n  type = \"\",\n  disabled = false,\n  style = {},\n  onClick,\n}, ref) {\n  return (\n    <div\n      // onClick={onClick}\n      className={classNames({\n        \"auto-growth-container\": 1,\n        [className]: className,\n        // disabled,\n      })}\n    >\n      <span className=\"auto-growth-span\" style={style}>\n        {value}\n      </span>\n      <input\n\n      ref={ref}\n        style={style}\n        className=\"auto-growth-input\"\n        value={value}\n        onInput={onInput}\n        type={type}\n        disabled={disabled}\n        onClick={onClick}\n        onWheel={(e) => {\n          if (document.activeElement === e.currentTarget) e.stopPropagation();\n        }}\n        onBlur={(e)=>{\n          if(type === \"number\")\n          setTimeout(()=>{\n            //@ts-ignore\n            e.target.value = value\n          })\n        }}\n      ></input>\n      {disabled?<div className=\"click-panel\" onClick={onClick}></div>:<></>}\n    </div>\n  );\n}) \n"
  },
  {
    "path": "src/Common/api.ts",
    "content": "export const getExistMap = (id:string) => {\n    const url = `/${id}.json`;\n    return fetch(url).then(res=>res.text());\n}"
  },
  {
    "path": "src/Common/color.ts",
    "content": "import { arrayToMap } from \"./util\";\n\nexport const colorSH = [\n    {\n        \"line\": \"1号线\",\n        \"color\": \"#EA0B2A\",\n        \"color_name\": \"正红色\",\n        \"rgb\": [234, 11, 42]\n    },\n    {\n        \"line\": \"2号线\",\n        \"color\": \"#94D40B\",\n        \"color_name\": \"绿色\",\n        \"rgb\": [148, 212, 11]\n    },\n    {\n        \"line\": \"3号线\",\n        \"color\": \"#F8D000\",\n        \"color_name\": \"黄色\",\n        \"rgb\": [248, 208, 0]\n    },\n    {\n        \"line\": \"4号线\",\n        \"color\": \"#60269E\",\n        \"color_name\": \"紫色\",\n        \"rgb\": [96, 38, 158]\n    },\n    {\n        \"line\": \"5号线\",\n        \"color\": \"#934C9A\",\n        \"color_name\": \"紫红色\",\n        \"rgb\": [147, 76, 154]\n    },\n    {\n        \"line\": \"6号线\",\n        \"color\": \"#D80169\",\n        \"color_name\": \"品红色\",\n        \"rgb\": [216, 1, 105]\n    },\n    {\n        \"line\": \"7号线\",\n        \"color\": \"#FE6B01\",\n        \"color_name\": \"橙色\",\n        \"rgb\": [254, 107, 1]\n    },\n    {\n        \"line\": \"8号线\",\n        \"color\": \"#00A0E8\",\n        \"color_name\": \"蓝色\",\n        \"rgb\": [0, 160, 232]\n    },\n    {\n        \"line\": \"9号线\",\n        \"color\": \"#6FC5E8\",\n        \"color_name\": \"淡蓝色\",\n        \"rgb\": [111, 197, 232]\n    },\n    {\n        \"line\": \"10号线\",\n        \"color\": \"#C3A5E1\",\n        \"color_name\": \"淡紫色\",\n        \"rgb\": [195, 165, 225]\n    },\n    {\n        \"line\": \"11号线\",\n        \"color\": \"#792330\",\n        \"color_name\": \"棕色\",\n        \"rgb\": [121, 35, 48]\n    },\n    {\n        \"line\": \"12号线\",\n        \"color\": \"#007A61\",\n        \"color_name\": \"深绿色\",\n        \"rgb\": [0, 122, 97]\n    },\n    {\n        \"line\": \"13号线\",\n        \"color\": \"#F095CE\",\n        \"color_name\": \"粉色\",\n        \"rgb\": [240, 149, 206]\n    },\n    {\n        \"line\": \"14号线\",\n        \"color\": \"#827805\",\n        \"color_name\": \"橄榄绿色\",\n        \"rgb\": [130, 120, 5]\n    },\n    {\n        \"line\": \"15号线\",\n        \"color\": \"#BDA686\",\n        \"color_name\": \"香槟金色\",\n        \"rgb\": [189, 166, 134]\n    },\n    {\n        \"line\": \"16号线\",\n        \"color\": \"#2AD2C5\",\n        \"color_name\": \"水绿色\",\n        \"rgb\": [42, 210, 197]\n    }\n];\n\nexport const colorSHMap = arrayToMap(\"color\",colorSH);"
  },
  {
    "path": "src/Common/const.ts",
    "content": "const gauge = 10;\nconst line_radius = 10;\nconst handleLength = 45;\nconst handleWidth = 15;\nexport { gauge, line_radius, handleLength, handleWidth };\n"
  },
  {
    "path": "src/Common/teyvat.ts",
    "content": "import { UserDataType } from \"../Data/UserData\";\nimport { t } from \"i18next\";\nexport const teyvat: UserDataType = {\n  stations: [\n    {\n      stationId: 1,\n      stationName: t(\"wang-feng-jiao-zhan\"),\n      position: [678, -52],\n      shape: \"cicle\",\n      lineIds: [3],\n      tagDirection: 2,\n    },\n    {\n      stationId: 2,\n      stationName: t(\"zhai-xing-ya-zhan\"),\n      position: [645, 71],\n      shape: \"cicle\",\n      lineIds: [3],\n    },\n    {\n      stationId: 3,\n      stationName: t(\"qian-feng-shen-dian-zhan\"),\n      position: [640, 191],\n      shape: \"cicle\",\n      lineIds: [3],\n    },\n    {\n      stationId: 4,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-1\"),\n      position: [463, 418],\n      shape: \"cicle\",\n      lineIds: [2, 3, 8],\n    },\n    {\n      stationId: 5,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-2\"),\n      position: [573, 641],\n      shape: \"cicle\",\n      lineIds: [3],\n    },\n    {\n      stationId: 6,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-3\"),\n      position: [740, 641],\n      shape: \"cicle\",\n      lineIds: [3],\n    },\n    {\n      stationId: 7,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-4\"),\n      position: [813, 533],\n      shape: \"cicle\",\n      lineIds: [3],\n    },\n    {\n      stationId: 8,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-5\"),\n      position: [388, 318],\n      shape: \"cicle\",\n      lineIds: [1, 2],\n      tagDirection: 6\n    },\n    {\n      stationId: 9,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-6\"),\n      position: [458, 193],\n      shape: \"cicle\",\n      lineIds: [2],\n    },\n    {\n      stationId: 10,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-7\"),\n      position: [460, 86],\n      shape: \"cicle\",\n      lineIds: [2],\n    },\n    {\n      stationId: 11,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-8\"),\n      position: [458, -64],\n      shape: \"cicle\",\n      lineIds: [2],\n    },\n    {\n      stationId: 12,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-9\"),\n      position: [325, -102],\n      shape: \"cicle\",\n      lineIds: [2],\n    },\n    {\n      stationId: 13,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-10\"),\n      position: [245, 168],\n      shape: \"cicle\",\n      lineIds: [1],\n    },\n    {\n      stationId: 14,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-11\"),\n      position: [320, 226],\n      shape: \"cicle\",\n      lineIds: [1],\n    },\n    {\n      stationId: 15,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-12\"),\n      position: [270, 358],\n      shape: \"cicle\",\n      lineIds: [1],\n    },\n    {\n      stationId: 16,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-13\"),\n      position: [70, 428],\n      shape: \"cicle\",\n      lineIds: [1, 4, 8],\n    },\n    {\n      stationId: 17,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-14\"),\n      position: [-2, 336],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 18,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-15\"),\n      position: [3, 248],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 19,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-16\"),\n      position: [-70, 151],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 20,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-17\"),\n      position: [15, 18],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 21,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-18\"),\n      position: [-87, -77],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 22,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-19\"),\n      position: [83, 628],\n      shape: \"cicle\",\n      lineIds: [4],\n      tagDirection: 2,\n    },\n    {\n      stationId: 23,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-20\"),\n      position: [92, 748],\n      shape: \"cicle\",\n      lineIds: [4],\n      tagDirection: 2,\n    },\n    {\n      stationId: 24,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-21\"),\n      position: [248, 748],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 25,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-22\"),\n      position: [338, 778],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 26,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-23\"),\n      position: [180, 851],\n      shape: \"cicle\",\n      lineIds: [4],\n    },\n    {\n      stationId: 27,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-24\"),\n      position: [-35, 703],\n      shape: \"cicle\",\n      lineIds: [8],\n    },\n    {\n      stationId: 28,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-25\"),\n      position: [-230, 813],\n      shape: \"cicle\",\n      lineIds: [5, 8],\n    },\n    {\n      stationId: 29,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-26\"),\n      position: [-310, 568],\n      shape: \"cicle\",\n      lineIds: [5],\n    },\n    {\n      stationId: 30,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-27\"),\n      position: [-452, 473],\n      shape: \"cicle\",\n      lineIds: [5],\n    },\n    {\n      stationId: 31,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-28\"),\n      position: [-240, 971],\n      shape: \"cicle\",\n      lineIds: [5],\n    },\n    {\n      stationId: 32,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-29\"),\n      position: [-197, 1071],\n      shape: \"cicle\",\n      lineIds: [5],\n    },\n    {\n      stationId: 33,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-30\"),\n      position: [-280, 1226],\n      shape: \"cicle\",\n      lineIds: [5],\n    },\n    {\n      stationId: 34,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-31\"),\n      position: [-285, 1451],\n      shape: \"cicle\",\n      lineIds: [5, 6],\n    },\n    {\n      stationId: 35,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-32\"),\n      position: [-210, 1608],\n      shape: \"cicle\",\n      lineIds: [5, 7],\n    },\n    {\n      stationId: 36,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-33\"),\n      position: [-605, 1601],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 37,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-34\"),\n      position: [-671, 1511],\n      shape: \"cicle\",\n      lineIds: [7, 11],\n      tagDirection: 5,\n    },\n    {\n      stationId: 38,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-35\"),\n      position: [-362, 1351],\n      shape: \"cicle\",\n      lineIds: [6],\n    },\n    {\n      stationId: 39,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-36\"),\n      position: [-642, 1326],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 40,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-37\"),\n      position: [-437, 1158],\n      shape: \"cicle\",\n      lineIds: [6],\n    },\n    {\n      stationId: 41,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-38\"),\n      position: [-552, 1008],\n      shape: \"cicle\",\n      lineIds: [6],\n    },\n    {\n      stationId: 42,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-39\"),\n      position: [-602, 946],\n      shape: \"cicle\",\n      lineIds: [6],\n    },\n    {\n      stationId: 43,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-40\"),\n      position: [-525, 829],\n      shape: \"cicle\",\n      lineIds: [8],\n      tagDirection: 4\n    },\n    {\n      stationId: 44,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-41\"),\n      position: [-742, 828],\n      shape: \"cicle\",\n      lineIds: [6, 7, 8],\n    },\n    {\n      stationId: 45,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-42\"),\n      position: [-805, 728],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 46,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-43\"),\n      position: [-955, 903],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 47,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-44\"),\n      position: [-857, 943],\n      shape: \"cicle\",\n      lineIds: [8],\n      tagDirection: 2\n    },\n    {\n      stationId: 48,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-45\"),\n      position: [-855, 1078],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 49,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-46\"),\n      position: [-725, 1208],\n      shape: \"cicle\",\n      lineIds: [7],\n    },\n    {\n      stationId: 50,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-47\"),\n      position: [-897, 1411],\n      shape: \"cicle\",\n      lineIds: [11, 12],\n    },\n    {\n      stationId: 51,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-48\"),\n      position: [-1090, 1388],\n      shape: \"cicle\",\n      lineIds: [9, 11],\n    },\n    {\n      stationId: 52,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-49\"),\n      position: [-1090, 1076],\n      shape: \"cicle\",\n      lineIds: [9, 10],\n    },\n    {\n      stationId: 53,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-50\"),\n      position: [-1272, 1173],\n      shape: \"cicle\",\n      lineIds: [10],\n    },\n    {\n      stationId: 54,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-51\"),\n      position: [-1405, 1271],\n      shape: \"cicle\",\n      lineIds: [10],\n    },\n    {\n      stationId: 55,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-52\"),\n      position: [-1360, 1388],\n      shape: \"cicle\",\n      lineIds: [10, 11],\n    },\n    {\n      stationId: 56,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-53\"),\n      position: [-1195, 1576],\n      shape: \"cicle\",\n      lineIds: [10, 12],\n    },\n    {\n      stationId: 57,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-54\"),\n      position: [-1037, 1491],\n      shape: \"cicle\",\n      lineIds: [9, 12],\n    },\n    {\n      stationId: 58,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-55\"),\n      position: [-1067, 1791],\n      shape: \"cicle\",\n      lineIds: [9],\n      tagDirection: 2,\n    },\n    {\n      stationId: 59,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-56\"),\n      position: [-1177, 1933],\n      shape: \"cicle\",\n      lineIds: [9],\n      tagDirection: 3,\n    },\n    {\n      stationId: 60,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-57\"),\n      position: [-1310, 1931],\n      shape: \"cicle\",\n      lineIds: [9, 10],\n      tagDirection: 7,\n    },\n    {\n      stationId: 61,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-58\"),\n      position: [-1247, 2116],\n      shape: \"cicle\",\n      lineIds: [10],\n    },\n    {\n      stationId: 62,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-59\"),\n      position: [-1255, 1701],\n      shape: \"cicle\",\n      lineIds: [10],\n      tagDirection: 3,\n    },\n    {\n      stationId: 63,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-60\"),\n      position: [-1522, 1681],\n      shape: \"cicle\",\n      lineIds: [11, 12],\n    },\n    {\n      stationId: 64,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-61\"),\n      position: [-1695, 1681],\n      shape: \"cicle\",\n      lineIds: [12],\n    },\n    {\n      stationId: 65,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-62\"),\n      position: [-1865, 1493],\n      shape: \"cicle\",\n      lineIds: [12],\n    },\n    {\n      stationId: 66,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-63\"),\n      position: [-2215, 1326],\n      shape: \"cicle\",\n      lineIds: [12],\n    },\n    {\n      stationId: 67,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-64\"),\n      position: [-1812, 1908],\n      shape: \"cicle\",\n      lineIds: [11],\n    },\n    {\n      stationId: 68,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-65\"),\n      position: [-1482, 1931],\n      shape: \"cicle\",\n      lineIds: [9],\n    },\n    {\n      stationId: 69,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-66\"),\n      position: [-1737, 1998],\n      shape: \"cicle\",\n      lineIds: [9],\n      tagDirection: 3\n    },\n    {\n      stationId: 70,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-67\"),\n      position: [-1917, 2093],\n      shape: \"cicle\",\n      lineIds: [9, 11],\n    },\n    {\n      stationId: 71,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-68\"),\n      position: [-2077, 1883],\n      shape: \"cicle\",\n      lineIds: [9],\n    },\n    {\n      stationId: 72,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-69\"),\n      position: [-1997, 2211],\n      shape: \"cicle\",\n      lineIds: [11],\n    },\n    {\n      stationId: 73,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-70\"),\n      position: [-2212, 2316],\n      shape: \"cicle\",\n      lineIds: [11],\n    },\n    {\n      stationId: 74,\n      stationName: t(\"Common-teyvat-192be7b183f6eee79-71\"),\n      position: [-2470, 2316],\n      shape: \"cicle\",\n      lineIds: [11],\n    },\n  ].reduce((map, cur) => {\n    map.set(cur.stationId, cur);\n    return map;\n  }, new Map()),\n  lines: [\n    {\n      lineId: 1,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-72\"),\n      color: \"#EA0B2A\",\n      stationIds: [13, 14, 8, 15, 16],\n      sign: \"1\",\n      order: 1,\n      bendFirst: [true, true, true, true, true],\n    },\n    {\n      lineId: 2,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-73\"),\n      color: \"#94D40B\",\n      stationIds: [12, 11, 10, 9, 8, 4],\n      sign: \"2\",\n      order: 2,\n      bendFirst: [false, true, true, true, true, true],\n    },\n    {\n      lineId: 3,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-74\"),\n      color: \"#F8D000\",\n      stationIds: [1, 2, 3, 4, 5, 6, 7],\n      sign: \"3\",\n      order: 3,\n      bendFirst: [true, true, true, false, true, true, true],\n    },\n    {\n      lineId: 4,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-75\"),\n      color: \"#60269E\",\n      stationIds: [21, 20, 19, 18, 17, 16, 22, 23, 26, 25, 24],\n      sign: \"4\",\n      order: 4,\n      bendFirst: [\n        true,\n        false,\n        true,\n        true,\n        true,\n        true,\n        true,\n        true,\n        false,\n        true,\n        true,\n      ],\n    },\n    {\n      lineId: 5,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-76\"),\n      color: \"#934C9A\",\n      stationIds: [30, 29, 28, 31, 32, 33, 34, 35],\n      sign: \"5\",\n      order: 5,\n      bendFirst: [true, true, true, true, true, true, true, true],\n    },\n    {\n      lineId: 6,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-77\"),\n      color: \"#D80169\",\n      stationIds: [44, 42, 41, 40, 38, 34],\n      sign: \"6\",\n      order: 6,\n      bendFirst: [false, true, true, true, false, true],\n    },\n    {\n      lineId: 7,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-78\"),\n      color: \"#FE6B01\",\n      stationIds: [35, 36, 37, 39, 49, 48, 46, 45, 44],\n      sign: \"7\",\n      order: 7,\n      bendFirst: [true, true, true, false, true, true, false, true, true],\n    },\n    {\n      lineId: 8,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-79\"),\n      color: \"#00A0E8\",\n      stationIds: [47, 44, 43, 28, 27, 16, 4],\n      sign: \"8\",\n      order: 8,\n      bendFirst: [true, true, false, false, false, false, true],\n    },\n    {\n      lineId: 9,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-80\"),\n      color: \"#385f88\",\n      stationIds: [52, 51, 57, 58, 59, 60, 68, 69, 70, 71],\n      sign: \"2\",\n      order: 9,\n      bendFirst: [true, true, true, false, true, true, true, true, true, true],\n    },\n    {\n      lineId: 10,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-81\"),\n      color: \"#e8c148\",\n      stationIds: [52, 53, 54, 55, 56, 62, 60, 61],\n      sign: \"1\",\n      order: 10,\n      bendFirst: [false, false, false, true, false, true, true, true],\n    },\n    {\n      lineId: 11,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-82\"),\n      color: \"#dd8d4e\",\n      stationIds: [37, 50, 51, 55, 63, 67, 70, 72, 73, 74],\n      sign: \"3\",\n      order: 11,\n      bendFirst: [false, true, true, true, true, true, false, true, true, true],\n    },\n    {\n      lineId: 12,\n      lineName: t(\"Common-teyvat-192be7b183f6eee79-83\"),\n      color: \"#35743c\",\n      stationIds: [50, 57, 56, 63, 64, 65, 66],\n      sign: \"4\",\n      order: 12,\n      bendFirst: [true, true, true, true, true, true, true],\n    },\n  ].reduce((map, cur) => {\n    map.set(cur.lineId, cur);\n    return map;\n  }, new Map()),\n  title: t(\"teyvat\"),\n  backgroundColor: \"#fffee0\",\n};\n"
  },
  {
    "path": "src/Common/util.ts",
    "content": "import { MouseEvent, WheelEventHandler } from \"react\";\nimport UAParser from \"ua-parser-js\";\nimport { TransformProps, UserDataType } from \"../Data/UserData\";\n\nexport const mapToArr = <K, V>(map: Map<K, V>) => {\n  const arr: V[] = [];\n  map.forEach((x) => arr.push(x));\n  return arr;\n};\n\nexport const scrollOptimize = (e: MouseEvent) => {\n  const { currentTarget: editTool } = e;\n  const editTools = editTool.parentElement;\n  const { scrollHeight, childNodes, offsetHeight } = editTools!;\n  let index = 0;\n  childNodes.forEach((x, i) => {\n    if (x === editTool) index = i;\n  });\n  const scrollY =\n    ((scrollHeight - offsetHeight) / (childNodes.length - 1)) * index;\n  editTools!.scrollTo({ top: scrollY, behavior: \"smooth\" });\n};\n\nexport const arrayToMap = <T>(\n  keyName: keyof T,\n  arr: T[]\n): Map<T[keyof T], T> => {\n  const resultMap = new Map<T[keyof T], T>();\n  for (const item of arr) {\n    const keyValue = item[keyName];\n    if (keyValue !== undefined) {\n      resultMap.set(keyValue, item);\n    }\n  }\n  return resultMap;\n};\n\nexport const onWheelX: WheelEventHandler = (event) => {\n  event.stopPropagation();\n  event.preventDefault();\n  const { currentTarget, deltaY } = event;\n  currentTarget.scrollBy({\n    top: 0,\n    left: deltaY,\n    behavior: \"auto\",\n  });\n};\n\nexport const onWheelY: WheelEventHandler = (event) => {\n  const { currentTarget, deltaY } = event;\n\n  const { scrollHeight, clientHeight, scrollTop } = currentTarget;\n  const deltaHeight = scrollHeight - clientHeight;\n  const scrollMax =\n    scrollTop > deltaHeight - 1 && scrollTop < deltaHeight + 1 && deltaY > 0;\n  const scrollMin = scrollTop === 0 && deltaY < 0;\n  // console.log(deltaY, scrollTop, scrollHeight - clientHeight);\n  if (!(scrollMax || scrollMin)) {\n    currentTarget.scrollBy({\n      top: deltaY,\n      left: 0,\n      behavior: \"auto\",\n    });\n    event.stopPropagation();\n    event.preventDefault();\n  }\n};\n\nconst parser = new UAParser(navigator.userAgent);\nexport const browserInfo = parser.getResult(); //{engine:{name:''}} //\nexport function generateRandomColor(): string {\n  // Generate a random hexadecimal color\n  const hex = Math.floor(Math.random() * 16777216).toString(16);\n  // Ensure the color has sufficient contrast relative to white\n  const luminance =\n    (parseInt(hex, 16) >> 16) * 0.299 +\n    ((parseInt(hex, 16) >> 8) & 0xff) * 0.587 +\n    (parseInt(hex, 16) & 0xff) * 0.114;\n  const isLightColor = luminance > 128; // Determine if the color is light\n  // Adjust the color to be darker if it's light, or lighter if it's dark\n  const adjustedHex = isLightColor\n    ? (parseInt(hex, 16) - 0x333333).toString(16)\n    : (parseInt(hex, 16) + 0x333333).toString(16);\n  // Ensure the color is 6 digits long\n  const finalHex = adjustedHex.padStart(6, \"0\");\n  return `#${finalHex}`;\n}\n\nexport async function base64ToFile(base64: string): Promise<File> {\n  const res = await fetch(base64);\n  const blob = await res.blob();\n  return new File([blob], \"image\", { type: blob.type });\n}\n\nexport function fileToBase64(file: File): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.readAsDataURL(file);\n    reader.onload = () => resolve(reader.result as string);\n    reader.onerror = (error) => reject(error);\n  });\n}\nexport function exportJson(content: string, filename: string) {\n  const exportContent = (content: string) => {\n    const link = document.createElement(\"a\");\n    link.href = URL.createObjectURL(\n      new Blob([content], { type: \"application/json\" })\n    );\n    link.download = filename;\n    link.style.display = \"none\";\n    document.body.appendChild(link);\n    link.click();\n    document.body.removeChild(link);\n  };\n  readFileFromIndexedDB(\"image\")\n    .then((file) => {\n      fileToBase64(file!).then(\n        (image) => {\n          try {\n            const data = JSON.parse(content);\n            const dataWithImage = { ...data, image };\n            const json = JSON.stringify(dataWithImage);\n            exportContent(json);\n          } catch (e) {\n            exportContent(content);\n          }\n        },\n        () => {\n          exportContent(content);\n        }\n      );\n    })\n    .catch((e) => {\n      console.error(e);\n      exportContent(content);\n    });\n}\n\nexport function exportPNG(content: Blob, filename: string) {\n  const link = document.createElement(\"a\");\n  link.href = URL.createObjectURL(content);\n  link.download = filename;\n  link.style.display = \"none\";\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n}\n\nexport function exportFile(content: string, filename: string, type: string) {\n  const link = document.createElement(\"a\");\n  link.href = URL.createObjectURL(new Blob([content], { type }));\n  link.download = filename;\n  link.style.display = \"none\";\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n}\n\nexport function importFromFile() {\n  const input = document.createElement(\"input\");\n  const promise = parseSelectedFile(input);\n  input.type = \"file\";\n  input.accept = \".json\";\n  // document.body.appendChild(input);\n  input.click();\n  return promise.then((data) => {\n    // document.body.removeChild(input);\n    console.log(data);\n    return data;\n  });\n}\n\nfunction parseSelectedFile(input: HTMLInputElement): Promise<any> {\n  return new Promise((resolve, reject) => {\n    input.addEventListener(\"change\", () => {\n      const file = input.files?.[0];\n      if (file) {\n        const reader = new FileReader();\n        reader.onload = (event) => {\n          try {\n            const jsonContent = event.target?.result as string;\n            resolve(jsonContent);\n          } catch (error) {\n            reject(error);\n          }\n        };\n        reader.readAsText(file);\n      } else {\n        reject(new Error(\"No file selected.\"));\n      }\n    });\n  });\n}\n\nexport const stringifyData = (data: UserDataType) => {\n  const {\n    stations: stationsMap,\n    lines: linesMap,\n    title,\n    backgroundColor,\n    translateX,\n    translateY,\n    scale,\n    opacity,\n  } = data;\n  const stations = mapToArr(stationsMap);\n  const lines = mapToArr(linesMap);\n  return JSON.stringify({\n    stations,\n    lines,\n    title,\n    backgroundColor,\n    translateX,\n    translateY,\n    scale,\n    opacity,\n  });\n};\n\nexport const setLocalStorage = (data: UserDataType, callback: Function) => {\n  const last = localStorage.getItem(\"current\");\n  const current = localStorage.getItem(\"current\");\n  const latest = stringifyData(data);\n  if (latest !== current) {\n    if (current) {\n      localStorage.setItem(\"last\", current);\n    }\n    localStorage.setItem(\"current\", latest);\n    callback();\n  }\n};\n\nexport const getBoundary = (data: UserDataType) => {\n  const { stations } = data;\n  const allStationsList = mapToArr(stations);\n  let minX = Infinity,\n    minY = Infinity,\n    maxX = -Infinity,\n    maxY = -Infinity;\n  allStationsList.forEach((station) => {\n    const { position } = station;\n    const [x, y] = position;\n    minX = Math.min(x, minX);\n    minY = Math.min(y, minY);\n    maxX = Math.max(x, maxX);\n    maxY = Math.max(y, maxY);\n  });\n  return { minX, minY, maxX, maxY };\n};\n\nexport const mediateMap = (\n  data: UserDataType,\n  { setScale, setTranslateX, setTranslateY }: TransformProps\n) => {\n  const { minX, minY, maxX, maxY } = getBoundary(data);\n  const width = maxX - minX;\n  const height = maxY - minY;\n  const { innerHeight, innerWidth } = window;\n  let scale = 1,\n    transformX = -minX,\n    transformY = -minY;\n  if (innerWidth > innerHeight) {\n    const margin = innerWidth * 0.05;\n    scale = (innerWidth - margin) / width;\n    transformX = margin / 2 - minX * scale;\n    transformY = (innerHeight - height * scale) / 2 - minY * scale;\n  } else {\n    const margin = innerHeight * 0.05;\n    scale = (innerHeight - margin) / height;\n    transformY = margin / 2 - minY * scale;\n    transformX = (innerWidth - width * scale) / 2 - minX * scale;\n  }\n\n  // small size map\n  if (scale > 1) {\n    scale = 1;\n    transformX = (innerWidth - width) / 2 - minX;\n    transformY = (innerHeight - height) / 2 - minY;\n  }\n  setScale(scale);\n  setTranslateX(transformX);\n  setTranslateY(transformY);\n};\n\nexport function importImage(): Promise<File | null> {\n  return new Promise((resolve, reject) => {\n    const input = document.createElement(\"input\");\n    input.type = \"file\";\n    input.accept = \"image/*\";\n    input.onchange = (event: Event) => {\n      const target = event.target as HTMLInputElement;\n      if (target.files && target.files.length > 0) {\n        const file = target.files[0];\n        resolve(file);\n      } else {\n        resolve(null);\n      }\n    };\n    input.click();\n  });\n}\n\ninterface TransformValues {\n  translateX: number;\n  translateY: number;\n  scale: number;\n}\n\nexport function calculateTransform(file: File): Promise<TransformValues> {\n  return new Promise((resolve, reject) => {\n    const img = new Image();\n    const reader = new FileReader();\n\n    reader.onload = (e) => {\n      img.src = e.target?.result as string;\n    };\n\n    reader.onerror = (e) => {\n      reject(e);\n    };\n\n    img.onload = () => {\n      const screenWidth = window.innerWidth;\n      const screenHeight = window.innerHeight;\n\n      const imgWidth = img.width;\n      const imgHeight = img.height;\n      const imgAspectRatio = imgWidth / imgHeight;\n      const screenAspectRatio = screenWidth / screenHeight;\n\n      let scale: number;\n      if (imgAspectRatio > screenAspectRatio) {\n        // Image is wider than the screen\n        scale = (screenWidth * 0.8) / imgWidth;\n      } else {\n        // Image is taller than the screen\n        scale = (screenHeight * 0.8) / imgHeight;\n      }\n\n      const scaledWidth = imgWidth * scale;\n      const scaledHeight = imgHeight * scale;\n\n      const translateX = (screenWidth - scaledWidth) / 2;\n      const translateY = (screenHeight - scaledHeight) / 2;\n\n      resolve({ translateX, translateY, scale });\n    };\n\n    reader.readAsDataURL(file);\n  });\n}\n\nexport function storeFileInIndexedDB(\n  file: File,\n  customFileName: string\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const request = indexedDB.open(\"FileDatabase\", 1);\n\n    request.onupgradeneeded = (event) => {\n      const db = (event.target as IDBOpenDBRequest).result;\n      if (!db.objectStoreNames.contains(\"files\")) {\n        db.createObjectStore(\"files\", { keyPath: \"name\" });\n      }\n    };\n\n    request.onsuccess = (event) => {\n      const db = (event.target as IDBOpenDBRequest).result;\n      if (!db.objectStoreNames.contains(\"files\")) {\n        db.close();\n        indexedDB.deleteDatabase(\"FileDatabase\").onsuccess = () => {\n          storeFileInIndexedDB(file, customFileName).then(resolve).catch(reject);\n        };\n      } else {\n        const transaction = db.transaction(\"files\", \"readwrite\");\n        const objectStore = transaction.objectStore(\"files\");\n        const fileRecord = {\n          name: customFileName,\n          content: file,\n        };\n\n        const addRequest = objectStore.put(fileRecord);\n\n        addRequest.onsuccess = () => {\n          resolve();\n        };\n\n        addRequest.onerror = (event) => {\n          reject((event.target as IDBRequest).error);\n        };\n      }\n    };\n\n    request.onerror = (event) => {\n      reject((event.target as IDBRequest).error);\n    };\n  });\n}\n\nexport function readFileFromIndexedDB(fileName: string): Promise<File | null> {\n  return new Promise((resolve, reject) => {\n    const request = indexedDB.open(\"FileDatabase\", 1);\n\n    request.onsuccess = (event) => {\n      try {\n        const db = (event.target as IDBOpenDBRequest).result;\n        const transaction = db.transaction(\"files\", \"readonly\");\n        const objectStore = transaction.objectStore(\"files\");\n        const getRequest = objectStore.get(fileName);\n\n        getRequest.onsuccess = (event) => {\n          const result = (event.target as IDBRequest).result;\n          if (result) {\n            resolve(result.content);\n          } else {\n            resolve(null);\n          }\n        };\n\n        getRequest.onerror = (event) => {\n          reject((event.target as IDBRequest).error);\n        };\n      } catch (e) {\n        console.error(e);\n        reject(e);\n      }\n    };\n\n    request.onerror = (event) => {\n      reject((event.target as IDBRequest).error);\n    };\n  });\n}\n\nexport function deleteFileFromIndexedDB(fileName: string): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const request = indexedDB.open(\"FileDatabase\", 1);\n\n    request.onsuccess = (event) => {\n      const db = (event.target as IDBOpenDBRequest).result;\n      const transaction = db.transaction(\"files\", \"readwrite\");\n      const objectStore = transaction.objectStore(\"files\");\n      const deleteRequest = objectStore.delete(fileName);\n\n      deleteRequest.onsuccess = () => {\n        resolve();\n      };\n\n      deleteRequest.onerror = (event) => {\n        reject((event.target as IDBRequest).error);\n      };\n    };\n\n    request.onerror = (event) => {\n      reject((event.target as IDBRequest).error);\n    };\n  });\n}\n"
  },
  {
    "path": "src/Data/Shape.ts",
    "content": "export const Shape = {\n    'cicle': '圆形', // typo\n    'square': '正方形',\n    'triangle': '三角形',\n    'start': '五角星', // typo\n    'pentagon': '五边形',\n    'hexagon': '六边形',\n    'cross': '十字形',\n    'rhombus': '菱形',\n    'diamond': '钻石',\n    'leaf': '叶子',\n    'ginkgo': '银杏'\n};\n"
  },
  {
    "path": "src/Data/UserData.ts",
    "content": "import { Dispatch, SetStateAction } from \"react\";\nimport { base64ToFile, generateRandomColor, mapToArr } from \"../Common/util\";\nimport { colorSH } from \"../Common/color\";\nimport { Direct } from \"../DataStructure/Direction\";\nimport { teyvat } from \"../Common/teyvat\";\nimport i18n from \"../i18n/config\";\n\nexport class StationProps {\n  stationId!: number;\n  stationName!: string;\n  position!: number[];\n  shape!: string;\n  lineIds!: number[];\n  tagDirection?: Direct;\n}\nexport class LineProps {\n  lineId!: number;\n  lineName!: string;\n  color!: string;\n  stationIds!: number[];\n  sign!: string;\n  order!: number;\n  bendFirst!: boolean[];\n  subLine?: boolean;\n}\n\nexport type ChangeSteps = {\n  fromX: number;\n  fromY: number;\n  toX: number;\n  toY: number;\n  stationId: number;\n};\n\nexport type LineChanges = {\n  stationId: number;\n  lineId: number;\n  stationIndex: number;\n};\n\nexport type RecordType = StationProps[] | ChangeSteps[] | LineChanges[];\n\nexport class CardShowing {\n  constructor() {\n    this.stationIds = [];\n    this.lineIds = [];\n  }\n  stationIds?: number[];\n  lineIds?: number[];\n  stationFirst?: boolean;\n}\n\nexport type InsertInfo = { insertIndex: number; line: LineProps };\n\nexport class UserDataType {\n  stations!: Map<number | string, StationProps>;\n  lines!: Map<number | string, LineProps>;\n  title?: string;\n  backgroundColor?: string;\n  backgroundImage?: File;\n  opacity?: number;\n  translateX?: number;\n  translateY?: number;\n  scale?: number;\n}\n\nexport type ShowNameProps = {\n  showName: boolean;\n  setShowName: React.Dispatch<React.SetStateAction<boolean>>;\n  autoHiddenName: boolean;\n  setAutoHiddenName: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nexport type DrawProps = {\n  drawing: boolean;\n  setDrawing: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nexport type DrawerSize = {\n  drawerX: number;\n  drawerY: number;\n};\n\nexport type TransformProps = {\n  translateX: number;\n  setTranslateX: React.Dispatch<React.SetStateAction<number>>;\n  translateY: number;\n  setTranslateY: React.Dispatch<React.SetStateAction<number>>;\n  scale: number;\n  setScale: React.Dispatch<React.SetStateAction<number>>;\n};\n\nexport type ShowTourProps = {\n  showTour: boolean;\n  setShowTour: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nexport type PageProps = {\n  page: string;\n  setPage: React.Dispatch<React.SetStateAction<string>>;\n};\n\nexport const initData = {\n  ...teyvat,\n};\n\nexport const setDataFromJson = (\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  jsonString: string\n) => {\n  const res = JSON.parse(jsonString);\n  const {\n    stations: stationsArr,\n    lines: linesArr,\n    title,\n    backgroundColor,\n    translateX,\n    translateY,\n    scale,\n    opacity,\n    image,\n  }: {\n    stations: StationProps[];\n    lines: LineProps[];\n    title: string;\n    backgroundColor: string;\n    translateX: number;\n    translateY: number;\n    scale: number;\n    opacity: number;\n    image: string;\n  } = res;\n  const stations = stationsArr.reduce((map, cur) => {\n    map.set(cur.stationId, cur);\n    return map;\n  }, new Map());\n  const lines = linesArr.reduce((map, cur) => {\n    map.set(cur.lineId, cur);\n    return map;\n  }, new Map());\n  const data = {\n    stations,\n    lines,\n    title,\n    backgroundColor,\n    translateX,\n    translateY,\n    scale,\n    opacity,\n  };\n  setData(data);\n  if (image)\n    base64ToFile(image)\n      .then((backgroundImage) => {\n        setData({ ...data, backgroundImage });\n      })\n      .catch((e) => {\n        console.error(e);\n      });\n  return data;\n};\n\nexport const deleteStation = (\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  stationId: number\n) => {\n  const { stations, lines } = data;\n  const station = stations.get(stationId);\n  const { lineIds } = station!;\n  //detele stations in line\n  lineIds.forEach((lineId) => {\n    const newStationIds: number[] = [];\n    const newBendFirst: boolean[] = [];\n    const line = lines.get(lineId);\n    const { stationIds, bendFirst } = line!;\n    stationIds.forEach((id, index) => {\n      if (stationId !== id) {\n        // break the cicle\n        if (id !== newStationIds[newStationIds.length - 1]) {\n          newStationIds.push(id);\n          newBendFirst.push(bendFirst[index]);\n        }\n      }\n    });\n\n    lines.set(lineId, {\n      ...line!,\n      stationIds: newStationIds,\n      bendFirst: newBendFirst,\n    });\n  });\n  // delete station\n  stations.delete(stationId);\n  setData({ ...data });\n};\nexport const deleteLine = (\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  lineId: number\n) => {\n  const { stations, lines } = data;\n  const line = lines.get(lineId);\n  const { stationIds } = line!;\n  //detele stations in line\n  stationIds.forEach((stationId) => {\n    const newLineIds: number[] = [];\n    const station = stations.get(stationId);\n    const { lineIds } = station!;\n    lineIds.forEach((id) => {\n      if (lineId !== id) {\n        newLineIds.push(id);\n      }\n    });\n    stations.set(stationId, {\n      ...station!,\n      lineIds: newLineIds,\n    });\n  });\n  // delete line\n  lines.delete(lineId);\n  setData({ ...data });\n};\nexport const dataProcessor = (\n  id: number,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  state: UserDataType\n) => {\n  const { stations, lines } = state;\n  return {\n    setStationName: (name: string) => {\n      setData((state) => {\n        const station = stations.get(id);\n        station!.stationName = name;\n        return { ...state };\n      });\n    },\n    setStationPosition: (x: number, y: number) => {\n      setData((state) => {\n        const station = stations.get(id);\n        station!.position = [x, y].map((x) =>\n          Number.isNaN(x) ? 0 : Math.round(x)\n        );\n        return { ...state };\n      });\n    },\n    setStationShape: (shape: string) => {\n      setData((state) => {\n        const station = stations.get(id);\n        station!.shape = shape;\n        return { ...state };\n      });\n    },\n    setStationTagDirection: (direct: Direct) => {\n      setData((state) => {\n        const station = stations.get(id);\n        station!.tagDirection = direct;\n        if (direct === 8) delete station!.tagDirection;\n        return { ...state };\n      });\n    },\n    getStationById: (stationId: string | number) => {\n      return stations.get(stationId);\n    },\n    getLineById: (lineId: string | number) => {\n      return lines.get(lineId);\n    },\n    getStationsInThisLine: () => {\n      return lines.get(id)!.stationIds.map((x) => stations.get(x));\n    },\n    setLineName: (name: string) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.lineName = name;\n        return { ...state };\n      });\n    },\n    setSign: (sign: string) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.sign = sign;\n        return { ...state };\n      });\n    },\n    setOrder: (order: number) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.order = order;\n        return { ...state };\n      });\n    },\n    setColor: (color: string) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.color = color;\n        return { ...state };\n      });\n    },\n    setSubLine: (subLine: boolean) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.subLine = subLine;\n        if (!subLine) delete line!.subLine;\n        return { ...state };\n      });\n    },\n    getBendFirst: (stationIndex: number) => {\n      const line = lines.get(id);\n      return line?.bendFirst[stationIndex];\n    },\n    setBendFirst: (stationIndex: number, bendFirst: boolean) => {\n      setData((state) => {\n        const line = lines.get(id);\n        line!.bendFirst[stationIndex] = bendFirst;\n        return { ...state };\n      });\n    },\n    deleteStation: () => deleteStation(state, setData, id),\n    deleteLine: () => deleteLine(state, setData, id),\n    removeStationFromLine: (lineId: number, stationIndex: number) => {\n      setData((state) => {\n        const station = stations.get(id);\n        const line = lines.get(lineId);\n        const { stationIds, bendFirst } = line!;\n        if (stationIds[stationIndex] === id) {\n          stationIds.splice(stationIndex, 1);\n          bendFirst.splice(stationIndex, 1);\n          if (!stationIds.some((stationId) => stationId === id)) {\n            const { lineIds } = station!;\n            station!.lineIds = lineIds.filter((id) => lineId !== id);\n          }\n          if (stationIds[stationIndex - 1] === stationIds[stationIndex]) {\n            stationIds.splice(stationIndex, 1);\n            bendFirst.splice(stationIndex, 1);\n          }\n        }\n        return { ...state };\n      });\n    },\n    addNewLine: () => {\n      const newLine = new LineProps();\n      setData((state) => {\n        const maxId = mapToArr(lines).reduce(\n          (pre, cur) => Math.max(pre, cur.lineId),\n          0\n        );\n        const lineId = maxId + 1;\n        Object.assign(newLine, {\n          lineId: lineId,\n          lineName:i18n.t(\"lineNo\",{lineId}),\n          color: colorSH[lineId - 1]\n            ? colorSH[lineId - 1].color\n            : generateRandomColor(),\n          stationIds: [id],\n          sign: lineId.toString(),\n          order: lineId,\n          bendFirst: [true],\n        });\n        const station = stations.get(id);\n        const { lineIds } = station!;\n        station!.lineIds = [...new Set(lineIds.concat([lineId]))];\n        lines.set(lineId, newLine);\n        return { ...state };\n      });\n      return newLine;\n    },\n    addStationToLine: (stationId: number, stationIndex: number) => {\n      return new Promise(res=>{\n       setData((state) => {\n        const line = lines.get(id);\n        if (!line) debugger;\n        const { stationIds, bendFirst } = line!;\n        console.log(structuredClone(stationIds));\n        if (\n          stationIds[stationIndex] !== stationId &&\n          stationIds[stationIndex - 1] !== stationId\n        ) {\n          stationIds.splice(stationIndex, 0, stationId);\n          bendFirst.splice(stationIndex, 0, true);\n          if(stationIds.some((x,index)=>x===stationIds[index-1]||x===stationIds[index+1])) debugger\n          const station = stations.get(stationId);\n          const { lineIds } = station!;\n          station!.lineIds = [...new Set(lineIds.concat([id]))];\n          res(true);\n        } else {\n          res(false);  \n        }\n        return { ...state };\n      }); \n      });\n    },\n  };\n};\n\nexport const addNewStation = (\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  x: number,\n  y: number,\n  record: StationProps[],\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>,\n  currentRecordIndex: number,\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>,\n  cardShowing: CardShowing,\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>,\n  defaultShape: string,\n) => {\n  const { stations } = data;\n  let max = 0;\n  stations.forEach((station) => {\n    max = Math.max(station.stationId, max);\n  });\n  const stationId = max + 1;\n  const newStation = {\n    stationId,\n    stationName: `${i18n.t('newStation')} ${max + 1}`,\n    position: [x, y].map(Math.round),\n    shape: defaultShape,\n    lineIds: [],\n  };\n  setCardShowing({ stationIds: [stationId] });\n  const newRecord = record.slice(0, currentRecordIndex + 1);\n  setRecord(newRecord.concat([newStation]));\n  setCurrentRecordIndex(currentRecordIndex + 1);\n  stations.set(max + 1, newStation);\n  setData({ ...data });\n};\n\nexport const addStationFromRecord = (\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  station: StationProps\n) => {\n  const { stations } = data;\n  let max = 0;\n  stations.forEach((station) => {\n    max = Math.max(station.stationId, max);\n  });\n  const newStation = { ...station, stationId: max + 1 };\n  stations.set(max + 1, newStation);\n  setData({ ...data });\n};\n"
  },
  {
    "path": "src/DataStructure/Bend.ts",
    "content": "import { Rail } from \"./Rail\";\nimport { Track } from \"./Track\";\n\nexport class Bend {\n  // filter empty indexes\n  static round1(track: Track) {\n    const emptyRails = track.getEmptyRails().map((rail) => rail.index);\n    if (emptyRails.length) return emptyRails;\n    return [0, 1, 2];\n  }\n  // filter opposite rails\n  static round2(track: Track, round1Indexes: number[], rail?: Rail) {\n    // rail not exist or in/out rail direction not just opposite to the candidate rail direction\n    if (!rail || !rail.track.direction.oppositeTo(track.direction))\n      return round1Indexes;\n    return round1Indexes.filter(\n      (railIndex) => rail.oppositeIndex() === railIndex\n    );\n  }\n  // filter center rail\n  static round3(round2Indexes: number[]) {\n    if (round2Indexes.find((railIndex) => railIndex === 1)) return 1;\n  }\n\n  // filter most close rail\n  static round4(track: Track, rail?: Rail) {\n    if (!rail) return 0;\n    return rail.track.direction.rotationTo(track.direction) > 0 ? 0 : 2;\n  }\n\n  static getBestRailIndex(track: Track, rail?: Rail) {\n    const round1Indexes = this.round1(track);\n    if (round1Indexes.length === 1) return round1Indexes[0];\n    const round2Indexes = this.round2(track, round1Indexes, rail);\n    if (round2Indexes.length === 1) return round2Indexes[0];\n    const round3Res = this.round3(round2Indexes);\n    if (round3Res === 1) return 1;\n    const round4Res = this.round4(track, rail);\n    return round4Res;\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/ConnectType.ts",
    "content": "export enum ConnectType {\n    straight,\n    straightFirst,\n    bendFirst\n  }"
  },
  {
    "path": "src/DataStructure/Direction.ts",
    "content": "//clockwise\n\nexport enum Direct {\n  up,\n  upRight,\n  right,\n  rightDown,\n  down,\n  downLeft,\n  left,\n  leftUp,\n  // Quadrant I bisected by a diagonal line\n  // upRightA means the upper half\n  // upRightB means the lower half\n  // all the directions is marked in clockwise\n  upRightA,\n  upRightB,\n  rightDownA,\n  rightDownB,\n  downLeftA,\n  downLeftB,\n  leftUpA,\n  leftUpB,\n  coincide,\n}\n\nexport class Direction {\n  direct: Direct;\n  standard: boolean;\n  lean: boolean;\n  constructor(direct: Direct) {\n    this.direct = direct;\n    this.standard = direct < 8;\n    this.lean = direct % 2 === 1;\n  }\n\n  delta(direct: Direct){\n    const diff = Math.abs(direct - this.direct);\n    return Math.min(diff, 8-diff);\n  }\n\n  opposite() {\n    if (this.direct < 8) return new Direction((this.direct + 4) % 8);\n    if (this.direct >= 8 && this.direct < 12)\n      return new Direction(this.direct + 4);\n    if (this.direct >= 12 && this.direct < 16)\n      return new Direction(this.direct - 4);\n    return new Direction(this.direct);\n  }\n\n  oppositeTo(direction: Direction | undefined) {\n    if (direction) return direction.opposite().direct === this.direct;\n    throw new Error(\"no direction!\");\n  }\n\n  sameTo(direction: Direction) {\n    return this.direct === direction.direct;\n  }\n\n  // how many rotation should this direction do to coincide to given direction\n  // 1 2 3 means clockwise rotate 1 2 3 times\n  // -1 -2 -3 means counterclockwise\n  // 0 means no need rotate\n  // 4 means opposite direction\n  rotationTo(direction: Direction) {\n    if (this.oppositeTo(direction)) return 4;\n    const side = direction.direct - this.direct;\n    if (side < -4) return side + 8;\n    if (side > 4) return side - 8;\n    return side;\n  }\n  getBendSteps(bendFirst: boolean) {\n    if (this.direct < 8 || this.direct > 15) {\n      throw new Error(\"this is not bend direction\");\n    }\n    const firstStep = new Direction(this.direct - 7 - (this.direct % 2));\n    const secondStep = new Direction((this.direct - 8 + (this.direct % 2)) % 8);\n    return bendFirst ? [firstStep, secondStep] : [secondStep, firstStep];\n  }\n}\n\nexport const DirectionVictor = [\n  [0, 1],\n  [1, 1],\n  [1, 0],\n  [1, -1],\n  [0, -1],\n  [-1, -1],\n  [-1, 0],\n  [-1, 1],\n];\n\nexport const DirectionVictorReverseY = DirectionVictor.map(([x,y])=>[x,-y]);\n"
  },
  {
    "path": "src/DataStructure/Display.ts",
    "content": "import { Station } from \"./Station\";\n\nexport class DisplayStation {\n    stationName: string;\n    bendFirst: boolean;\n    constructor(stationName: string, bendFirst: boolean){\n        this.stationName = stationName;\n        this.bendFirst = bendFirst;\n    }\n}"
  },
  {
    "path": "src/DataStructure/Line.ts",
    "content": "import { LineProps } from \"../Data/UserData\";\nimport { Bend } from \"./Bend\";\nimport { ConnectType } from \"./ConnectType\";\nimport { LineRecord } from \"./LineRecord\";\nimport { Rail } from \"./Rail\";\nimport { RailPair } from \"./RailPair\";\nimport { Station } from \"./Station\";\nimport { Straight } from \"./Straight\";\nimport { Vector } from \"./Vector\";\nexport class Line {\n  empty: boolean;\n  departureRecord: LineRecord | undefined;\n  _dev_tag: string | undefined;\n  displayLine?: LineProps;\n  constructor() {\n    this.empty = false;\n  }\n\n  getTerminalRecord(){\n    let p = this.departureRecord;\n    while(p?.nextLineRecord){\n      p = p.nextLineRecord;\n      if(p === this.departureRecord || !p.nextLineRecord) return p;\n    }\n    return p;\n  }\n\n  linkAll(stations: Station[]){\n    stations.reduce((pre,cur)=>{\n      this.link(pre,cur);\n      return cur;\n    });\n  }\n\n\n  // connect B station and C station\n  link(B: Station, C: Station, bendFirst: boolean = true) {\n    const railPair = this.applyBestRailPair(B,C,bendFirst);\n    railPair.setLine(this);\n    let bLineRecord = B.getJoint(this);\n    if (!bLineRecord) {\n      //if record not exist, add one\n      bLineRecord = new LineRecord(B, this);\n      // register cLineRecord in C station\n      B.addLineRecord(bLineRecord);\n      this.departureRecord = bLineRecord;\n    }\n    let cLineRecord// = C.getJoint(this);\n    if (!cLineRecord) {\n      cLineRecord = new LineRecord(C, this);\n      // register cLineRecord in C station\n      C.addLineRecord(cLineRecord);\n    }\n    // establish doubly linked list\n    bLineRecord?.establishConnectionTo(cLineRecord);\n    // update rail and connect type for B and C\n    LineRecord.updateLineRecords(bLineRecord, cLineRecord, railPair);\n  }\n\n  applyBestRailPair(B: Station, C: Station, bendFirst: boolean) {\n    const direction = new Vector(B.position, C.position);\n    if (direction.standard) {\n      const bOutIndex = Straight.getBestRailIndex(B, C, this);\n      const cInIndex = Rail.oppositeIndex(bOutIndex);\n      // if(B.displayStation?.stationName==='风起地站'&&C.displayStation?.stationName==='达达乌帕谷') debugger\n      const bTrack = B.getTrack(direction);\n      const cTrack = C.getTrack(direction.opposite());\n      const bRail = bTrack.getAvailableRail(bOutIndex);\n      const cRail = cTrack.getAvailableRail(cInIndex);\n      return new RailPair(bRail, cRail);\n    } else {\n      const [bOutDirection, cInDirectionOpposite] =\n        direction.getBendSteps(bendFirst);\n      const cInDirection = cInDirectionOpposite.opposite();\n      const bTrack = B.getTrack(bOutDirection);\n      const cTrack = C.getTrack(cInDirection);\n      const bLastRail = B.getJoint(this)?.lastRail;\n      const cNextRail = C.getJoint(this)?.nextRail;\n      const bOutIndex = Bend.getBestRailIndex(bTrack, bLastRail);\n      const cInIndex = Bend.getBestRailIndex(cTrack, cNextRail);\n      const bRail = bTrack.getAvailableRail(bOutIndex);\n      const cRail = cTrack.getAvailableRail(cInIndex);\n      return new RailPair(bRail, cRail);\n    }\n  }\n}\n\nexport class EmptyLine extends Line {\n  constructor() {\n    super();\n    this.empty = true;\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/LineRecord.ts",
    "content": "import { ConnectType } from \"./ConnectType\";\nimport { Line } from \"./Line\";\nimport { Rail } from \"./Rail\";\nimport { RailPair } from \"./RailPair\";\nimport { Station } from \"./Station\";\n\nexport class LineRecord {\n  station: Station;\n  line: Line | undefined;\n  lastLineRecord: LineRecord | undefined;\n  nextLineRecord: LineRecord | undefined;\n  lastRail: Rail | undefined;\n  nextRail: Rail | undefined;\n\n  constructor(station: Station, line?: Line) {\n    this.station = station;\n    if (line) {\n      this.line = line;\n    }\n  }\n\n  getInDirection(){\n    return this.lastRail?.track.direction;\n  }\n\n  getOutDirection(){\n    return this.nextRail?.track.direction;\n  }\n  establishConnectionTo(BRecord: LineRecord) {\n    LineRecord.establishConnection(this, BRecord);\n  }\n\n  static establishConnection(ARecord: LineRecord, BRecord: LineRecord) {\n    ARecord.nextLineRecord = BRecord;\n    BRecord.lastLineRecord = ARecord;\n  }\n\n  // update the rail and connect type information for connectting 2 linerecords\n  static updateLineRecords(\n    ARecord: LineRecord,\n    BRecord: LineRecord,\n    railPair: RailPair,\n  ) {\n    const { departureRail, arrivalRail } = railPair;\n    ARecord.nextRail = departureRail;\n    BRecord.lastRail = arrivalRail;\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/Mode.ts",
    "content": "export enum Mode {\n    normal,\n    moving,\n    touchMoving,\n    touchScaling\n  }\n\n\n  export enum FunctionMode{\n    normal,\n    addingStation,\n    dragingStation,\n    lineEditing,\n    backgroundEditing,\n    customBackground,\n    editingCustomBackgroundPosition,\n    selectingStation,\n    choosingExistMap,\n  }"
  },
  {
    "path": "src/DataStructure/Point.ts",
    "content": "import { MouseEvent, Touch } from \"react\";\nimport { Straight } from \"./Straight\";\n\nexport class Point {\n  x: number;\n  y: number;\n  yReversed: boolean;\n  q_start: boolean;\n  q: boolean;\n  q_end: boolean;\n  constructor(x: number = 0, y: number = 0, yReversed: boolean = false) {\n    this.x = x;\n    this.y = y;\n    this.yReversed = yReversed;\n    this.q_start = false;\n    this.q = false;\n    this.q_end = false;\n  }\n\n  round(){\n    return new Point(Math.round(this.x), Math.round(this.y))\n  }\n\n  offset(A: Point) {\n    return new Point(A.x + this.x, A.y + this.y);\n  }\n\n  displacementTo(A: Point) {\n    return new Point(this.x - A.x, this.y - A.y);\n  }\n\n  distanceTo(A: Point) {\n    return Math.sqrt(Math.pow(this.x - A.x, 2) + Math.pow(this.y - A.y, 2));\n  }\n\n  sameTo(A: Point) {\n    return A.x === this.x && A.y === this.y && A.yReversed === this.yReversed;\n  }\n\n  reverseY() {\n    return new Point(this.x, -this.y, !this.yReversed);\n  }\n\n  static getPointFromTouch(A: Touch) {\n    return new Point(A.clientX, A.clientY);\n  }\n\n  static getPointFromMouse(A: MouseEvent) {\n    return new Point(A.clientX, A.clientY);\n  }\n\n  static getMidPoint(A: Point, B: Point) {\n    return new Point((A.x + B.x) / 2, (A.y + B.y) / 2);\n  }\n\n  static getDisplacement(A: Point, B: Point) {\n    return new Point(A.x - B.x, A.y - B.y);\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/Rail.ts",
    "content": "import { EmptyLine, Line } from \"./Line\";\nimport { RailPair } from \"./RailPair\";\nimport { Track } from \"./Track\";\n\nexport class Rail {\n  track: Track;\n  index: number;\n  line: Line;\n  extra: boolean;\n  constructor(track: Track, index: number) {\n    this.track = track;\n    this.index = index;\n    this.line = new EmptyLine();\n    this.extra = false;\n  }\n\n  oppositeIndex(){\n    return 2 - this.index;\n  }\n\n  setLine(line: Line){\n    this.line = line;\n  }\n\n  static getStraightConnectRailPair(aEmptyRails: Rail[], bEmptyRails: Rail[]) {\n    if (aEmptyRails.length === 0 || bEmptyRails.length === 0) return;\n    const railPairs: RailPair[] = [];\n    aEmptyRails.forEach((aRail) => {\n      bEmptyRails.forEach((bRail) => {\n        //found just opposite rail\n        if (aRail.index + bRail.index === 2) {\n          railPairs.push(new RailPair(aRail,bRail));\n        }\n      });\n    });\n    return railPairs;\n  }\n  \n  static getBestRail(rails: Rail[]){\n    return rails.find(rail=>rail.index === 1) || rails[0];\n  }\n\n  static getRailByIndex(rails: Rail[], index: number){\n    return rails.find(rail=>rail.index === index);\n  }\n\n  static oppositeIndex(index: number){\n    return 2 - index;\n  }\n\n}\n\nexport class ExtraRail extends Rail{\n    constructor(track: Track, index: number){\n      super(track, index);\n      this.extra = true;\n    }\n}\n\n\n"
  },
  {
    "path": "src/DataStructure/RailPair.ts",
    "content": "import { Direction } from \"./Direction\";\nimport { Line } from \"./Line\";\nimport { Rail } from \"./Rail\";\nimport { Station } from \"./Station\";\n\nexport class RailPair {\n    departureRail: Rail;\n    arrivalRail: Rail;\n    center: boolean;\n    constructor(departureRail: Rail, arrivalRail: Rail) {\n      this.departureRail = departureRail;\n      this.arrivalRail = arrivalRail;\n      this.center = departureRail.index === 1;\n    }\n\n    reverse(){\n      const temp = this.departureRail;\n      this.departureRail = this.arrivalRail;\n      this.arrivalRail = temp;\n    }\n\n    setLine(line: Line){\n      this.departureRail.setLine(line);\n      this.arrivalRail.setLine(line);\n    }\n  }"
  },
  {
    "path": "src/DataStructure/Station.ts",
    "content": "import { StationProps } from \"../Data/UserData\";\nimport { Direct, Direction } from \"./Direction\";\nimport { Line } from \"./Line\";\nimport { LineRecord } from \"./LineRecord\";\nimport { Point } from \"./Point\";\nimport { Rail } from \"./Rail\";\nimport { Track } from \"./Track\";\n\nexport class Station {\n  position: Point;\n  tracks: Track[];\n  lineRecords: Map<Line, LineRecord[]>;\n  _dev_tag: string | undefined;\n  handlers: (Line | undefined | null)[];\n  displayStation?: StationProps;\n  constructor(position: Point) {\n    this.position = position;\n    this.tracks = new Array(8)\n      .fill(true)\n      .map((x, direct: Direct) => new Track(this, new Direction(direct)));\n    this.lineRecords = new Map();\n    this.handlers = new Array(8);\n  }\n\n  lineCount(){\n    const set = new Set();\n    this.lineRecords.forEach(line=>{\n      set.add(line);\n    })\n    return set.size;\n  }\n  isEmpty(direct: Direct){\n    return !this.handlers[direct] && this.tracks[direct].isEmpty();\n  }\n\n  getBestDirectionForName() {\n    let space = 0,\n      endIndex = 0,\n      maxSpace = 0,\n      firstSpace;\n    for (let i = 0; i < 8; i++) {\n      const empty = !this.handlers[i] && this.tracks[i].isEmpty();\n      if (empty) {\n        space++;\n        if (space > maxSpace) {\n          maxSpace = space;\n          endIndex = i;\n        }\n      } else {\n        if (firstSpace === undefined) firstSpace = space;\n        space = 0;\n      }\n    }\n    // all empty\n    if (space === 8 || maxSpace===0) {\n      return Direct.right;\n    }\n    if(maxSpace <= 2) {\n      if(this.isEmpty(2)) return 2;\n      if(this.isEmpty(6)) return 6;\n      if(this.isEmpty(1)) return 1;\n      if(this.isEmpty(3)) return 3;\n      if(this.isEmpty(5)) return 5;\n      if(this.isEmpty(7)) return 7;\n    }\n    if(firstSpace === undefined) firstSpace =0;\n    if (space + firstSpace >= maxSpace) {\n      // max space containing 0\n      if (firstSpace >= space) {\n        return Math.floor((firstSpace - space) / 2);\n      } else if (space > firstSpace) {\n        return 7 - Math.floor((space - firstSpace) / 2);\n      }\n    }\n      const best = endIndex - Math.floor(maxSpace / 2)\n      // max space not containing 0\n      if(maxSpace%2===0){\n        if(best%2===0){\n          return best+1;\n        }\n      }\n      return best;\n\n  }\n\n\n  getBestDirectionForName2(){\n  }\n  \n\n  addLineRecord(lineRecord: LineRecord) {\n    const { line, station } = lineRecord;\n    if (!line) {\n      throw new Error(\"line is undefined while add line record to statation\");\n    }\n    if (station !== this) {\n      throw new Error(\n        \"you are adding a line record which not belongs to this station\"\n      );\n    }\n    // this lineRecords is the array saving linerecords\n    const lineRecordsArr = this.lineRecords.get(line) || [];\n    lineRecordsArr.push(lineRecord);\n    // this.lineRecords is the map Line=>Line\n    // containing all the information of the lines go through this station\n    this.lineRecords.set(line, lineRecordsArr);\n  }\n\n  getTrack(direction: Direction) {\n    return this.tracks[direction.direct];\n  }\n\n  getRail(direction: Direction, index: number) {\n    return this.getTrack(direction).getRail(index);\n  }\n\n  // getBestRail(direction: Direction){\n  //   return this.getTrack(direction).getBestRail();\n  // }\n\n  // find the start or end of the Line\n  // if no records find, this station must be the departure station\n  // if both start and end exist, this station is the loop line joint\n  getJoint(line: Line) {\n    const terminal = this.lineRecords\n      .get(line)\n      ?.find((lineRecord) => !lineRecord.lastLineRecord);\n    const departure = this.lineRecords\n      .get(line)\n      ?.find((lineRecord) => !lineRecord.nextLineRecord);\n    return departure || terminal;\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/Straight.ts",
    "content": "import { Direction } from \"./Direction\";\nimport { Line } from \"./Line\";\nimport { Point } from \"./Point\";\nimport { Rail } from \"./Rail\";\nimport { Station } from \"./Station\";\nimport { Track } from \"./Track\";\nimport { Vector } from \"./Vector\";\n\nexport class Straight {\n  // round 1 : filter empty rails\n  static round1(B: Station, C: Station) {\n    const direction = new Vector(B.position, C.position);\n    const bTrack = B.getTrack(direction);\n    const cTrack = C.getTrack(direction.opposite());\n    const initScores = [0, 1, 2];\n    let max = 0;\n    const round1Indexes = initScores\n      .map((index) => {\n        let score = 0;\n        // if rail in bTrack is empty, this rail add one score\n        if (bTrack.rails[index].line.empty) {\n          score++;\n        }\n        // if rail in cTrack is empty, this rail add one score\n        if (cTrack.rails[Rail.oppositeIndex(index)].line.empty) {\n          score++;\n        }\n        // record the highest score\n        if (score > max) {\n          max = score;\n        }\n        return { index, score };\n      })\n      .filter(({ score }) => {\n        // find the highest score indexes\n        return score === max;\n      });\n    return round1Indexes;\n  }\n\n  // round 2 : filter straight pass rails\n  static round2(\n    B: Station,\n    C: Station,\n    round1Indexes: RoundResult[],\n    line: Line\n  ) {\n    const direction = new Vector(B.position, C.position);\n    const bLineRecord = B.getJoint(line);\n    const cLineRecord = C.getJoint(line);\n    let max = 0;\n    const round2Indexes = round1Indexes\n      .map(({ index }) => {\n        let score = 0;\n        if (\n          bLineRecord?.lastRail?.track.direction.oppositeTo(direction) &&\n          bLineRecord?.lastRail?.oppositeIndex() === index\n        ) {\n          score++;\n        }\n        if (\n          cLineRecord?.nextRail?.track.direction.sameTo(direction) &&\n          cLineRecord?.nextRail?.index === index\n        ) {\n          score++;\n        }\n        if (score > max) {\n          max = score;\n        }\n        return { index, score };\n      })\n      .filter(({ score }) => {\n        // find the highest score indexes\n        return score === max;\n      });\n    return round2Indexes;\n  }\n\n  // round 3 : filter center rails\n  static round3(B: Station, C: Station, round2Indexes: RoundResult[]) {\n    const round3Res = round2Indexes.find(({ index }) => index === 1);\n    return round3Res ? 1 : 0;\n  }\n\n  // round 4 : filter most close to the last or next rail\n  static round4(B: Station, C: Station, line: Line) {\n    const direction = new Vector(B.position, C.position);\n    const bLineRecord = B.getJoint(line);\n    const cLineRecord = C.getJoint(line);\n    let zeroRailScore = 0;\n    let secondRailScore = 0;\n    if (bLineRecord?.lastRail)\n      if (bLineRecord.lastRail.track.direction.rotationTo(direction) > 0)\n        zeroRailScore++;\n      else secondRailScore++;\n\n    if (cLineRecord?.nextRail)\n      if (cLineRecord.nextRail.track.direction.rotationTo(direction) > 0)\n        zeroRailScore++;\n      else secondRailScore++;\n\n    return zeroRailScore > secondRailScore ? 0 : 2;\n  }\n\n  static getBestRailIndex(B: Station, C: Station, line: Line) {\n    if (B._dev_tag === \"B\" && line._dev_tag === \"line8\") {\n      // debugger;\n    }\n    // round 1:\n    const round1Indexes = Straight.round1(B, C);\n    if (round1Indexes.length === 1) {\n      return round1Indexes[0].index;\n    }\n    // round 2:\n    const round2Indexes = Straight.round2(B, C, round1Indexes, line);\n    if (round2Indexes.length === 1) {\n      return round2Indexes[0].index;\n    }\n    // round 3:\n    const round3Index = Straight.round3(B, C, round2Indexes);\n    if (round3Index === 1) {\n      return round3Index;\n    }\n    // round 4:\n    const round4Index = Straight.round4(B, C, line);\n    return round4Index;\n  }\n}\n\nclass RoundResult {\n  score!: number;\n  index!: number;\n}\n"
  },
  {
    "path": "src/DataStructure/Track.ts",
    "content": "import { Direction } from \"./Direction\";\nimport { ExtraRail, Rail } from \"./Rail\";\nimport { Station } from \"./Station\";\n\nexport class Track {\n  station: Station;\n  direction: Direction;\n  rails: Rail[];\n  // extra rail won't occupy the space of rail\n  // extraRails save extraRail by index, every index has an array\n  extraRails: ExtraRail[][];\n  constructor(station: Station, direction: Direction) {\n    this.station = station;\n    this.direction = direction;\n    this.rails = new Array(3)\n      .fill(true)\n      .map((x, index) => new Rail(this, index));\n    this.extraRails = new Array(3).fill(true).map((x, index) => new Array());\n  }\n\n  isEmpty(){\n    return !this.rails.some(rail=>!rail.line.empty)\n  }\n\n  getEmptyRails() {\n    return this.rails.filter((rail) => rail.line.empty);\n  }\n\n  getRail(index: number) {\n    return this.rails[index];\n  }\n\n  applyExtraRail(index: number) {\n    const extraRail = new ExtraRail(this, index);\n    this.extraRails[index].push(extraRail);\n    return extraRail;\n  }\n\n  getAvailableRail(index: number) {\n    const rail = this.getRail(index);\n    return rail.line.empty ? rail : this.applyExtraRail(index);\n  }\n}\n"
  },
  {
    "path": "src/DataStructure/Vector.ts",
    "content": "import { Direct, Direction, DirectionVictorReverseY } from \"./Direction\";\nimport { Point } from \"./Point\";\n\nexport class Vector extends Direction {\n  start: Point; // startPoint\n  end: Point; // endPoint\n  constructor(start: Point, end: Point) {\n    super(Vector.getDirection(start, end));\n    this.start = start;\n    this.end = end;\n  }\n\n  verticalProlong(length: number) {\n    const A = this.start,\n      B = this.end;\n    if (A.x === B.x)\n      return [new Point(B.x + length, B.y), new Point(B.x - length, B.y)];\n    const diffSign = (A.x<B.x && A.y<B.y) || (A.x>B.x&&A.y>B.y);\n    const tan = (B.y - A.y) / (B.x - A.x);\n    const alpha = Math.abs(Math.atan(tan));\n    const sin = Math.sin(alpha);\n    const cos = Math.cos(alpha);\n\n    if(diffSign)\n    return [\n      new Point(B.x - sin * length, B.y + cos * length),\n      new Point(B.x + sin * length, B.y - cos * length),\n    ];\n    return [\n      new Point(B.x - sin * length, B.y - cos * length),\n      new Point(B.x + sin * length, B.y + cos * length),\n    ];\n    \n  }\n\n  prolong(length: number) {\n    const A = this.start,\n      B = this.end;\n    const kX = A.x < B.x ? 1 : -1;\n    const kY = A.y < B.y ? 1 : -1;\n    if (A.x === B.x) return new Point(A.x, B.y + kY * length);\n    const tan = (B.y - A.y) / (B.x - A.x);\n    const alpha = Math.abs(Math.atan(tan));\n    const sin = Math.sin(alpha);\n    const cos = Math.cos(alpha);\n    return new Point(B.x + kX * cos * length, B.y + kY * sin * length);\n  }\n\n  normalize(k: number = 1) {\n    const deltaX = this.end.x - this.start.x;\n    const deltaY = this.end.y - this.start.y;\n    const module = Math.sqrt(\n      Math.pow(deltaX, 2) + Math.pow(deltaY, 2)\n    );\n    return new Vector(\n      new Point(0, 0),\n      new Point((k * deltaX) / module, (k * deltaY) / module)\n    );\n  }\n\n  passesThroughPoint(A: Point) {\n    return (\n      (A.x - this.start.x) * (A.y - this.end.y) ===\n      (A.y - this.start.y) * (A.x - this.end.x)\n    );\n  }\n\n  round() {\n    return new Vector(this.start.round(), this.end.round());\n  }\n\n  passesThroughPointRound(point: Point) {\n    const A = point.round();\n    const vector = this.round();\n    return this.passesThroughPoint.bind(vector)(A);\n  }\n\n  getCrossPointTo(b: Vector) {\n    const a = this;\n    const A = a.start,\n      B = a.end,\n      C = b.start,\n      D = b.end;\n\n    const m = (A.x - B.x) / (A.y - B.y);\n    const n = (C.x - D.x) / (C.y - D.y);\n    // if(!Number.isFinite(m)) return new Point(A.x, (A.x - C.x) / n + C.y);\n    // if(!Number.isFinite(n)) return new Point(C.x, (C.x - A.x) / m + A.y);\n    if (!Number.isFinite(m)) return new Point(n * (A.y - C.y) + C.x, A.y);\n    if (!Number.isFinite(n)) return new Point(m * (C.y - A.y) + A.x, C.y);\n    const y = (C.x - A.x + m * A.y - n * C.y) / (m - n);\n    const x = n * (y - C.y) + C.x;\n    return new Point(x, y);\n  }\n\n  static getVectorByPointAndDirection(A: Point, direction: Direction) {\n    const [x, y] = DirectionVictorReverseY[direction.direct];\n    return new Vector(A, new Point(A.x + x, A.y + y));\n  }\n\n  static getDirection(start: Point, end: Point) {\n    const A = start.reverseY();\n    const B = end.reverseY();\n    if (A.x === B.x && A.y === B.y) return Direct.coincide;\n    if (A.x === B.x) return B.y > A.y ? Direct.up : Direct.down;\n    if (A.y === B.y) return B.x > A.x ? Direct.right : Direct.left;\n    const deltaX = B.x - A.x;\n    const deltaY = B.y - A.y;\n    if (deltaX > 0 && deltaY > 0)\n      if (deltaX === deltaY) return Direct.upRight;\n      else if (deltaX < deltaY) return Direct.upRightA;\n      else return Direct.upRightB;\n    if (deltaX > 0 && deltaY < 0)\n      if (deltaX === -deltaY) return Direct.rightDown;\n      else if (deltaX > -deltaY) return Direct.rightDownA;\n      else return Direct.rightDownB;\n    if (deltaX < 0 && deltaY < 0)\n      if (-deltaX === -deltaY) return Direct.downLeft;\n      else if (-deltaX < -deltaY) return Direct.downLeftA;\n      else return Direct.downLeftB;\n    if (deltaX < 0 && deltaY > 0)\n      if (-deltaX === deltaY) return Direct.leftUp;\n      else if (-deltaX > deltaY) return Direct.leftUpA;\n      else return Direct.leftUpB;\n    debugger\n    throw Error(\"error happend when getting direction\");\n  }\n}\n"
  },
  {
    "path": "src/Entrance/App.scss",
    "content": "\nbody{\n    margin: 0;\n    touch-action: none;\n    overscroll-behavior: none;\n}\nhtml{\n    touch-action: none;\n    overscroll-behavior: none;\n}\n\n.App{\n    height: 100vh;\n    width: 100vw;\n    overflow: hidden;\n    user-select: none;\n}\n\n*{\n    font-family: 'PingFang SC';\n    -webkit-tap-highlight-color: transparent;\n}"
  },
  {
    "path": "src/Entrance/App.test.tsx",
    "content": "import { render, screen } from '@testing-library/react';\nimport App from './App';\nimport React from 'react';\nimport { Direct, Direction } from '../DataStructure/Direction';\nimport { Track } from '../DataStructure/Track';\nimport { Station } from '../DataStructure/Station';\nimport { Point } from '../DataStructure/Point';\nimport { EmptyLine, Line } from '../DataStructure/Line';\nimport { Vector } from '../DataStructure/Vector';\n\ntest('renders learn react link', () => {\n  render(<App />);\n  const linkElement = screen;\n  const direction = new Direction(Direct.up);\n  const station = new Station(new Point(1,2));\n  const track = new Track(station,new Direction(Direct.up));\n  const A = new Point(1,2);\n  const B = new Point(3,4);\n  const vector = new Vector(A,B);\n  console.log(station.getTrack(vector).direction.direct) \n  console.log(direction)\n\n  expect(linkElement).toBeDefined();\n});\n\n\ntest('vector cross pointer',()=>{\n  const a = new Vector(new Point(0,0), new Point(1,1));\n  const b = new Vector(new Point(0,5), new Point(5,0));\n  const abCrossPoint = a.getCrossPointTo(b);\n  console.log(abCrossPoint);\n  expect(abCrossPoint.x).toEqual(2.5);\n  expect(abCrossPoint.y).toEqual(2.5);\n\n})"
  },
  {
    "path": "src/Entrance/App.tsx",
    "content": "import '../i18n/config';\nimport { ErrorBoundary } from \"react-error-boundary\";\nimport {\n  browserInfo,\n  mapToArr,\n  mediateMap,\n  readFileFromIndexedDB,\n  setLocalStorage,\n} from \"../Common/util\";\nimport {\n  CardShowing,\n  ChangeSteps,\n  InsertInfo,\n  LineChanges,\n  LineProps,\n  RecordType,\n  StationProps,\n  UserDataType,\n  initData,\n  setDataFromJson,\n} from \"../Data/UserData\";\nimport { FunctionMode, Mode } from \"../DataStructure/Mode\";\nimport { Cards } from \"../Render/Card/Cards\";\nimport {\n  DeleteConfirmation,\n  showConfirmationInterface,\n} from \"../Render/Delete/DeleteConfirmation\";\nimport { Menu } from \"../Render/Header/Menu\";\nimport ScaleLayer from \"../Render/Layer/ScaleLayer\";\nimport { WelcomeTour } from \"../WelcomeTour/WelcomeTour\";\nimport \"./App.scss\";\nimport \"driver.js/dist/driver.css\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { ErrorFallback } from \"../Render/ErrorFallback/ErrorFallback\";\nimport { Recovery } from \"../Render/Recovery/Recovery\";\nfunction App() {\n  const [editingMode, setEditingMode] = useState(Mode.normal);\n  const [functionMode, setFunctionMode] = useState(FunctionMode.normal);\n  const [record, setRecord] = useState<RecordType>([]);\n  const [currentRecordIndex, setCurrentRecordIndex] = useState(-1);\n  const [insertInfo, setInsertInfo] = useState<InsertInfo>();\n  const [data, setDataOriginal] = useState(initData);\n  const [showName, setShowName] = useState(true);\n  const [autoHiddenName, setAutoHiddenName] = useState(true);\n  const [drawing, setDrawing] = useState(false);\n  const [translateX, setTranslateX] = useState(0);\n  const [translateY, setTranslateY] = useState(0);\n  const [page, setPage] = useState(\"title\");\n  const [scale, setScale] = useState(1);\n  const ref = useRef<any>();\n  const menuRef = useRef();\n  const [saved, setSaved] = useState(true);\n  const [defaultShape, setDefaultShape] = useState('cicle');\n  const [showTour, setShowTour] = useState(() => {\n    return (\n      window.innerWidth >= 710 && !localStorage.getItem(\"skip-tour-viewed\")\n    );\n  });\n  const [recoveredFromError, setRecoveredFromError] = useState(false);\n  const [showConfirmation, setShowConfirmation] =\n    useState<showConfirmationInterface>();\n  // keep latest data if crash happend\n  const setData = (data: React.SetStateAction<UserDataType>) => {\n    if (typeof data === \"function\") {\n      setDataOriginal((state) => {\n        const newState = data(state);\n        setLocalStorage(newState, () => setSaved(false));\n        return newState;\n      });\n    } else {\n      setLocalStorage(data, () => setSaved(false));\n      setDataOriginal(data);\n    }\n  };\n  useEffect(() => {\n    setShowConfirmation(() => ref.current?.showConfirmation);\n  }, [ref.current?.showConfirmation]);\n  const [cardShowing, setCardShowing] = useState(new CardShowing());\n  const transfromTools = {\n    scale,\n    setScale,\n    translateX,\n    translateY,\n    setTranslateX,\n    setTranslateY,\n  };\n  const {backgroundColor} = data;\n  useEffect(() => {\n    document.getElementById('theme-color')!.setAttribute('content', backgroundColor?backgroundColor:\"#ffffff\");\n  }, [backgroundColor])\n  return (\n    <ErrorBoundary\n      FallbackComponent={ErrorFallback}\n      onReset={() => {\n        const last = localStorage.getItem(\"last\");\n        if (last) {\n          const data = setDataFromJson(setData, last);\n          readFileFromIndexedDB(\"image\")\n            .then((file) => {\n              setData((data) => ({\n                ...data,\n                // backgroundColor: \"image\",\n                backgroundImage: file as File,\n              }));\n            })\n            .catch((e) => {\n              console.error(e);\n            });\n          mediateMap(data, transfromTools);\n        }\n        setRecoveredFromError(true);\n      }}\n    >\n      <div className=\"App\">\n        <Menu\n          setEditingMode={setEditingMode}\n          functionMode={functionMode}\n          setFunctionMode={setFunctionMode}\n          record={record}\n          setRecord={setRecord}\n          currentRecordIndex={currentRecordIndex}\n          setCurrentRecordIndex={setCurrentRecordIndex}\n          data={data}\n          setData={setData}\n          ref={menuRef}\n          insertInfo={insertInfo}\n          setInsertInfo={setInsertInfo}\n          showName={showName}\n          setShowName={setShowName}\n          autoHiddenName={autoHiddenName}\n          setAutoHiddenName={setAutoHiddenName}\n          drawing={drawing}\n          setDrawing={setDrawing}\n          cardShowing={cardShowing}\n          setCardShowing={setCardShowing}\n          translateX={translateX}\n          translateY={translateY}\n          scale={scale}\n          setTranslateX={setTranslateX}\n          setTranslateY={setTranslateY}\n          setScale={setScale}\n          saved={saved}\n          setSaved={setSaved}\n          showTour={showTour}\n          setShowTour={setShowTour}\n          page={page}\n          setPage={setPage}\n          defaultShape={defaultShape}\n          setDefaultShape={setDefaultShape}\n        />\n        <DeleteConfirmation ref={ref} />\n        <ScaleLayer\n          editingMode={editingMode}\n          setEditingMode={setEditingMode}\n          data={data}\n          setData={setData}\n          functionMode={functionMode}\n          setFunctionMode={setFunctionMode}\n          record={record}\n          setRecord={setRecord}\n          currentRecordIndex={currentRecordIndex}\n          setCurrentRecordIndex={setCurrentRecordIndex}\n          insertInfo={insertInfo}\n          setInsertInfo={setInsertInfo}\n          cardShowing={cardShowing}\n          setCardShowing={setCardShowing}\n          showName={showName}\n          setShowName={setShowName}\n          autoHiddenName={autoHiddenName}\n          setAutoHiddenName={setAutoHiddenName}\n          drawing={drawing}\n          setDrawing={setDrawing}\n          translateX={translateX}\n          translateY={translateY}\n          scale={scale}\n          setTranslateX={setTranslateX}\n          setTranslateY={setTranslateY}\n          setScale={setScale}\n          page={page}\n          setPage={setPage}\n          defaultShape={defaultShape}\n        />\n        <Cards\n          functionMode={functionMode}\n          setFunctionMode={setFunctionMode}\n          data={data}\n          setData={setData}\n          showConfirmation={showConfirmation}\n          menuRef={menuRef}\n          insertInfo={insertInfo}\n          setInsertInfo={setInsertInfo}\n          cardShowing={cardShowing}\n          setCardShowing={setCardShowing}\n        />\n        <WelcomeTour showTour={showTour} setShowTour={setShowTour} />\n        <Recovery\n          data={data}\n          setData={setData}\n          recoveredFromError={recoveredFromError}\n          setRecoveredFromError={setRecoveredFromError}\n          transfromTools={transfromTools}\n        />\n      </div>\n    </ErrorBoundary>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "src/Entrance/reportWebVitals.js",
    "content": "const reportWebVitals = onPerfEntry => {\n  if (onPerfEntry && onPerfEntry instanceof Function) {\n    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n      getCLS(onPerfEntry);\n      getFID(onPerfEntry);\n      getFCP(onPerfEntry);\n      getLCP(onPerfEntry);\n      getTTFB(onPerfEntry);\n    });\n  }\n};\n\nexport default reportWebVitals;\n"
  },
  {
    "path": "src/Entrance/setupTests.js",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom';\n"
  },
  {
    "path": "src/Grid/Scale.ts",
    "content": "import { CardShowing, ChangeSteps, RecordType, StationProps, UserDataType, addNewStation } from \"./../Data/UserData\";\nimport {\n  WheelEvent,\n  Dispatch,\n  SetStateAction,\n  MouseEvent,\n  TouchEvent,\n} from \"react\";\nimport { FunctionMode, Mode } from \"../DataStructure/Mode\";\nimport { Point } from \"../DataStructure/Point\";\nimport React from \"react\";\n\nconst sensitivity = -0.0006;\n\nconst scaleByPointer = (\n  scaleRatio: number,\n  translateX: number,\n  translateY: number,\n  refPoint: Point\n) =>\n  new Point(\n    refPoint.x - scaleRatio * (refPoint.x - translateX),\n    refPoint.y - scaleRatio * (refPoint.y - translateY)\n  );\n\nexport const onWheel = (\n  event: WheelEvent<HTMLDivElement>,\n  preScale: number,\n  setScale: Dispatch<SetStateAction<number>>,\n  translateX: number,\n  translateY: number,\n  setTranslateX: Dispatch<SetStateAction<number>>,\n  setTranslateY: Dispatch<SetStateAction<number>>,\n  functionMode: FunctionMode,\n) => {\n  const { deltaY, clientX, clientY } = event;\n\n  const nextScale = deltaY * sensitivity + preScale;\n  const scaleRatio = nextScale / preScale;\n  const refPoint = new Point(clientX, clientY);\n  if (nextScale > 0.1 || (functionMode ===FunctionMode.editingCustomBackgroundPosition && nextScale > 0)) {\n    const transform = scaleByPointer(\n      scaleRatio,\n      translateX,\n      translateY,\n      refPoint\n    );\n    setTranslateX(transform.x);\n    setTranslateY(transform.y);\n    setScale(nextScale);\n  }\n};\n\nexport const onMouseDown = (\n  event: MouseEvent<HTMLDivElement>,\n  translateX: number,\n  translateY: number,\n  setEditingMode: Dispatch<SetStateAction<Mode>>,\n  setMouseRefPoint: Dispatch<SetStateAction<Point>>,\n  setMouseStartTranslate: Dispatch<React.SetStateAction<Point>>,\n  setMoved: Dispatch<SetStateAction<boolean>>\n) => {\n  const point = Point.getPointFromMouse(event);\n  setMouseRefPoint(point);\n  setEditingMode(Mode.moving);\n  setMouseStartTranslate(new Point(translateX, translateY));\n  setMoved(false);\n};\n\nexport const onMouseMove = (\n  event: MouseEvent<HTMLDivElement>,\n  translateX: number,\n  translateY: number,\n  setTranslateX: Dispatch<SetStateAction<number>>,\n  setTranslateY: Dispatch<SetStateAction<number>>,\n  editingMode: Mode,\n  mouseRefPoint: Point,\n  mouseStartTranslate: Point,\n  setMoved: Dispatch<SetStateAction<boolean>>\n) => {\n  // setMoved(true);\n  switch (editingMode) {\n    case Mode.moving: {\n      // console.log(event);\n      const point = Point.getPointFromMouse(event);\n      const displacement = point.displacementTo(mouseRefPoint);\n      const distance = point.distanceTo(mouseRefPoint);\n      if(distance>5) setMoved(true);  \n      setTranslateX(mouseStartTranslate.x + displacement.x);\n      setTranslateY(mouseStartTranslate.y + displacement.y);\n      break;\n    }\n  }\n};\n\nexport const onMouseUp = (\n  event: MouseEvent<HTMLDivElement>,\n  setEditingMode: Dispatch<SetStateAction<Mode>>,\n  editingMode: Mode,\n  functionMode: FunctionMode,\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  moved: boolean,\n  translateX: number,\n  translateY: number,\n  scale: number,\n  record: RecordType,\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>,\n  currentRecordIndex: number,\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>,\n  cardShowing: CardShowing,\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>,\n  defaultShape: string,\n) => {\n  // console.log(event);\n  setEditingMode(Mode.normal);\n  if (functionMode === FunctionMode.addingStation && !moved) {\n    console.log({ translateX, translateY, scale });\n    const { clientX, clientY } = event;\n    const x = (clientX - translateX) / scale;\n    const y = (clientY - translateY) / scale;\n    addNewStation(\n      data,\n      setData,\n      x,\n      y,\n      record as StationProps[],\n      setRecord,\n      currentRecordIndex,\n      setCurrentRecordIndex,\n      cardShowing,\n      setCardShowing,\n      defaultShape,\n    );\n  }\n  const {currentTarget, target} = event;\n  if(currentTarget === target && !moved){\n    setCardShowing({});\n  }\n};\n\nexport const onMouseLeave = (\n  event: MouseEvent<HTMLDivElement>,\n  setEditingMode: Dispatch<SetStateAction<Mode>>\n) => {\n  // console.log(event);\n  setEditingMode(Mode.normal);\n};\n\nexport const onTouchStart = (\n  event: TouchEvent<HTMLDivElement>,\n  setEditingMode: Dispatch<SetStateAction<Mode>>,\n  setTouchRefPoint: Dispatch<SetStateAction<Point>>,\n  setTouchStartDistance: Dispatch<SetStateAction<number>>,\n  setTouchStartScale: Dispatch<SetStateAction<number>>,\n  scale: number,\n  setTouchStartTranslate: Dispatch<SetStateAction<Point>>,\n  translateX: number,\n  translateY: number,\n  setMoved: Dispatch<SetStateAction<boolean>>\n) => {\n  event.preventDefault();\n  const { touches } = event;\n  // record touch start translate position\n  setTouchStartTranslate(new Point(translateX, translateY));\n  setMoved(false);\n\n  switch (touches.length) {\n    //one finger\n    case 1: {\n      const touch = touches[0];\n      setTouchRefPoint(Point.getPointFromTouch(touch));\n      setEditingMode(Mode.touchMoving);\n      break;\n    }\n    //two finger\n    case 2: {\n      const touchA = touches[0];\n      const touchB = touches[1];\n      const pointA = Point.getPointFromTouch(touchA);\n      const pointB = Point.getPointFromTouch(touchB);\n      setTouchRefPoint(Point.getMidPoint(pointA, pointB));\n      setEditingMode(Mode.touchScaling);\n      //start touch distance\n      const distance = pointA.distanceTo(pointB);\n      setTouchStartDistance(distance);\n      setTouchStartScale(scale);\n      break;\n    }\n  }\n};\n\nexport const onTouchMove = (\n  event: TouchEvent<HTMLDivElement>,\n  editingMode: Mode,\n  touchRefPoint: Point,\n  translateX: number,\n  translateY: number,\n  setTranslateX: Dispatch<SetStateAction<number>>,\n  setTranslateY: Dispatch<SetStateAction<number>>,\n  touchStartDistance: number,\n  touchStartScale: number,\n  setScale: Dispatch<SetStateAction<number>>,\n  touchStartTranslate: Point,\n  setMoved: Dispatch<SetStateAction<boolean>>\n) => {\n  event.preventDefault();\n  const { touches } = event;\n  setMoved(true);\n  // console.log(event, touches.length, editingMode);\n  switch (touches.length) {\n    //one finger\n    case 1: {\n      if (editingMode === Mode.touchMoving) {\n        const touch = touches[0];\n        const point = Point.getPointFromTouch(touch);\n        // console.log(touchRefPoint);\n        const displacement = point.displacementTo(touchRefPoint);\n        setTranslateX(displacement.x + touchStartTranslate.x);\n        setTranslateY(displacement.y + touchStartTranslate.y);\n      }\n      break;\n    }\n    //two finger\n    case 2: {\n      if (editingMode === Mode.touchScaling) {\n        const touchA = touches[0];\n        const touchB = touches[1];\n        const pointA = Point.getPointFromTouch(touchA);\n        const pointB = Point.getPointFromTouch(touchB);\n\n        // for scale\n        const distance = pointA.distanceTo(pointB);\n        const nextScale = (touchStartScale * distance) / touchStartDistance;\n        setScale(nextScale);\n\n        // for translate\n        const midPoint = Point.getMidPoint(pointA, pointB);\n        const scaleRatio = nextScale / touchStartScale;\n        const transform = scaleByPointer(\n          scaleRatio,\n          touchStartTranslate.x,\n          touchStartTranslate.y,\n          touchRefPoint\n        );\n        //displacement between preMidPoint and midPoint\n        const displacement = midPoint.displacementTo(touchRefPoint);\n        setTranslateX(displacement.x + transform.x);\n        setTranslateY(displacement.y + transform.y);\n      }\n      break;\n    }\n  }\n};\n\nexport const onTouchEnd = (\n  event: TouchEvent<HTMLDivElement>,\n  setEditingMode: Dispatch<SetStateAction<Mode>>,\n  editingMode: Mode,\n  functionMode: FunctionMode,\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  moved: boolean,\n  translateX: number,\n  translateY: number,\n  scale: number,\n  record: RecordType,\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>,\n  currentRecordIndex: number,\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>,\n  cardShowing: CardShowing,\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>,\n  defaultShape: string,\n) => {\n  event.preventDefault();\n  const { changedTouches } = event;\n  // console.log(event,editingMode);\n  if (\n    functionMode === FunctionMode.addingStation &&\n    !moved &&\n    changedTouches.length === 1\n  ) {\n    const touch = changedTouches[0];\n    console.log({ touch, translateX, translateY, scale });\n    const { clientX, clientY } = touch;\n    const x = (clientX - translateX) / scale;\n    const y = (clientY - translateY) / scale;\n    addNewStation(\n      data,\n      setData,\n      x,\n      y,\n      record as StationProps[],\n      setRecord,\n      currentRecordIndex,\n      setCurrentRecordIndex,\n      cardShowing,\n      setCardShowing,\n      defaultShape,\n    );\n  }\n  const {currentTarget, target} = event;\n  if(currentTarget === target && !moved){\n    setCardShowing({});\n  }\n  setEditingMode(Mode.normal);\n};\n"
  },
  {
    "path": "src/Line/Handle.ts",
    "content": "import { Station } from \"./../DataStructure/Station\";\nimport {\n  Direct,\n  Direction,\n  DirectionVictorReverseY,\n} from \"../DataStructure/Direction\";\nimport { Line } from \"../DataStructure/Line\";\nimport { LineRecord } from \"../DataStructure/LineRecord\";\nimport { Point } from \"../DataStructure/Point\";\nimport { Vector } from \"../DataStructure/Vector\";\nimport { handleLength, handleWidth } from \"../Common/const\";\n\nconst getLPLPoints = (allKeyPoints: Point[]) => {\n  const LQLPoints = allKeyPoints.slice();\n  // LQLPoints.pop();\n  // LQLPoints.shift();\n  return LQLPoints;\n};\n\nconst checkIfStraightTrackHasHanderOrLine = (\n  direction: Direction,\n  station: Station\n) => {\n  const { direct } = direction.opposite();\n  return station.handlers[direct] || !station.tracks[direct].isEmpty();\n};\nconst checkifHandeCanGoStraight = (\n  outDirection: Direction,\n  station: Station\n) => {\n  const ifStraightTrackHasHander = !checkIfStraightTrackHasHanderOrLine(\n    outDirection,\n    station\n  );\n  return ifStraightTrackHasHander;\n};\nconst getDepartureGoStraightHandeCommand = (A: Point, B: Point) => {\n  const BA = new Vector(B, A);\n  const C = BA.prolong(handleLength);\n  const BC = new Vector(B, C);\n  const [D, E] = BC.verticalProlong(handleWidth);\n  return `M ${D.x} ${D.y} L ${E.x} ${E.y} M ${C.x} ${C.y}`;\n};\nconst addHandleForStation = (station: Station, line: Line, direct: Direct) => {\n  station.handlers[direct] = line;\n};\nconst getBestDirectionForHandle = (station: Station, direction: Direction) => {\n  let min = Infinity,\n    bestChoice = 0;\n  for (let i = 0; i < station.handlers.length; i++) {\n    const notEmpty = station.handlers[i] || !station.tracks[i].isEmpty();\n    if (!notEmpty) {\n      const delta = direction.opposite().delta(i);\n      if (delta < min) {\n        bestChoice = i;\n        min = delta;\n      }\n    }\n  }\n  return bestChoice;\n};\nconst getDepartureBestChoiceHandeCommand = (\n  A: Point,\n  B: Point,\n  pathStartPoint: Point\n) => {\n  const F = pathStartPoint;\n  const AB = new Vector(A, B);\n  const C = AB.prolong(handleLength - 1);\n  const BC = new Vector(B, C);\n  const [D, E] = BC.verticalProlong(handleWidth);\n  return `M ${D.x} ${D.y} L ${E.x} ${E.y} M ${C.x} ${C.y} L ${A.x} ${A.y} L ${F.x} ${F.y}`;\n};\nconst getBestChoiceHandleCommand = (\n  station: Station,\n  direction: Direction,\n  pathStartPoint: Point,\n  line: Line\n) => {\n  const handleDirect = getBestDirectionForHandle(station, direction);\n  if (handleDirect === undefined) {\n    return ` M  ${pathStartPoint.x} ${pathStartPoint.y}`;\n  } else {\n    const A = station.position;\n    const [x, y] = DirectionVictorReverseY[handleDirect];\n    const B = new Point(A.x + x, A.y + y);\n    addHandleForStation(station, line!, handleDirect);\n    return getDepartureBestChoiceHandeCommand(A, B, pathStartPoint);\n  }\n};\nconst getStartHandleCommand = (\n  A: Point,\n  B: Point,\n  departureRecord: LineRecord\n) => {\n  let command = \"\";\n  const outDirection = departureRecord?.getOutDirection();\n  const { station, line } = departureRecord;\n  const ifHandeCanGoStraight = checkifHandeCanGoStraight(\n    outDirection!,\n    station\n  );\n  if (ifHandeCanGoStraight) {\n    command = getDepartureGoStraightHandeCommand(A, B);\n    addHandleForStation(station, line!, outDirection!.opposite().direct);\n  } else {\n    command = getBestChoiceHandleCommand(station, outDirection!, A, line!);\n  }\n  return command;\n};\n\nconst getTerminalGoStraightHandeCommand = (C: Point, D: Point) => {\n  const CD = new Vector(C, D);\n  const E = CD.prolong(handleLength);\n  const CE = new Vector(C, E);\n  const [F, G] = CE.verticalProlong(handleWidth);\n  return ` L ${E.x} ${E.y} M ${F.x} ${F.y} L ${G.x} ${G.y}`;\n};\n\nconst getTerminalBestChoiceHandeCommand = (\n  A: Point,\n  B: Point,\n  pathEndPoint: Point\n) => {\n  const F = pathEndPoint;\n  const AB = new Vector(A, B);\n  const C = AB.prolong(handleLength - 1);\n  const BC = new Vector(B, C);\n  const [D, E] = BC.verticalProlong(handleWidth);\n  return `L ${F.x} ${F.y} L ${A.x} ${A.y} L ${C.x} ${C.y}   M ${D.x} ${D.y} L ${E.x} ${E.y} `;\n};\n\nconst getBestChoiceTerminalHandleCommand = (\n  station: Station,\n  direction: Direction,\n  pathStartPoint: Point,\n  line: Line\n) => {\n  const handleDirect = getBestDirectionForHandle(station, direction);\n  if (handleDirect === undefined) {\n    return ` L  ${pathStartPoint.x} ${pathStartPoint.y}`;\n  } else {\n    const A = station.position;\n    const [x, y] = DirectionVictorReverseY[handleDirect];\n    const B = new Point(A.x + x, A.y + y);\n    addHandleForStation(station, line!, handleDirect);\n    return getTerminalBestChoiceHandeCommand(A, B, pathStartPoint);\n  }\n};\n\nconst getEndHandleCommand = (\n  C: Point,\n  D: Point,\n  terminalRecord: LineRecord\n) => {\n  let command = \"\";\n  const inDirection = terminalRecord?.getInDirection();\n  const { station, line } = terminalRecord;\n  const ifHandeCanGoStraight = checkifHandeCanGoStraight(inDirection!, station);\n  if (ifHandeCanGoStraight) {\n    command = getTerminalGoStraightHandeCommand(C, D);\n    addHandleForStation(station, line!, inDirection!.opposite().direct);\n  } else {\n    command = getBestChoiceTerminalHandleCommand(\n      station,\n      inDirection!,\n      D,\n      line!\n    );\n  }\n  return command;\n};\nconst getHandleCommand = (line: Line, allKeyPoints: Point[]) => {\n  const [A, B] = allKeyPoints;\n  const C = allKeyPoints[allKeyPoints.length - 2],\n    D = allKeyPoints[allKeyPoints.length - 1];\n  const { departureRecord, displayLine } = line;\n  const { subLine } = displayLine!;\n  const terminalRecord = line.getTerminalRecord();\n  let startHandleCommand = getStartHandleCommand(A, B, departureRecord!);\n  let endHandleCommand = ` L ${A.x} ${A.y}`; // loop line\n  if (!(departureRecord?.station === terminalRecord?.station)) {\n    endHandleCommand = getEndHandleCommand(C, D, terminalRecord!);\n  }\n  const LQLPoints = getLPLPoints(allKeyPoints);\n  // subline no need handler in joint\n  if (\n    subLine &&\n    departureRecord?.station?.lineCount &&\n    departureRecord?.station?.lineCount() >= 2\n  ) {\n    startHandleCommand = ` M ${A.x} ${A.y} `;\n  }\n  if (\n    subLine &&\n    terminalRecord?.station?.lineCount &&\n    terminalRecord?.station?.lineCount() >= 2\n  ) {\n    endHandleCommand = \"\";\n  }\n  return { startHandleCommand, LQLPoints, endHandleCommand };\n};\nconst clearHandleFromRecord = (lineRecord: LineRecord | undefined) => {\n  if (lineRecord) {\n    const { station, line } = lineRecord;\n    station.handlers.forEach((handle, index) => {\n      if (handle === line) {\n        station.handlers[index] = null;\n      }\n    });\n  } else {\n    console.error(\"no linerecord to clear handle\");\n  }\n};\nconst clearHandle = (line: Line) => {\n  const { departureRecord } = line;\n  const terminalRecord = line.getTerminalRecord();\n  clearHandleFromRecord(departureRecord);\n  clearHandleFromRecord(terminalRecord);\n};\n\nexport { getHandleCommand, clearHandle };\n"
  },
  {
    "path": "src/Line/LinePoints.ts",
    "content": "import { gauge, line_radius } from \"../Common/const\";\nimport { Direction } from \"../DataStructure/Direction\";\nimport { Line } from \"../DataStructure/Line\";\nimport { LineRecord } from \"../DataStructure/LineRecord\";\nimport { Point } from \"../DataStructure/Point\";\nimport { Rail } from \"../DataStructure/Rail\";\nimport { Vector } from \"../DataStructure/Vector\";\n\nconst getTurningPoint = (\n  A: Point,\n  B: Point,\n  aDirection: Direction,\n  bDirection: Direction\n) => {\n  const aVector = Vector.getVectorByPointAndDirection(A, aDirection);\n  const bVector = Vector.getVectorByPointAndDirection(B, bDirection);\n  const crossPoint = aVector.getCrossPointTo(bVector);\n  return crossPoint;\n};\nconst getOffsetPointFromDirectionAndRail = (\n  point: Point,\n  direction: Direction,\n  rail: Rail\n) => {\n  // if(rail.track.station.displayStation!.stationName==='风起地站' && rail.line.displayLine?.lineName==='2号线')\n  // debugger \n  const s = Math.SQRT1_2;\n\n  // lean\n  const directionOffset = [\n    [[-1,0],[0,0],[1,0]],// 0 up\n    [[-s,-s],[0,0],[s,s]],// 1 upRight\n    [[0,-1],[0,0],[0,1]],// 2 right\n    [[s,-s],[0,0],[-s,s]],// 3 rightDown\n    [[1,0],[0,0],[-1,0]],// 4 down\n    [[s,s],[0,0],[-s,-s]],// 5 downLeft\n    [[0,1],[0,0],[0,-1]],// 6 left\n    [[-s,s],[0,0],[s,-s]],// 7 leftUp\n  ];\n\n  // const directionOffset = [\n  //   [0, -1],\n  //   [SQRT1_2, -SQRT1_2],\n  //   [1, 0],\n  //   [SQRT1_2, SQRT1_2],\n  //   [0, 1],\n  //   [-SQRT1_2, SQRT1_2],\n  //   [-1, 0],\n  //   [-SQRT1_2, -SQRT1_2],\n  // ];\n  // const offsetIndex = (direction.direct + rail.index - 1 + 8) % 8;\n  const offset = directionOffset[direction.direct];\n  const [offsetX, offsetY] = offset[rail.index].map((x) => x * gauge);\n  return new Point(offsetX + point.x, offsetY + point.y);\n};\nconst getStartOffsetPointOfStation = (lineRecord: LineRecord) => {\n  const { station, nextRail } = lineRecord;\n  return getOffsetPointFromDirectionAndRail(\n    station.position,\n    nextRail!.track.direction,\n    nextRail!\n  );\n};\nconst getEndOffsetPointOfStation = (lineRecord: LineRecord) => {\n  const { station, lastRail } = lineRecord;\n  return getOffsetPointFromDirectionAndRail(\n    station.position,\n    lastRail!.track.direction,\n    lastRail!\n  );\n};\nconst getInOffsetPointOfStation = (lineRecord: LineRecord) => {\n  const { station, lastRail } = lineRecord;\n  return getOffsetPointFromDirectionAndRail(\n    station.position,\n    lastRail!.track.direction,\n    lastRail!\n  );\n};\nconst getOutOffsetPointOfStation = (lineRecord: LineRecord) => {\n  const { station, nextRail } = lineRecord;\n  return getOffsetPointFromDirectionAndRail(\n    station.position,\n    nextRail!.track.direction,\n    nextRail!\n  );\n};\nconst getPointsBetweenStations = (lineRecord: LineRecord) => {\n  const { nextLineRecord } = lineRecord;\n  if (nextLineRecord) {\n    const AOffsetPoint = getStartOffsetPointOfStation(lineRecord);\n    const BOffsetPoint = getEndOffsetPointOfStation(nextLineRecord);\n    if (\n      lineRecord.getOutDirection()!.oppositeTo(nextLineRecord.getInDirection())\n    ) {\n      //direct to next station\n      return [AOffsetPoint, BOffsetPoint];\n    } else {\n      //has turning\n      const turningPoint = getTurningPoint(\n        AOffsetPoint,\n        BOffsetPoint,\n        lineRecord.getOutDirection()!,\n        nextLineRecord.getInDirection()!\n      );\n      return [AOffsetPoint, turningPoint, BOffsetPoint];\n    }\n  } else throw new Error(\"No NextLineRecord!\");\n  return [];\n};\nconst getPointsInStation = (lineRecord: LineRecord) => {\n  const { nextLineRecord, lastLineRecord } = lineRecord;\n  if (nextLineRecord && lastLineRecord) {\n    const AOffsetPoint = getInOffsetPointOfStation(lineRecord);\n    const BOffsetPoint = getOutOffsetPointOfStation(lineRecord);\n    const inDirection = lineRecord.getInDirection();\n    const outDirection = lineRecord.getOutDirection();\n    // same point in and out\n    if (\n      AOffsetPoint.sameTo(BOffsetPoint) ||\n      inDirection?.oppositeTo(outDirection)\n    )\n      return [];\n    else {\n      // same in same out, need two points\n      if (inDirection?.sameTo(outDirection!)) {\n        return []; // no need points cause last and next will add end and start points\n        // return [AOffsetPoint, BOffsetPoint];\n      }\n      const crossPointInStation = getTurningPoint(\n        AOffsetPoint,\n        BOffsetPoint,\n        inDirection!,\n        outDirection!\n      );\n      // if(crossPointInStation.x === Infinity) debugger\n      // not same point, but cross in inPoint or outPoint\n      if (\n        crossPointInStation.sameTo(AOffsetPoint) ||\n        crossPointInStation.sameTo(BOffsetPoint)\n      )\n        return [];\n      return [crossPointInStation];\n    }\n  } else return [];\n};\nconst isPointInStationInNextLine = ([A]: Point[], [B, C]: Point[]) => {\n  if (A) {\n    const BC = new Vector(B, C);\n    return BC.passesThroughPoint(A);\n  }\n  return false;\n};\n// keypoints record all points to draw line\nconst getAllKeyPoints = (line: Line) => {\n  let lineRecord = line.departureRecord;\n  let keyPoints: Point[] = [];\n  if (!lineRecord) {\n    console.error(\"No DepartureStation!\");\n    return [];\n  }\n  while (lineRecord.nextLineRecord) {\n    const pointsInStation = getPointsInStation(lineRecord);\n    // if(pointsInStation[0]&&(pointsInStation[0].x === 500 && pointsInStation[0].y === 600)) debugger;\n    keyPoints = keyPoints.concat(pointsInStation);\n    const pointsBetweenStations = getPointsBetweenStations(lineRecord);\n\n    // cross point in next line, delete next line start point\n    if (isPointInStationInNextLine(pointsInStation, pointsBetweenStations))\n      pointsBetweenStations.shift();\n    // next line start point is the same with this line's end,\n    // delete next line start point\n    if (\n      keyPoints.length &&\n      pointsBetweenStations[0].sameTo(keyPoints[keyPoints.length - 1])\n    )\n      pointsBetweenStations.shift();\n    keyPoints = keyPoints.concat(pointsBetweenStations);\n    lineRecord = lineRecord.nextLineRecord;\n    if (lineRecord === line.departureRecord) break;\n  }\n  // to-do why duplicate\n  return keyPoints.filter((p,index)=>index>0?!(p.x===keyPoints[index-1].x&&p.y===keyPoints[index-1].y):true);\n};\n\nconst deleteDuplicatedPoints = (keyPoints: Point[]) => {\n  if (keyPoints.length <= 2) return keyPoints; // no need delete duplicate point\n  const start = keyPoints[0],\n    end = keyPoints[keyPoints.length - 1];\n  const QKeyPoints: Point[] = [start];\n  for (let i = 1; i < keyPoints.length - 1; i++) {\n    const A = keyPoints[i - 1];\n    const B = keyPoints[i];\n    const C = keyPoints[i + 1];\n    const AC = new Vector(A, C);\n    const AB = new Vector(A, B);\n    const BC = new Vector(B, C);\n    if (!AC.passesThroughPointRound(B) //|| AB.direct !== BC.direct\n    )\n      QKeyPoints.push(B);\n  }\n  QKeyPoints.push(end);\n  return QKeyPoints;\n};\n\nconst addLPointsAroundQPoints = (qPoints: Point[]) => {\n  if (qPoints.length <= 2) return qPoints; // no need add L points\n  const start = qPoints[0],\n    end = qPoints[qPoints.length - 1];\n  const LQLKeyPoints: Point[] = [start];\n  for (let i = 1; i < qPoints.length - 1; i++) {\n    const A = qPoints[i - 1];\n    const B = qPoints[i];\n    const C = qPoints[i + 1];\n    const BA = new Vector(B, A);\n    const BC = new Vector(B, C);\n    const BAOffsetPoint = BA.normalize(line_radius).end.offset(B);\n    const BCOffsetPoint = BC.normalize(line_radius).end.offset(B);\n    BAOffsetPoint.q_start = true;\n    B.q = true;\n    BCOffsetPoint.q_end = true;\n    LQLKeyPoints.push(BAOffsetPoint);\n    LQLKeyPoints.push(B);\n    LQLKeyPoints.push(BCOffsetPoint);\n  }\n  LQLKeyPoints.push(end);\n  return LQLKeyPoints;\n};\nconst getRoundedPoints = (keyPoints: Point[]) => {\n  const QKeyPoints = deleteDuplicatedPoints(keyPoints);\n  const LQLPoints = addLPointsAroundQPoints(QKeyPoints);\n  return LQLPoints;\n};\nconst generateLineCommand = (LQLPoints: Point[]) => {\n  if (LQLPoints.length <= 1) {\n    console.error(\n      \"no enough point to draw line. now we have \" + LQLPoints.length\n    );\n    return \"\";\n  }\n  const start = LQLPoints[0],\n    end = LQLPoints[LQLPoints.length - 1];\n  const MCommand = ``;\n  const EndCommand = ` L ${end.x} ${end.y} `;\n  let path = \"\";\n  for (let i = 1; i < LQLPoints.length - 1; i++) {\n    const P = LQLPoints[i];\n    switch (true) {\n      case P.q_start:\n        path += ` L ${P.x} ${P.y} `;\n        break;\n      case P.q:\n        path += ` Q ${P.x} ${P.y} `;\n        break;\n      case P.q_end:\n        path += ` , ${P.x} ${P.y} `;\n        break;\n      default:\n        throw new Error(\"no Point flag for command!\");\n    }\n  }\n  return MCommand + path + EndCommand;\n};\n\nexport { getAllKeyPoints, getRoundedPoints, generateLineCommand };\n"
  },
  {
    "path": "src/Render/Card/Cards.scss",
    "content": ".cards {\n    position: fixed;\n    bottom: 0;\n    // left: -65px;\n    // zoom: 0.85\n    width: fit-content;\n    max-width: 100vw;\n    height: 500px;\n    overflow-x: scroll;\n    overflow-y: visible;\n    white-space: nowrap;\n    padding-top: 200px;\n    // padding-right: 100px;\n    box-sizing: border-box;\n    pointer-events: none;\n    &::-webkit-scrollbar {\n        display: none;\n        // width: 0.01px;\n    }\n    .card-container {\n        display: inline-block;\n        pointer-events: auto;\n\n        & > div {\n            margin-left: 50px;\n            position: relative;\n            box-shadow: 0 4px 159px 7px rgba(0, 0, 0, 0.25);\n            // filter: drop-shadow(0 0 2px #999);\n        }\n        &:last-child {\n            margin-right: 50px;\n        }\n    }\n\n    // @media (max-width: 555px) {\n    //     height: 285px;\n    //     &>div{\n    //     margin-left: 50px;\n    // // box-shadow: none;\n    // // border: 1px solid rgba(0, 0, 0, 0.266);\n\n    //     &:last-child{\n    //         margin-right: 50px;\n    //     }\n    //     zoom: 0.7;\n    // }\n    // }\n}\n"
  },
  {
    "path": "src/Render/Card/Cards.tsx",
    "content": "import React, {\n  CSSProperties,\n  Dispatch,\n  RefObject,\n  SetStateAction,\n  useEffect,\n  useLayoutEffect,\n  useRef,\n  useState,\n} from \"react\";\nimport { Line } from \"../../DataStructure/Line\";\nimport { Station } from \"../../DataStructure/Station\";\nimport { DisplayStation } from \"../../DataStructure/Display\";\nimport { LineCard } from \"./LineCard\";\nimport \"./Cards.scss\";\nimport { StationCard } from \"./StationCard\";\nimport { CardShowing, InsertInfo, UserDataType } from \"../../Data/UserData\";\nimport { browserInfo, mapToArr, onWheelX, onWheelY } from \"../../Common/util\";\nimport { showConfirmationInterface } from \"../Delete/DeleteConfirmation\";\nimport { FunctionMode } from \"../../DataStructure/Mode\";\n\nexport function Cards({\n  data,\n  setData,\n  showConfirmation,\n  menuRef,\n  functionMode,\n  setFunctionMode,\n  insertInfo,\n  setInsertInfo,\n  cardShowing,\n  setCardShowing,\n}: {\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  showConfirmation?: showConfirmationInterface;\n  menuRef: RefObject<any>;\n  functionMode: FunctionMode;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n}) {\n  const { lines, stations } = data;\n  const { engine } = browserInfo;\n  const [pointerEvents, setPointerEvents] = useState<\"auto\" | \"none\">(\"none\");\n  const { lineIds, stationIds, stationFirst } = cardShowing;\n  const linesComp = lineIds?.map((lineId) => {\n    const line = lines.get(lineId);\n    if (line)\n      return (\n        <div className=\"card-container\">\n          <LineCard\n            setData={setData}\n            line={line}\n            data={data}\n            key={\"line-card-\" + line.lineId}\n            showConfirmation={showConfirmation}\n            functionMode={functionMode}\n            setFunctionMode={setFunctionMode}\n            insertInfo={insertInfo}\n            setInsertInfo={setInsertInfo}\n            menuRef={menuRef}\n            cardShowing={cardShowing}\n            setCardShowing={setCardShowing}\n          />\n        </div>\n      );\n  });\n  const stationComp = stationIds?.map((stationId) => {\n    const station = stations.get(stationId);\n    if (station)\n      return (\n        <div className=\"card-container\">\n          <StationCard\n            setData={setData}\n            station={station}\n            data={data}\n            key={\"station-card-\" + station.stationId}\n            showConfirmation={showConfirmation}\n            menuRef={menuRef}\n            functionMode={functionMode}\n            setFunctionMode={setFunctionMode}\n            insertInfo={insertInfo}\n            setInsertInfo={setInsertInfo}\n            cardShowing={cardShowing}\n            setCardShowing={setCardShowing}\n          />\n        </div>\n      );\n  });\n  const [style, setStyle] = useState<CSSProperties>();\n  const handleStyle = () => {\n    const style: CSSProperties =\n      engine.name === \"WebKit\"\n        ? { pointerEvents: \"auto\", height: 370, paddingTop: 70 }\n        : {};\n    if (\n      ((stationIds?.length || 0) + (lineIds?.length || 0)) * 555  <\n      window.innerWidth\n    ) {\n      style.paddingRight = 100;\n      style.pointerEvents = \"none\";\n    }\n    setStyle(style);\n  };\n\n  useEffect(() => {\n    handleStyle();\n    window.addEventListener(\"resize\", handleStyle);\n    return () => window.removeEventListener(\"resize\", handleStyle);\n  }, [cardShowing]);\n  return (\n    <div\n      className=\"cards\"\n      onWheel={onWheelX}\n      style={style}\n      // style={{pointerEvents}}\n      onTouchStart={(e) => {\n        const { target, currentTarget } = e;\n        if (target === currentTarget) setPointerEvents(\"none\");\n        else setPointerEvents(\"auto\");\n      }}\n    >\n      {stationFirst ? stationComp : linesComp}\n      {stationFirst ? linesComp : stationComp}\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/Render/Card/LineCard.scss",
    "content": ".line-card {\n    width: 455px;\n    height: 250px;\n    border-radius: 23px;\n    display: inline-block;\n    // margin-left: 50px;\n    // margin-bottom: 50px;\n    // zoom: 0.8;\n    --margin-left: 33px;\n    background-color: rgba(255, 255, 255, 0.863);\n    backdrop-filter: blur(15px);\n    position: relative;\n    transition: 0.3s ease-in-out width;\n    overflow-x: hidden;\n    .tools {\n        position: absolute;\n        right: 0;\n        .tool-item {\n            vertical-align: top;\n            height: 34px;\n            width: 34px;\n            display: inline-flex;\n            justify-content: center;\n            align-items: center;\n            margin: 14.5px 11.3px 0 0;\n            background-color: #d9d9d9;\n            border-radius: 7.25px;\n            .expand-icon {\n                height: 15px;\n                width: 15px;\n            }\n            .edit-icon {\n                height: 17.74px;\n                width: 17.74px;\n            }\n        }\n    }\n    .stations-count {\n        font-size: 18px;\n        font-weight: 500;\n        cursor: pointer;\n        margin: 23px 0 0 var(--margin-left);\n        width: fit-content;\n    }\n    .line-name {\n        & > * {\n            font-size: 24px;\n            font-weight: 500;\n        }\n\n        margin: 2px 0 0 var(--margin-left);\n    }\n\n    .from-to {\n        font-size: 18px;\n        font-weight: 500;\n        margin: 5px 0 0 var(--margin-left);\n        color: #ababab;\n    }\n    .edit-detail {\n        .name-detail {\n            margin-top: 22.58px;\n            white-space: nowrap;\n            width: 254.2px;\n            overflow-y: visible;\n            overflow-x: scroll;\n            height: 100px;\n            &::-webkit-scrollbar {\n                display: none;\n                // width: 0.01px;\n            }\n            .name-item {\n                display: inline-block;\n                margin-right: 24.2px;\n                vertical-align: top;\n                &:first-child {\n                    margin-left: 32.25px;\n                }\n                .title {\n                    font-size: 11.25px;\n                    font-weight: 500;\n                    color: #ea0b2a;\n                }\n                input {\n                    margin-top: 21.77px;\n                    padding: 0;\n                }\n                .sign-input {\n                    // width: 35.5px;\n                    * {\n                        min-width: 35.5px;\n                        height: 35.5px;\n                        border: none;\n                        border-radius: 8.87px;\n                        background-color: #ea0b2a;\n                        font-size: 23.25px;\n                        color: white;\n                        text-align: center;\n                    }\n                }\n                .line-name-input,\n                .order-input {\n                    * {\n                        font-size: 36px;\n                        border: none;\n                        font-weight: 500;\n                        // width: 100px;\n                        margin-top: 14px;\n                    }\n                }\n                .order-input {\n                    // width: 30px;\n                    // white-space: nowrap;\n                    vertical-align: top;\n                }\n            }\n        }\n        .color-detail {\n            .color-detail-choosing {\n                box-sizing: border-box;\n                padding: 21px 32.25px;\n                width: 255px;\n                display: grid;\n                grid-template-columns: repeat(5, 20%);\n                grid-template-rows: repeat(2, 50%);\n                grid-row-gap: 9px;\n                grid-column-gap: 6px;\n                .color-preview {\n                    cursor: pointer;\n                    width: 19.5px;\n                    height: 19.5px;\n                    border-radius: 50%;\n                    border: 2px solid;\n                    display: flex;\n                    justify-content: center;\n                    align-items: center;\n                    .color-preview-inner {\n                        width: 16.9px;\n                        height: 16.9px;\n                        border-radius: 50%;\n                    }\n                }\n            }\n            .custom-color {\n                margin: 0 32.25px;\n                border-top: 1px dashed black;\n                width: 197px;\n                box-sizing: border-box;\n                padding-top: 15px;\n                // padding-left: 10px;\n                .selected-color-preview {\n                    .color-input {\n                        // width: 19.5px;\n                        // height: 19.5px;\n                        // border-radius: 50%;\n                        display: inline-block;\n                    }\n                    .color-value {\n                        display: inline-block;\n                        margin-left: 15px;\n                        font-size: 15.25px;\n                        font-weight: 500;\n                        width: 100px;\n                        text-decoration: underline;\n                        vertical-align: top;\n                        margin-top: 1px;\n                        border: none;\n                    }\n                }\n            }\n        }\n        .operation-detail {\n            .operation-item {\n                &:first-child {\n                    margin-top: 15px;\n                }\n                &:last-child {\n                    margin-bottom: 15px;\n                }\n                margin-left: 32.25px;\n                margin-top: 8px;\n                margin-bottom: 8px;\n                color: #2196f3;\n                font-size: 18px;\n                font-weight: 500;\n                cursor: pointer;\n                &.delete {\n                    color: #ea0b2a;\n                }\n            }\n        }\n    }\n    .station-bar {\n        margin: 30px 0 0 0;\n        white-space: nowrap;\n        width: 455px;\n        overflow-x: scroll;\n        overflow-y: hidden;\n        transition: 0.3s ease-in-out width;\n\n        &::-webkit-scrollbar {\n            display: none;\n            // width: 0.01px;\n        }\n        .add-first {\n            width: var(--margin-left);\n            display: inline-block;\n        }\n        .station-block {\n            display: inline-block;\n            width: 161px;\n            height: 78.22px;\n            border-left: 1px solid #cccccc;\n            position: relative;\n            vertical-align: top;\n            .track {\n                display: flex;\n                background-color: #f0f0f0;\n                width: 161px;\n                height: 48.3px;\n                .sleeper {\n                    border-left: 1px solid #cccccc;\n                    width: 53.6px;\n                    &:first-child {\n                        border: none;\n                    }\n                }\n            }\n            .bend-first {\n                position: absolute;\n                top: 7.215px;\n                left: 9.5px;\n                height: 33.87px;\n                width: 133.8px;\n                background-color: #d9d9d9;\n                border-radius: 4px;\n                display: flex;\n                align-items: center;\n                cursor: pointer;\n                transition: ease-in-out 0.3s background-color;\n                &.current-inserting {\n                    background-color: #c3c3c3;\n                }\n                .bend-icon {\n                    svg {\n                        width: 16px;\n                        height: 16px;\n                        transform-origin: center;\n                    }\n                    width: 16px;\n                    height: 16px;\n                    display: inline-block;\n                    margin: -1px 13px 0 18.5px;\n\n                    &.bend {\n                        svg {\n                            transform: rotate(-45deg);\n                        }\n                    }\n                }\n                .bend-des {\n                    display: inline-block;\n                    font-size: 14.25px;\n                    font-weight: 500;\n                    color: rgb(0, 0, 0, 0.5);\n                }\n            }\n            .station-name {\n                font-size: 18px;\n                font-weight: 500;\n                margin: 8px;\n                color: #ea0b2a;\n                cursor: pointer;\n            }\n        }\n    }\n    .edit-panel {\n        &.edit {\n            right: 0;\n        }\n        width: 200.8px;\n        background-color: #f2f2f2;\n        position: absolute;\n        right: -200.8px;\n        top: 0;\n        height: 250px;\n        transition: 0.3s ease-in-out right;\n        .edit-tools {\n            width: 200.8px;\n            height: 250px;\n            overflow-y: scroll;\n            overflow-x: hidden;\n            &::-webkit-scrollbar {\n                display: none;\n                // width: 0.01px;\n            }\n            .edit-tool {\n                &:first-child {\n                    margin: 21.7px 21.7px 2px 21.7px;\n                }\n                &:last-child {\n                    margin: 2px 21.7px 21.7px 21.7px;\n                }\n                cursor: pointer;\n                margin: 2px 21.7px 2px 21.7px;\n                width: 158px;\n                height: 75px;\n                border-radius: 11.3px;\n                font-weight: 500;\n                display: flow-root;\n                &.selected {\n                    background-color: #d9d9d9;\n                }\n                .title {\n                    font-size: 18px;\n                    margin: 12.1px 0 0 20.2px;\n                    text-transform: capitalize;\n                }\n                .value {\n                    font-size: 11.25px;\n                    margin: 4.83px 0 0 20.2px;\n                }\n                &.color > .value {\n                    color: #ea0b2a;\n                }\n            }\n        }\n\n        .done {\n            background-color: #2196f3;\n            border-radius: 25px;\n            width: 74px;\n            height: 28.2px;\n            position: absolute;\n            bottom: 23.4px;\n            right: 23.4px;\n            display: flex;\n            align-items: center;\n            .done-icon {\n                height: 17.74px;\n                width: 17.74px;\n                margin: 0 6.5px 0 11.3px;\n                path {\n                    fill: #ffffff;\n                    fill-opacity: 1;\n                }\n            }\n            .done-des {\n                font-size: 12px;\n                font-weight: 500;\n                color: white;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Card/LineCard.tsx",
    "content": "import React, {\n  Dispatch,\n  RefObject,\n  SetStateAction,\n  useEffect,\n  useState,\n  useTransition,\n} from \"react\";\nimport { Line } from \"../../DataStructure/Line\";\nimport { Station } from \"../../DataStructure/Station\";\nimport { DisplayStation } from \"../../DataStructure/Display\";\nimport \"./LineCard.scss\";\nimport ArrowIcon from \"../../Resource/Icon/arrow\";\nimport PlusIcon from \"../../Resource/Icon/plus\";\n\nimport ExpandIcon from \"../../Resource/Icon/expand\";\nimport ShrinkIcon from \"../../Resource/Icon/shrink\";\nimport EditIcon from \"../../Resource/Icon/edit\";\n\nimport classNames from \"classnames\";\nimport {\n  CardShowing,\n  InsertInfo,\n  LineProps,\n  StationProps,\n  UserDataType,\n  dataProcessor,\n} from \"../../Data/UserData\";\nimport {\n  browserInfo,\n  mapToArr,\n  onWheelX,\n  onWheelY,\n  scrollOptimize,\n} from \"../../Common/util\";\nimport { AutoGrowthInput } from \"../../Common/AutoGrowthInput\";\nimport { colorSH, colorSHMap } from \"../../Common/color\";\nimport { showConfirmationInterface } from \"../Delete/DeleteConfirmation\";\nimport { FunctionMode } from \"../../DataStructure/Mode\";\nimport { Point } from \"../../DataStructure/Point\";\nimport { useTranslation } from \"react-i18next\";\nimport i18n from \"../../i18n/config\";\nexport function LineCard({\n  line,\n  setData,\n  data,\n  showConfirmation,\n  functionMode,\n  setFunctionMode,\n  insertInfo,\n  setInsertInfo,\n  menuRef,\n  cardShowing,\n  setCardShowing,\n}: {\n  line: LineProps;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  data: UserDataType;\n  showConfirmation?: showConfirmationInterface;\n  functionMode: FunctionMode;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  menuRef: RefObject<any>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n}) {\n  const {\n    lineId,\n    lineName,\n    stationIds,\n    sign,\n    order,\n    color: colorSelected,\n    subLine = false,\n  } = line;\n  const {\n    getStationById,\n    getStationsInThisLine,\n    setLineName,\n    setSign,\n    setOrder,\n    setColor,\n    getBendFirst,\n    setBendFirst,\n    deleteLine,\n    setSubLine,\n  } = dataProcessor(lineId, setData, data);\n  const colorName = i18n.language === \"zh\" && colorSHMap.get(colorSelected)?.color_name || colorSelected;\n  const firstStation = getStationById(stationIds[0]);\n  const lastStation = getStationById(stationIds[stationIds.length - 1]);\n  // if (!firstStation) {\n  //   firstStation = new StationProps();\n  //   lastStation = firstStation;\n  // }\n  const [expand, setExpand] = useState(false);\n  const [edit, setEdit] = useState(false);\n  const [expandWidth, setExpandWidth] = useState(455);\n  const [tab, setTab] = useState(\"name\");\n  const addingStation =\n    functionMode === FunctionMode.selectingStation ||\n    functionMode === FunctionMode.lineEditing ||\n    !firstStation;\n  const getExpandWidth = () => {\n    const { stationIds: stations } = cardShowing;\n    const expected =\n      33 + 161 * (addingStation ? stationIds.length + 1 : stationIds.length);\n    const hasStation = stations && stations.length;\n\n    const width =\n      expected > window.innerWidth\n        ? window.innerWidth - (hasStation ? 505 : 100)\n        : expected;\n    // console.log(width);\n    setExpandWidth(width);\n  };\n  useEffect(() => {\n    getExpandWidth();\n    window.addEventListener(\"resize\", getExpandWidth);\n    return () => window.removeEventListener(\"resize\", getExpandWidth);\n  }, [stationIds, addingStation, cardShowing]);\n  useEffect(() => {\n    getExpandWidth();\n  }, [expand]);\n  const { t } = useTranslation();\n  const editTools = (tab: string) => {\n    switch (tab) {\n      case \"name\": {\n        return (\n          <div className=\"name-detail\" onWheel={onWheelX}>\n            <div className=\"name-item sign\">\n              <div className=\"title\" style={{ color: colorSelected }}>\n                {t('menu.symbol')}\n              </div>\n\n              <AutoGrowthInput\n                className=\"sign-input\"\n                value={sign}\n                onInput={(e) => setSign(e.currentTarget.value)}\n                style={{ backgroundColor: colorSelected }}\n              />\n            </div>\n            <div className=\"name-item line-name-item\">\n              <div className=\"title\" style={{ color: colorSelected }}>\n                {t('line.name')}\n              </div>\n              <AutoGrowthInput\n                onInput={(e) => setLineName(e.currentTarget.value)}\n                className=\"line-name-input\"\n                value={lineName}\n              />\n            </div>\n            <div className=\"name-item order\">\n              <div className=\"title\" style={{ color: colorSelected }}>\n                {t('line.order')}\n              </div>\n\n              <AutoGrowthInput\n                className=\"order-input\"\n                value={order}\n                type=\"number\"\n                onInput={(e) => setOrder(parseInt(e.currentTarget.value))}\n              />\n            </div>\n          </div>\n        );\n      }\n      case \"color\": {\n        return (\n          <div className=\"color-detail\">\n            <div className=\"color-detail-choosing\">\n              {new Array(10).fill(1).map((x, index) => {\n                const { color } = colorSH[index];\n                const choosed = color === colorSelected;\n\n                return (\n                  <div\n                    className={classNames({\n                      \"color-preview\": 1,\n                      \"color-selected\": choosed,\n                    })}\n                    style={{\n                      borderColor: color,\n                      backgroundColor: choosed ? \"inherit\" : color,\n                    }}\n                    onClick={() => setColor(color)}\n                  >\n                    <div\n                      className=\"color-preview-inner\"\n                      style={{ backgroundColor: color }}\n                    ></div>\n                  </div>\n                );\n              })}\n            </div>\n            <div className=\"custom-color\">\n              <div className=\"selected-color-preview\">\n                <input\n                  className=\"color-input\"\n                  type=\"color\"\n                  value={colorSelected}\n                  onInput={(e) => setColor(e.currentTarget.value)}\n                />\n                <input\n                  className=\"color-value\"\n                  value={colorSelected}\n                  onInput={(e) => setColor(e.currentTarget.value)}\n                ></input>\n              </div>\n            </div>\n          </div>\n        );\n      }\n      case \"operation\": {\n        return (\n          <div className=\"operation-detail\">\n            <div\n              className=\"operation-item\"\n              onClick={() => {\n                setSubLine(!subLine);\n              }}\n            >\n              {subLine?t('line.notSubLineAnymore'):t('line.asSubline')}...\n            </div>\n            <div\n              className=\"operation-item delete\"\n              onClick={() => {\n                showConfirmation!({ line }, deleteLine);\n              }}\n            >\n              {t('line.deleteLine')}\n            </div>\n          </div>\n        );\n      }\n    }\n  };\n  const { engine } = browserInfo;\n  const stationsInThisLine = getStationsInThisLine();\n  if (addingStation) {\n    stationsInThisLine.unshift(new StationProps());\n  }\n  return (\n    <div\n      className={classNames({ \"line-card\": 1, \"expand-card\": expand })}\n      style={{\n        width: expand ? expandWidth : undefined,\n        boxShadow:\n          engine.name === \"WebKit\"\n            ? \"0 4px 59px 7px rgba(0, 0, 0, 0.25)\"\n            : undefined,\n      }}\n    >\n      <div className=\"tools\">\n        {expand || edit ? (\n          <></>\n        ) : (\n          <div\n            className=\"edit tool-item\"\n            onClick={() => {\n              setEdit(true);\n              // setTab(\"name\");\n            }}\n          >\n            <EditIcon className=\"edit-icon\"></EditIcon>\n          </div>\n        )}\n        {edit ? (\n          <></>\n        ) : (\n          <div className={classNames({\"expand tool-item\":1,shrink: expand})} onClick={() => setExpand(!expand)}>\n            {expand ? <ShrinkIcon className=\"expand-icon\"/> : <ExpandIcon className=\"expand-icon\"/>}\n          </div>\n        )}\n      </div>\n      <div\n        className=\"stations-count\"\n        onClick={() => {\n          setCardShowing({ lineIds: [lineId], stationIds });\n        }}\n      >\n        {stationIds.length}{t('line.stations')}\n      </div>\n\n      <AutoGrowthInput\n        onInput={(e) => setLineName(e.currentTarget.value)}\n        className=\"line-name\"\n        value={lineName}\n        disabled\n      />\n      {edit ? (\n        <div className=\"edit-detail\">{editTools(tab)}</div>\n      ) : (\n        <>\n          <div className=\"from-to\">\n            {firstStation\n              ? t('line.fromTo', {from:firstStation!.stationName,to: lastStation!.stationName})\n              : t('line.notInUse')}\n          </div>\n\n          <div\n            className=\"station-bar\"\n            style={expand ? { width: expandWidth } : {}}\n            onWheel={onWheelX}\n          >\n            <div className=\"add-first\"></div>\n            {stationsInThisLine.map((station, index) => {\n              const { stationName, stationId } = station!;\n              const bendFirst = getBendFirst(index);\n              const last = index === stationsInThisLine.length - 1;\n              let currentInserting = false;\n              if (insertInfo) {\n                const { insertIndex, line: insertLine } = insertInfo;\n                if (insertIndex === index && insertLine === line) {\n                  currentInserting = true;\n                }\n              }\n              return (\n                <div className=\"station-block\">\n                  <div className=\"track\">\n                    <div className=\"sleeper\"></div>\n                    <div className=\"sleeper\"></div>\n                    <div className=\"sleeper\"></div>\n                  </div>\n                  <div\n                    className={classNames({\n                      \"bend-first\": 1,\n                      \"current-inserting\": currentInserting,\n                    })}\n                    onClick={(e) => {\n                      if (addingStation) {\n                        if (!firstStation) {\n                          if (menuRef?.current?.showTools) {\n                            menuRef.current.showTools(\n                              e,\n                              FunctionMode.selectingStation\n                            );\n                          }\n                        }\n                        setInsertInfo({ insertIndex: index, line });\n                        setFunctionMode(FunctionMode.selectingStation);\n                      } else if (last) {\n                        setInsertInfo({ insertIndex: index + 1, line });\n                        if (menuRef?.current?.showTools) {\n                          menuRef.current.showTools(\n                            e,\n                            FunctionMode.selectingStation\n                          );\n                        }\n                      } else {\n                        setBendFirst(index, !bendFirst);\n                      }\n                    }}\n                  >\n                    <div\n                      className={classNames({\n                        \"bend-icon\": 1,\n                        bend: bendFirst && !addingStation && !last,\n                      })}\n                    >\n                      {addingStation || last ? <PlusIcon /> : <ArrowIcon />}\n                    </div>\n                    <div className=\"bend-des\">\n                      {addingStation || last\n                        ? currentInserting\n                          ? t('line.insertHere')\n                          : t('line.insertStation')\n                        : bendFirst\n                        ? t('line.bendFirst')\n                        : t('line.straight')}\n                    </div>\n                  </div>\n                  <div\n                    className=\"station-name\"\n                    style={{ color: colorSelected }}\n                    onClick={() => {\n                      setCardShowing({\n                        lineIds: [lineId],\n                        stationIds: [stationId],\n                      });\n                    }}\n                  >\n                    {stationName}\n                  </div>\n                </div>\n              );\n            })}\n          </div>\n        </>\n      )}\n\n      {\n        <div className={classNames({ \"edit-panel\": 1, edit })}>\n          <div\n            className={classNames({\n              \"edit-tools\": 1,\n            })}\n            onWheel={onWheelY}\n          >\n            <div\n              className={classNames({\n                \"edit-tool name\": 1,\n                selected: tab === \"name\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"name\");\n              }}\n            >\n              <div className=\"title\">{t('line.name')}</div>\n              <div className=\"value\">{lineName}</div>\n            </div>\n            <div\n              className={classNames({\n                \"edit-tool color\": 1,\n                selected: tab === \"color\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"color\");\n              }}\n            >\n              <div className=\"title\">{t('line.color')}</div>\n              <div className=\"value\" style={{ color: colorSelected }}>\n                {colorName}\n              </div>\n            </div>\n            <div\n              className={classNames({\n                \"edit-tool operation\": 1,\n                selected: tab === \"operation\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"operation\");\n              }}\n            >\n              <div className=\"title\">{t('line.operation')}</div>\n              <div className=\"value\">{t('line.delete')}</div>\n            </div>\n          </div>\n\n          <div className=\"done\" onClick={() => setEdit(false)}>\n            <EditIcon className=\"done-icon\" />\n            <span className=\"done-des\">{t('line.done')}</span>\n          </div>\n        </div>\n      }\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/Render/Card/StationCard.scss",
    "content": ".station-card {\n    width: 455px;\n    height: 250px;\n    border-radius: 23px;\n    display: inline-block;\n    // margin-left: 50px;\n    // margin-bottom: 50px;\n\n    // zoom: 0.8;\n    --margin-left: 33px;\n    background-color: rgba(255, 255, 255, 0.863);\n    backdrop-filter: blur(15px);\n    position: relative;\n    transition: 0.3s ease-in-out width;\n    overflow: hidden;\n    .tools {\n        position: absolute;\n        right: 0;\n        .tool-item {\n            vertical-align: top;\n            height: 34px;\n            width: 34px;\n            display: inline-flex;\n            justify-content: center;\n            align-items: center;\n            margin: 14.5px 11.3px 0 0;\n            background-color: #d9d9d9;\n            border-radius: 7.25px;\n            .expand-icon {\n                height: 15px;\n                width: 15px;\n            }\n            .edit-icon {\n                height: 17.74px;\n                width: 17.74px;\n            }\n        }\n    }\n    .line-count {\n        font-size: 18px;\n        font-weight: 500;\n        margin: 23px 0 0 var(--margin-left);\n        cursor: pointer;\n    }\n    .station-name {\n        & > * {\n            font-size: 25px;\n            font-weight: 500;\n        }\n        margin: 2px 0 0 var(--margin-left);\n    }\n\n    .from-to {\n        font-size: 18px;\n        font-weight: 500;\n        margin: 5px 0 0 var(--margin-left);\n        color: #ababab;\n    }\n    .edit-detail {\n        height: 164px;\n        overflow-y: scroll;\n        &::-webkit-scrollbar {\n            display: none;\n            // width: 0.01px;\n        }\n        .name-detail {\n            margin-top: 22.58px;\n            white-space: nowrap;\n            width: fit-content;\n            .name-item {\n                display: inline-block;\n                margin-right: 24.2px;\n                vertical-align: top;\n                position: relative;\n                &:first-child {\n                    margin-left: 32.25px;\n                }\n                .title {\n                    font-size: 11.25px;\n                    font-weight: 500;\n                    color: #ea0b2a;\n                }\n                input {\n                    margin-top: 21.77px;\n                    padding: 0;\n                }\n                .auto-growth-span {\n                    font-size: 36px;\n                    border: none;\n                    font-weight: 500;\n                    width: 100px;\n                    margin-top: 14px;\n                    opacity: 0;\n                }\n                .auto-growth-input {\n                    font-size: 36px;\n                    border: none;\n                    font-weight: 500;\n                    width: calc(100% + 18px);\n                    margin-top: 14px;\n                    position: absolute;\n                    left: 0;\n                }\n            }\n        }\n        .color-detail {\n            .color-detail-choosing {\n                box-sizing: border-box;\n                padding: 10px 32.25px;\n                width: 255px;\n                display: grid;\n                border: white 1px solid;\n                grid-template-columns: repeat(4, 25%);\n                grid-template-rows: repeat(3, 33.33%);\n                // grid-row-gap: 9px;\n                // grid-column-gap: 6px;\n                .shape-container {\n                    height: 46.13px;\n                    display: flex;\n                    justify-content: center;\n                    align-items: center;\n                    border-left: 1px black dotted;\n                    border-bottom: 1px black solid;\n                    transform: translate(-1px, 1px);\n                    cursor: pointer;\n\n                    &.left {\n                        border-left: none;\n                    }\n                    &.bottom {\n                        border-bottom: none;\n                    }\n                    .shape-preview {\n                        width: 19.5px;\n                        height: 19.5px;\n                        // border-radius: 50%;\n                        // border: 2px solid;\n                        display: flex;\n                        justify-content: center;\n                        align-items: center;\n                        &.shape-selected {\n                            svg {\n                                * {\n                                    stroke: #ea0b2a;\n                                }\n                            }\n                        }\n                        &.square {\n                            zoom: 0.9;\n                        }\n                        &.triangle {\n                            zoom: 1.05;\n                        }\n                        &.start {\n                            zoom: 1.15;\n                        }\n                        &.hexagon {\n                            zoom: 0.9;\n                        }\n                        &.pentagon {\n                            zoom: 1.1;\n                        }\n                        &.diamond{\n                            zoom: 1.15;\n                        }\n                        &.leaf{\n                            zoom: 0.9;\n                        }\n                    }\n                }\n            }\n        }\n        .operation-detail {\n            .operation-item {\n                width: fit-content;\n                &:first-child {\n                    margin-top: 15px;\n                }\n                &:last-child {\n                    margin-bottom: 15px;\n                }\n                margin-left: 32.25px;\n                margin-top: 8px;\n                margin-bottom: 8px;\n                color: #2196f3;\n                font-size: 18px;\n                font-weight: 500;\n                cursor: pointer;\n                &.delete {\n                    color: #ea0b2a;\n                }\n            }\n        }\n        .tag-detail {\n            display: grid;\n            grid-template-columns: repeat(3, 33.33%);\n            grid-template-rows: repeat(3, 33.33%);\n            width: 200px;\n            height: 126px;\n            margin: 18px 30.25px;\n            align-content: center;\n            justify-content: center;\n            align-items: center;\n            justify-items: center;\n            .tag-item {\n                text-align: center;\n                font-size: 11.25px;\n                font-weight: 500;\n                cursor: pointer;\n                background-color: rgb(0, 0, 0, 13%);\n                height: 30px;\n                width: 55.65px;\n                border-radius: 3px;\n                border: 1px dotted;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                &.selected{\n                background-color: rgb(0, 0, 0, 23%);\n                border: 1px solid;\n                }\n                &.center{\n                    background-color: transparent;\n                    border: none;\n                }\n            }\n        }\n    }\n    .station-bar {\n        margin: 30px 0 0 0;\n        white-space: nowrap;\n        width: 455px;\n        overflow-x: scroll;\n        overflow-y: hidden;\n        transition: 0.3s ease-in-out width;\n\n        &::-webkit-scrollbar {\n            display: none;\n            // width: 0.01px;\n        }\n        .add-first {\n            width: var(--margin-left);\n            display: inline-block;\n        }\n        .station-block {\n            display: inline-block;\n            width: 161px;\n            height: 78.22px;\n            border-left: 1px solid #cccccc;\n            position: relative;\n            .track {\n                display: flex;\n                background-color: #f0f0f0;\n                width: 161px;\n                height: 48.3px;\n                .sleeper {\n                    border-left: 1px solid #cccccc;\n                    width: 53.6px;\n                    &:first-child {\n                        border: none;\n                    }\n                }\n            }\n            .bend-first {\n                position: absolute;\n                top: 7.215px;\n                left: 9.5px;\n                height: 33.87px;\n                width: 133.8px;\n                background-color: #d9d9d9;\n                border-radius: 4px;\n                display: flex;\n                align-items: center;\n                .bend-icon {\n                    width: 16px;\n                    height: 16px;\n                    display: inline-block;\n                    margin: 0 13px 0 18.5px;\n\n                    &.bend {\n                        transform: rotate(-45deg);\n                    }\n                }\n                .bend-des {\n                    display: inline-block;\n                    font-size: 14.25px;\n                    font-weight: 500;\n                    color: rgb(0, 0, 0, 0.5);\n                }\n            }\n            .station-name {\n                font-size: 18px;\n                font-weight: 500;\n                margin: 8px;\n                color: #ea0b2a;\n            }\n        }\n    }\n    .edit-panel {\n        &.edit {\n            right: 0;\n        }\n        width: 200.8px;\n        background-color: #f2f2f2;\n        position: absolute;\n        right: -200.8px;\n        top: 0;\n        height: 250px;\n        transition: 0.3s ease-in-out right;\n        .edit-tools {\n            width: 200.8px;\n            height: 250px;\n            overflow-y: scroll;\n            overflow-x: hidden;\n            &::-webkit-scrollbar {\n                display: none;\n                // width: 0.01px;\n            }\n            .edit-tool {\n                &:first-child {\n                    margin: 21.7px 21.7px 2px 21.7px;\n                }\n                &:last-child {\n                    margin: 2px 21.7px 21.7px 21.7px;\n                }\n                cursor: pointer;\n                margin: 2px 21.7px 2px 21.7px;\n                width: 158px;\n                height: 75px;\n                border-radius: 11.3px;\n                font-weight: 500;\n                display: flow-root;\n                &.selected {\n                    background-color: #d9d9d9;\n                }\n                .title {\n                    font-size: 18px;\n                    margin: 12.1px 0 0 20.2px;\n                    text-transform: capitalize;\n                }\n                .value {\n                    font-size: 11.25px;\n                    margin: 4.83px 0 0 20.2px;\n                    .position {\n                        color: #5e5e5e;\n                        margin: 0 5px;\n                        text-decoration: underline;\n                    }\n                }\n            }\n        }\n\n        .done {\n            background-color: #2196f3;\n            border-radius: 25px;\n            width: 74px;\n            height: 28.2px;\n            position: absolute;\n            bottom: 23.4px;\n            right: 23.4px;\n            display: flex;\n            align-items: center;\n            .done-icon {\n                height: 17.74px;\n                width: 17.74px;\n                margin: 0 6.5px 0 11.3px;\n                path {\n                    fill: #ffffff;\n                    fill-opacity: 1;\n                }\n            }\n            .done-des {\n                font-size: 12px;\n                font-weight: 500;\n                color: white;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Card/StationCard.tsx",
    "content": "import React, {\n  Dispatch,\n  RefObject,\n  SetStateAction,\n  useEffect,\n  useState,\n} from \"react\";\n\nimport \"./StationCard.scss\";\nimport classNames from \"classnames\";\nimport { Point } from \"../../DataStructure/Point\";\nimport {\n  CardShowing,\n  InsertInfo,\n  StationProps,\n  UserDataType,\n  dataProcessor,\n} from \"../../Data/UserData\";\nimport shapes from \"../../Resource/Shape/shape\";\nimport { Shape } from \"../../Data/Shape\";\nimport { AutoGrowthInput } from \"../../Common/AutoGrowthInput\";\nimport {\n  browserInfo,\n  onWheelX,\n  onWheelY,\n  scrollOptimize,\n} from \"../../Common/util\";\nimport { showConfirmationInterface } from \"../Delete/DeleteConfirmation\";\nimport { FunctionMode } from \"../../DataStructure/Mode\";\nimport { useTranslation } from \"react-i18next\";\nexport function StationCard({\n  station,\n  setData,\n  data,\n  showConfirmation,\n  menuRef,\n  functionMode,\n  setFunctionMode,\n  insertInfo,\n  setInsertInfo,\n  cardShowing,\n  setCardShowing,\n}: {\n  station: StationProps;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  data: UserDataType;\n  showConfirmation?: showConfirmationInterface;\n  menuRef: RefObject<any>;\n  functionMode: FunctionMode;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n}) {\n  const {\n    stationName,\n    lineIds,\n    position,\n    shape: shapeSelected,\n    stationId,\n    tagDirection=8,\n  } = station;\n  const {\n    setStationName,\n    setStationPosition,\n    setStationShape,\n    getLineById,\n    deleteStation,\n    removeStationFromLine,\n    addNewLine,\n    setStationTagDirection,\n  } = dataProcessor(stationId, setData, data);\n  const [x, y] = position;\n  const setX = (x: number) => setStationPosition(x, y);\n  const setY = (y: number) => setStationPosition(x, y);\n  const lineCount = lineIds.length;\n  const [tab, setTab] = useState(\"name\");\n  const { engine } = browserInfo;\n  const { t } = useTranslation();\n  const tags = [\n    t('station.up'),\n    t('station.upRight'),\n    t('station.right'),\n    t('station.rightDown'),\n    t('station.down'),\n    t('station.downLeft'),\n    t('station.left'),\n    t('station.leftUp'),\n    t('station.auto')\n  ];\n  const editTools = (tab: string) => {\n    switch (tab) {\n      case \"name\": {\n        return (\n          <div className=\"name-detail\">\n            <div className=\"name-item sign\">\n              <div className=\"title\">{t('station.x')}</div>\n              <AutoGrowthInput\n                value={x}\n                onInput={(x) => setX(Number(x.currentTarget.value))}\n                type=\"number\"\n              />\n            </div>\n            <div className=\"name-item order\">\n              <div className=\"title\">{t('station.y')}</div>\n              <AutoGrowthInput\n                value={y}\n                onInput={(y) => setY(Number(y.currentTarget.value))}\n                type=\"number\"\n              />\n            </div>\n          </div>\n        );\n      }\n      case \"color\": {\n        const column = 4;\n        const row = 3;\n        const grid = new Array(column * row).fill(0);\n        Object.keys(shapes).forEach((shape, index) => (grid[index] = shape));\n        return (\n          <div className=\"color-detail\">\n            <div className=\"color-detail-choosing\">\n              {grid.map((shape, index) => {\n                const left = index % column === 0;\n                const bottom = Math.floor(index / column) === row - 1;\n                // console.log({ shape });\n                return (\n                  <div\n                    className={classNames({\n                      \"shape-container\": 1,\n                      left,\n                      bottom,\n                    })}\n                    onClick={() => {\n                      if (shape) setStationShape(shape);\n                    }}\n                  >\n                    <div\n                      className={classNames({\n                        \"shape-preview\": 1,\n                        \"shape-selected\": shape === shapeSelected,\n                        [shape]: 1,\n                      })}\n                    >\n                      {\n                        //@ts-ignore\n                        shapes[shape]\n                      }\n                    </div>\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n        );\n      }\n      case \"operation\": {\n        return (\n          <div className=\"operation-detail\">\n            <div\n              className=\"operation-item add-new-line-btn\"\n              onClick={(e) => {\n                const newLine = addNewLine();\n                setInsertInfo({ insertIndex: 1, line: newLine! });\n                // setFunctionMode(FunctionMode.selectingStation);\n                if (menuRef?.current?.showTools) {\n                  menuRef.current.showTools(e, FunctionMode.selectingStation);\n                }\n              }}\n            >\n              {t('station.startHere')}\n            </div>\n            {lineIds.map((lineId) => {\n              const line = getLineById(lineId);\n              const stationIndexes: number[] = [];\n              line?.stationIds.forEach((x, index) => {\n                if (x === stationId) stationIndexes.push(index);\n              });\n              const { lineName } = line!;\n              const removeStations = stationIndexes.map((stationIndex) => (\n                <div\n                  className=\"operation-item delete\"\n                  onClick={() => {\n                    showConfirmation!({ line, station, stationIndex }, () => {\n                      removeStationFromLine(lineId, stationIndex);\n                    });\n                  }}\n                >\n                  {t('station.remove',{lineName,stationIndex: stationIndex! + 1})}...\n                </div>\n              ));\n              return removeStations;\n            })}\n            <div\n              className=\"operation-item delete\"\n              onClick={() => {\n                showConfirmation!({ station }, () => {\n                  deleteStation();\n                  if (menuRef?.current?.backToTitle) {\n                    menuRef.current.backToTitle();\n                  }\n                });\n              }}\n            >\n              {t('station.delete')}\n            </div>\n          </div>\n        );\n      }\n      case \"tag\": {\n        const directMapIndex = [7, 0, 1, 6, 8, 2, 5, 4, 3];\n        return (\n          <div className=\"tag-detail\">\n            {directMapIndex.map((direct, index) => {\n              if (index === 4)\n                return (\n                  <div\n                    onClick={() => {\n                      setStationTagDirection(8);\n                    }}\n                    className=\"tag-item center\"\n                  >\n                    {tags[tagDirection]}\n                  </div>\n                );\n              else\n                return (\n                  <div\n                    onClick={() => {\n                      setStationTagDirection(direct);\n                    }}\n                    className={classNames({\n                      \"tag-item\": 1,\n                      selected: tagDirection === direct,\n                    })}\n                  ></div>\n                );\n            })}\n          </div>\n        );\n      }\n    }\n  };\n  return (\n    <div\n      className={classNames({ \"station-card\": 1 })}\n      style={\n        engine.name === \"WebKit\"\n          ? { boxShadow: \"0 4px 59px 7px rgba(0, 0, 0, 0.25)\" }\n          : {}\n      }\n    >\n      <div\n        className=\"line-count\"\n        onClick={() => {\n          setCardShowing({\n            stationIds: [stationId],\n            lineIds,\n            stationFirst: true,\n          });\n        }}\n      >\n        {lineCount}{t('station.lines')}\n      </div>\n      <AutoGrowthInput\n        onInput={(e) => setStationName(e.currentTarget.value)}\n        className=\"station-name\"\n        value={stationName}\n      />\n      <div className=\"edit-detail\" onWheel={onWheelY}>\n        {editTools(tab)}\n      </div>\n\n      {\n        <div className={classNames({ \"edit-panel\": 1, edit: 1 })}>\n          <div\n            className={classNames({\n              \"edit-tools\": 1,\n            })}\n            onWheel={onWheelY}\n          >\n            <div\n              className={classNames({\n                \"edit-tool name\": 1,\n                selected: tab === \"name\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"name\");\n              }}\n            >\n              <div className=\"title\">{t('station.poisition')}</div>\n              <div className=\"value\">\n                X<span className=\"position\">{x}</span>Y\n                <span className=\"position\">{y}</span>\n              </div>\n            </div>\n            <div\n              className={classNames({\n                \"edit-tool color\": 1,\n                selected: tab === \"color\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"color\");\n              }}\n            >\n              <div className=\"title\">{t('station.shape')}</div>\n              <div className=\"value\">\n                {\n                  t(`shape.${shapeSelected}`)\n                }\n              </div>\n            </div>\n            <div\n              className={classNames({\n                \"edit-tool operation station-card-operation\": 1,\n                selected: tab === \"operation\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"operation\");\n              }}\n            >\n              <div className=\"title\">{t('station.operation')}</div>\n              <div className=\"value\">{t('station.operateDes')}</div>\n            </div>\n            <div\n              className={classNames({\n                \"edit-tool operation tag\": 1,\n                selected: tab === \"tag\",\n              })}\n              onClick={(e) => {\n                scrollOptimize(e);\n                setTab(\"tag\");\n              }}\n            >\n              <div className=\"title\">{t('station.stationName')}</div>\n              <div className=\"value\">{tags[tagDirection]}</div>\n            </div>\n          </div>\n        </div>\n      }\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/Render/Component/LineRender.tsx",
    "content": "import React, {\n  CSSProperties,\n  Dispatch,\n  SetStateAction,\n  memo,\n  useEffect,\n  useState,\n} from \"react\";\nimport { Line } from \"../../DataStructure/Line\";\nimport { Point } from \"../../DataStructure/Point\";\n\nimport {\n  generateLineCommand,\n  getAllKeyPoints,\n  getRoundedPoints,\n} from \"../../Line/LinePoints\";\nimport { clearHandle, getHandleCommand } from \"../../Line/Handle\";\nimport { gauge } from \"../../Common/const\";\nimport {\n  CardShowing,\n  DrawProps,\n  DrawerSize,\n  UserDataType,\n} from \"../../Data/UserData\";\n\nfunction LineRender({\n  line,\n  cardShowing,\n  setCardShowing,\n  command,\n  data,\n  setData,\n  drawing,\n  drawerX,\n  drawerY,\n}: {\n  line: Line;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n  command: string;\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n} & DrawProps &\n  DrawerSize) {\n  const { stations } = data;\n  const { displayLine, departureRecord } = line;\n  const { color, lineId, subLine, lineName } = displayLine!;\n  const { lineIds, stationIds } = cardShowing;\n  const showing = lineIds?.length || stationIds?.length;\n  const emphasis =\n    lineIds?.includes(lineId) ||\n    (stationIds &&\n      stationIds.length === 1 &&\n      stationIds[0] &&\n      stations.get(stationIds[0]) &&\n      stations.get(stationIds[0])?.lineIds?.includes(lineId));\n\n  const [moved, setMoved] = useState(false);\n  const onClick = () => {\n    if (!moved) {\n      setCardShowing({ lineIds: [lineId] });\n    }\n  };\n  return (\n    <>\n      <div style={{ position: \"absolute\" }}>\n        <svg\n          width={drawing ? drawerX : 300}\n          height={drawing ? drawerY : 300}\n          style={{ overflow: \"visible\" }}\n        >\n          {/* <path fill=\"transparent\" stroke=\"black\" d={MCommand + LCommand} /> */}\n          <path\n            id={lineName}\n            // fill=\"transparent\"\n            // stroke-linecap=\"round\"\n            className={`line-path-${lineId}`}\n            strokeDasharray={subLine ? \"10,5\" : undefined}\n            fill=\"none\"\n            stroke={showing && !emphasis ? `${color}55` : `${color}`}\n            d={command}\n            strokeWidth={gauge}\n            style={{ cursor: \"pointer\" }}\n            onMouseDown={() => setMoved(false)}\n            onTouchStart={() => setMoved(false)}\n            onTouchMove={() => (!moved) && setMoved(true)}\n            onMouseMove={() => (!moved) && setMoved(true)}\n            onMouseUp={onClick}\n            onTouchEnd={onClick}\n          />\n\n          {/* <circle cx=\"10\" cy=\"10\" r=\"2\" fill=\"red\" /> */}\n        </svg>\n      </div>\n      {/* {renderPoints(allKeyPoints)} */}\n    </>\n  );\n}\n\nexport default memo(LineRender);\n"
  },
  {
    "path": "src/Render/Delete/DeleteConfirmation.scss",
    "content": ".delete-confirmation-container {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: -1000;\n  height: 100vh;\n  width: 100vw;\n  background-color: rgba(255, 255, 255, 0.2);\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  opacity: 0;\n  transition:\n    0.3s ease-in-out opacity,\n    0.3s ease-in-out z-index;\n  &.before-animated,\n  &.before-disappear {\n    backdrop-filter: blur(1px);\n  }\n  &.animated {\n    opacity: 1;\n    backdrop-filter: blur(10px);\n    z-index: 1000;\n  }\n  .delete-confirmation {\n    text-align: center;\n\n    .title {\n      font-weight: 500;\n      font-size: 36px;\n      padding-left: 13px;\n    }\n    .sub-title {\n      font-weight: 500;\n      font-size: 18px;\n    }\n    .preview {\n      margin-top: 74.2px;\n      display: inline-block;\n      // border-top: 1px solid black;\n      width: fit-content;\n      // padding: 0 40px;\n      text-align: center;\n      position: relative;\n      // display: flex;\n      // align-items: center;\n      // justify-content: center;\n      // &>div{\n      //   transform: translateY(-50%);\n      // }\n      .preview-content {\n        display: flex;\n        justify-content: center;\n        align-items: center;\n        .icon {\n          display: inline-block;\n          margin-left: 40px;\n\n          .line {\n            // width: 35.5px;\n            margin-right: 35.5px;\n\n            .sign-input {\n              // width: 35.5px;\n              * {\n                min-width: 35.5px;\n                height: 35.5px;\n                border: none;\n                border-radius: 8.87px;\n                background-color: #ea0b2a;\n                font-size: 23.25px;\n                color: white;\n                text-align: center;\n              }\n            }\n          }\n          .station {\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            margin-right: 25.8px;\n            svg {\n              &.square {\n                zoom: 0.9;\n              }\n              &.triangle {\n                zoom: 1.05;\n              }\n              &.start {\n                zoom: 1.15;\n              }\n              &.hexagon {\n                zoom: 0.9;\n              }\n              &.pentagon {\n                zoom: 1.1;\n              }\n              &.diamond {\n                zoom: 1.15;\n              }\n              &.leaf {\n                zoom: 0.9;\n              }\n              &.ginkgo {\n                zoom: 0.8;\n              }\n            }\n          }\n        }\n        .text {\n          margin-right: 40px;\n          display: inline-block;\n          font-weight: 500;\n          font-size: 18px;\n\n          line-height: 35.5px;\n          // vertical-align: middle;\n        }\n      }\n\n      .delete-line {\n        border-top: 1px solid #ea0b2a;\n        position: absolute;\n        top: 50%;\n        width: 100%;\n        transition: 0.3s ease-in-out;\n        // animation-delay: 5s;\n        transition-delay: 0.3s;\n      }\n    }\n\n    .delete {\n      font-weight: 500;\n      font-size: 18px;\n      margin-top: 104.8px;\n      cursor: pointer;\n      color: #ea0b2a;\n    }\n    .back {\n      margin-top: 16.12px;\n      font-weight: 500;\n      font-size: 18px;\n      cursor: pointer;\n    }\n  }\n}\n"
  },
  {
    "path": "src/Render/Delete/DeleteConfirmation.tsx",
    "content": "import React, {\n  Dispatch,\n  SetStateAction,\n  forwardRef,\n  useEffect,\n  useImperativeHandle,\n  useState,\n} from \"react\";\nimport { LineProps, StationProps } from \"../../Data/UserData\";\nimport \"./DeleteConfirmation.scss\";\nimport { AutoGrowthInput } from \"../../Common/AutoGrowthInput\";\nimport shapes from \"../../Resource/Shape/shape\";\nimport classNames from \"classnames\";\nimport { useTranslation } from \"react-i18next\";\nimport i18n from \"../../i18n/config\";\nexport interface showConfirmationInterface {\n  (\n    {\n      line,\n      station,\n      stationIndex,\n    }: { line?: LineProps; station?: StationProps; stationIndex?: number },\n    callback?: any\n  ): void;\n}\nenum ShowMode {\n  none,\n  beforeAnimate,\n  animated,\n  beforeDisappear,\n}\nexport const DeleteConfirmation = forwardRef(function (\n  {}: any,\n  ref: React.Ref<unknown> | undefined\n) {\n  const [show, setShow] = useState(ShowMode.none);\n  //   const [title, setTitle] = useState();\n  //   const [subTitle, setSubTitle] = useState();\n  const [line, setLine] = useState<LineProps>();\n  const [station, setStation] = useState<StationProps>();\n  const [stationIndex, setStationIndex] = useState<number | undefined>();\n  const [callback, setCallback] = useState(() => () => {});\n  const {t} = useTranslation();\n  //@ts-ignore\n  window.setShow = setShow\n  const showWithAnimate = () => {\n    setShow(ShowMode.beforeAnimate);\n    setTimeout(() => setShow(ShowMode.animated));\n  };\n  const disappearWithAnimate = () => {\n    setShow(ShowMode.beforeDisappear);\n    setTimeout(() => setShow(ShowMode.none),300);\n  };\n  const showConfirmation: showConfirmationInterface = (\n    { line, station, stationIndex },\n    callback\n  ) => {\n    showWithAnimate();\n    setLine(line);\n    setStation(station);\n    setCallback(() => callback);\n    setStationIndex(stationIndex);\n  };\n  useImperativeHandle(\n    ref,\n    () => {\n      return {\n        showConfirmation,\n      };\n    },\n    []\n  );\n  const remove = line && station;\n  const deleteText = remove ? t('delete.remove') : t('delete.delete');\n  const title = t('que-shi-yao-deletetext-ma', {deleteText});\n  const { stationName, shape } = station || {};\n  const { lineName, sign, color } = line || {};\n  const index = stationIndex ? stationIndex + 1 : 1;\n  const getOrdinalSuffix = (number: number)=> {\n    const suffixes = [\"th\", \"st\", \"nd\", \"rd\"];\n    const v = number % 100;\n    return number + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\n  }\n  const subTitle = t('delete.subtile', {lineName, index:i18n.language === 'en-US'? getOrdinalSuffix(index):index});\n\n  return (\n    <div\n      style={show === ShowMode.none ? { display: \"none\" } : {}}\n      className={classNames({\n        \"delete-confirmation-container\": 1,\n        \"before-animate\": show === ShowMode.beforeAnimate, \n        \"animated\": show === ShowMode.animated,\n        \"before-disappear\": show === ShowMode.beforeDisappear,\n      })}\n      onClick={disappearWithAnimate}\n    >\n      <div className=\"delete-confirmation\">\n        <div className=\"title\">{title}</div>\n        {remove ? <div className=\"sub-title\">{subTitle}</div> : <></>}\n        <div className=\"preview\">\n          <div className=\"preview-content\">\n            <div className=\"icon\">\n              {line && !station ? (\n                <div className=\"line\">\n                  <AutoGrowthInput\n                    className=\"sign-input\"\n                    value={sign!}\n                    //   disabled\n                    style={{ backgroundColor: color }}\n                  />\n                </div>\n              ) : (\n                <div className=\"station\">\n                  {\n                    //@ts-ignore\n                    shapes[shape]\n                  }\n                </div>\n              )}\n            </div>\n            <div className=\"text\">{stationName || lineName}</div>\n          </div>\n          <div\n            className=\"delete-line\"\n            style={show===ShowMode.animated || show === ShowMode.beforeDisappear ? {} : { width: 0 }}\n          ></div>\n        </div>\n        <div\n          className=\"delete\"\n          onClick={() => {\n            disappearWithAnimate();\n            if (typeof callback === \"function\") callback();\n          }}\n        >\n          {deleteText}\n        </div>\n        <div className=\"back\" onClick={disappearWithAnimate}>\n          {t('delete.cancel')}\n        </div>\n      </div>\n    </div>\n  );\n});\n"
  },
  {
    "path": "src/Render/ErrorFallback/ErrorFallback.scss",
    "content": ".error-layer {\n  text-align: center;\n  .title {\n    margin-top: 20vh;\n    font-size: 36px;\n    font-weight: 1000;\n  }\n  .sub-title {\n    margin-top: 0.5vh;\n    font-size: 18px;\n    font-weight: 500;\n  }\n  .error-btn {\n    span{\n      margin-left: 55px;\n      text-align: left;\n    }\n    user-select: none;\n    font-size: 18px;\n    font-weight: 500;\n    cursor: pointer;\n    --gap: min(20px, 2vw);\n    position: relative;\n    svg{\n      position: absolute;\n      left: calc(var(--gap) + 20px);\n    }\n    &.recover-from-cache {\n      margin-top: 12vh;\n      background-color: rgb(234, 11, 42, 0.09);\n      color: #ea0b2a;\n      svg {\n        width: 20px;\n\n      }\n    }\n    &.export-from-cache {\n      margin-top: 0.5vh;\n      background-color: #D9D9D9;\n      svg {\n        width: 16px;\n        padding: 0 2px;\n  \n      }\n    }\n    padding: 20px 30px;\n    width: 315px;\n    margin: auto;\n    border-radius: 10px;\n    display: flex;\n    justify-content: left;\n    align-items: center;\n\n  }\n  .export-error{\n    position: absolute;\n    bottom: 10vh;\n    margin: auto;\n    left: 0;\n    right: 0;\n    font-size: 18px;\n    font-weight: 500;\n    .export-error-file{\n      color: #ea0b2a;\n      cursor: pointer;\n    }\n  }\n}\n"
  },
  {
    "path": "src/Render/ErrorFallback/ErrorFallback.tsx",
    "content": "import React from \"react\";\nimport \"./ErrorFallback.scss\";\nimport { ReactComponent as RecoverIcon } from \"../../Resource/Icon/clock.arrow.circlepath.svg\";\nimport { ReactComponent as ExportIcon } from \"../../Resource/Icon/export.svg\";\nimport { exportFile, exportJson } from \"../../Common/util\";\nimport moment from \"moment\";\nimport { useTranslation } from \"react-i18next\";\n\nexport const ErrorFallback = ({\n  error,\n  resetErrorBoundary,\n}: {\n  error: Error;\n  resetErrorBoundary: () => void;\n}) => {\n  const exportFile = (key: string) => {\n    const current = localStorage.getItem(key);\n    exportJson(\n      current!,\n      `recovery-${key}-${moment().format(\"YYYY-MM-DD_HH-mm-ss\")}.json`\n    );\n  };\n  const { t } = useTranslation();\n  return (\n    <div className=\"error-layer\">\n      <div className=\"title\">{t('error.metError')}</div>\n      <div className=\"sub-title\">{t('error.dontWorry')}</div>\n      <div className=\"recover-from-cache error-btn\" onClick={resetErrorBoundary}>\n        <RecoverIcon />\n        <span>{t('error.recoverFromCache')}</span>\n      </div>\n      <div\n        className=\"export-from-cache error-btn\"\n        onClick={() => exportFile(\"last\")}\n      >\n        <ExportIcon />\n        <span>{t('error.exportNoErrorFile')}</span>\n      </div>\n      <div className=\"export-error\">\n        <div className=\"or\">\n          {t('error.orYouCould')}\n          <span\n            className=\"export-error-file\"\n            onClick={() => exportFile(\"current\")}\n          >\n            {t('error.exportError')}\n          </span>\n        </div>\n        <div className=\"for\">{t('error.sendAuthor')}</div>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "src/Render/Header/Component/OpacityControl.scss",
    "content": ".tool {\n    position: relative;\n    display: inline-block;\n    cursor: pointer;\n    perspective: 1000px;\n    perspective-origin: 0 50%;\n\n    &:has(.slider-container) {\n        z-index: 600;\n    }\n\n    .slider-container {\n        transition:\n            transform 0s,\n            transform 0.3s ease-in-out,\n            all 0.3s ease-in-out;\n        &.show {\n            opacity: 1;\n            pointer-events: unset;\n            top: 100%;\n            transform: scale(calc(1 + var(--value) * 0.075)) rotate3d(0, 1, 0, 0deg);\n        }\n        opacity: 0;\n        pointer-events: none;\n        position: absolute;\n        top: 50%;\n        left: 0;\n        margin-top: 8px;\n        background: rgba(255, 255, 255, 0.136);\n        box-shadow: 0 0 100px rgba(#000000, 0.15);\n        // border: #ea0b2a 1px solid;\n        z-index: 600;\n        width: 400%;\n        max-width: 100vw;\n        overflow: hidden;\n        height: 40px;\n        border-radius: 5px;\n        backdrop-filter: blur(20px);\n        transform: scale(calc(1 + var(--value) * 0.075)) rotate3d(0, 1, 0, var(--deg));\n        transform-origin: 0 0;\n        .opacity-text {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            margin: auto;\n            pointer-events: none;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            margin-left: 20px;\n            font-size: 14px;\n            opacity: var(--value);\n            span {\n                margin-left: 2px;\n                font-size: 10px;\n                font-weight: 600;\n                vertical-align: baseline;\n                margin-top: 2.5px;\n            }\n        }\n        .slider {\n            appearance: none;\n            width: 100%;\n            height: 100%;\n            appearance: none;\n            margin: 0;\n            background-color: transparent;\n            background-image: repeating-linear-gradient(\n                to right,\n                transparent,\n                transparent calc(18% - 1px),\n                #05051a1c 18%\n            );\n            &::-webkit-slider-thumb {\n                box-shadow: -20rem 0 0 20rem rgba(#ea0b2a, 0.2);\n                cursor: col-resize;\n                background-color: rgba(#ea0b2a, 0.2);\n            }\n\n                @supports not (-webkit-touch-callout: none) {\n                    &::-webkit-slider-thumb {\n                        -webkit-appearance: none;\n                        appearance: none;\n                        width: 0;\n                    }\n                }\n                @supports (-webkit-min-device-pixel-ratio: 0) {\n                    &::-webkit-slider-thumb {\n                        -webkit-appearance: auto;\n                        appearance: auto;\n                        width: auto;\n                    }\n                  }\n\n            \n            &::-webkit-slider-runnable-track {\n                // pointer-events: none;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Header/Component/OpacityControl.tsx",
    "content": "import React, {\n  useState,\n  useRef,\n  useEffect,\n  CSSProperties,\n  useLayoutEffect,\n} from \"react\";\nimport \"./OpacityControl.scss\";\nimport classNames from \"classnames\";\nimport { browserInfo } from \"../../../Common/util\";\nimport { useTranslation } from \"react-i18next\";\ninterface OpacityControlProps {\n  opacity: number;\n  setOpacity: (value: number) => void;\n}\n\n\nconst OpacityControl: React.FC<OpacityControlProps> = ({\n  opacity,\n  setOpacity,\n}) => {\n  const [showSlider, setShowSlider] = useState(false);\n  const sliderRef = useRef<HTMLDivElement>(null);\n  const inputRef = useRef<HTMLInputElement>(null);\n  const toolRef = useRef<HTMLDivElement>(null);\n  const { t } = useTranslation();\n  const handleClick = () => {\n    setShowSlider(!showSlider);\n  };\n\n  const handleSliderChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    setOpacity(Number(event.target.value));\n  };\n\n  useEffect(() => {\n    if (showSlider && sliderRef.current && toolRef.current) {\n      const toolRect =\n      toolRef.current.getBoundingClientRect();\n      const viewportWidth = window.innerWidth;\n\n      if (toolRect.left + 230 > viewportWidth) {\n        sliderRef.current.style.left = \"unset\";\n        sliderRef.current.style.right = \"0\";\n        (sliderRef.current.style as any)['--deg'] = \"-25deg\";\n        sliderRef.current.style.transformOrigin = \"100% 50%\";\n        toolRef.current.style.perspectiveOrigin = \"100% 50%\";\n      } else {\n        sliderRef.current.style.left = \"0\";\n        sliderRef.current.style.transformOrigin = \"0 50%\";\n        toolRef.current.style.perspectiveOrigin = \"0 50%\";\n        (sliderRef.current.style as any)['--deg'] = \"25deg\";\n      }\n    }\n  }, [showSlider]);\n  useLayoutEffect(() => {\n    if (sliderRef.current) {\n      sliderRef.current.style.transition = \"0.3s ease-in-out\";\n    }\n  }, [showSlider]);\n  useEffect(() => {\n    const handleClickCapture = (event: TouchEvent | MouseEvent) => {\n      if (event.target !== inputRef.current && event.target !== toolRef.current) {\n        console.log(\"focusout\");\n        setShowSlider(false);\n      }\n    };\n    const resize = () => setShowSlider(false);\n    document.addEventListener(\"touchstart\", handleClickCapture, true);\n    document.addEventListener(\"click\", handleClickCapture, true);\n    document.addEventListener(\"resize\",resize);\n    return () => {\n      document.removeEventListener(\"touchstart\", handleClickCapture, true);\n      document.addEventListener(\"click\", handleClickCapture, true);\n      document.removeEventListener(\"resize\",resize);\n    };\n  }, []);\n  const { engine } = browserInfo;\n  const safari = engine.name === \"WebKit\";\n  return (\n    <div className=\"tool\" onClick={handleClick} ref={toolRef}>\n      {t('opacity')}\n      {\n        <div\n          className={classNames({ \"slider-container\": 1, show: showSlider })}\n          ref={sliderRef}\n          onClick={(e) => e.stopPropagation()}\n          style={{ \"--value\": opacity } as CSSProperties}\n          onTransitionEnd={() => {\n            if (showSlider && sliderRef.current) {\n              sliderRef.current.style.transition = \"none\";\n            }\n          }}\n        >\n          <span\n            className=\"opacity-text\"\n            style={{ \"--value\": opacity } as CSSProperties}\n          >\n            {Math.floor(opacity * 100)}\n            <span>%</span>\n          </span>\n          <input\n            ref={inputRef}\n            type=\"range\"\n            min=\"0\"\n            max=\"1\"\n            step=\"0.001\"\n            value={opacity}\n            onChange={handleSliderChange}\n            className=\"slider\"\n            onClick={(e) => e.stopPropagation()}\n            style={{ \"--value\": opacity , \"--safari\": safari} as CSSProperties}\n            onBlur={() => setShowSlider(false)}\n          />\n        </div>\n      }\n    </div>\n  );\n};\n\nexport default OpacityControl;\n"
  },
  {
    "path": "src/Render/Header/Component/ShapeSelector.scss",
    "content": ".tool {\n    position: relative;\n    display: inline-block;\n    cursor: pointer;\n    perspective: 1000px;\n    perspective-origin: 0 50%;\n\n    &:has(.shape-selector-container) {\n        z-index: 600;\n    }\n\n    .shape-selector-container {\n        .color-detail {\n            .color-detail-choosing {\n                box-sizing: border-box;\n                padding: 10px 10px;\n                width: 222.75px;\n                display: grid;\n                border: white 1px solid;\n                grid-template-columns: repeat(4, 25%);\n                grid-template-rows: repeat(3, 33.33%);\n                // grid-row-gap: 9px;\n                // grid-column-gap: 6px;\n                .shape-container {\n                    height: 46.13px;\n                    display: flex;\n                    justify-content: center;\n                    align-items: center;\n                    border-left: 1px black dotted;\n                    border-bottom: 1px black solid;\n                    transform: translate(-1px, 1px);\n                    cursor: pointer;\n\n                    &.left {\n                        border-left: none;\n                    }\n                    &.bottom {\n                        border-bottom: none;\n                    }\n                    .shape-preview {\n                        width: 19.5px;\n                        height: 19.5px;\n                        // border-radius: 50%;\n                        // border: 2px solid;\n                        display: flex;\n                        justify-content: center;\n                        align-items: center;\n                        &.shape-selected {\n                            svg {\n                                * {\n                                    stroke: #ea0b2a;\n                                }\n                            }\n                        }\n                        &.square {\n                            zoom: 0.9;\n                        }\n                        &.triangle {\n                            zoom: 1.05;\n                        }\n                        &.start {\n                            zoom: 1.15;\n                        }\n                        &.hexagon {\n                            zoom: 0.9;\n                        }\n                        &.pentagon {\n                            zoom: 1.1;\n                        }\n                        &.diamond{\n                            zoom: 1.15;\n                        }\n                        &.leaf{\n                            zoom: 0.9;\n                        }\n                    }\n                }\n            }\n        }\n        transition:\n            transform 0s,\n            transform 0.3s ease-in-out,\n            all 0.3s ease-in-out;\n        &.show {\n            opacity: 1;\n            pointer-events: unset;\n            top: 100%;\n            transform: scale(calc(1 + var(--value) * 0.075)) rotate3d(0, 1, 0, 0deg);\n        }\n        opacity: 0;\n        pointer-events: none;\n        position: absolute;\n        top: 50%;\n        left: 0;\n        margin-top: 8px;\n        background: rgba(255, 255, 255, 0.136);\n        box-shadow: 0 0 100px rgba(#000000, 0.15);\n        // border: #ea0b2a 1px solid;\n        z-index: 600;\n        width: 222.75px;\n        max-width: 100vw;\n        overflow: hidden;\n        height: 162px;\n        border-radius: 5px;\n        backdrop-filter: blur(20px);\n        transform: scale(calc(1 + var(--value) * 0.075)) rotate3d(0, 1, 0, var(--deg));\n        transform-origin: 0 0;\n        .opacity-text {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            margin: auto;\n            pointer-events: none;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            margin-left: 20px;\n            font-size: 14px;\n            opacity: var(--value);\n            span {\n                margin-left: 2px;\n                font-size: 10px;\n                font-weight: 600;\n                vertical-align: baseline;\n                margin-top: 2.5px;\n            }\n        }\n        .slider {\n            appearance: none;\n            width: 100%;\n            height: 100%;\n            appearance: none;\n            margin: 0;\n            background-color: transparent;\n            background-image: repeating-linear-gradient(\n                to right,\n                transparent,\n                transparent calc(18% - 1px),\n                #05051a1c 18%\n            );\n            &::-webkit-slider-thumb {\n                box-shadow: -20rem 0 0 20rem rgba(#ea0b2a, 0.2);\n                cursor: col-resize;\n                background-color: rgba(#ea0b2a, 0.2);\n            }\n\n                @supports not (-webkit-touch-callout: none) {\n                    &::-webkit-slider-thumb {\n                        -webkit-appearance: none;\n                        appearance: none;\n                        width: 0;\n                    }\n                }\n                @supports (-webkit-min-device-pixel-ratio: 0) {\n                    &::-webkit-slider-thumb {\n                        -webkit-appearance: auto;\n                        appearance: auto;\n                        width: auto;\n                    }\n                  }\n\n            \n            &::-webkit-slider-runnable-track {\n                // pointer-events: none;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Header/Component/ShapeSelector.tsx",
    "content": "import React, {\n  useState,\n  useRef,\n  useEffect,\n  CSSProperties,\n  useLayoutEffect,\n  SetStateAction,\n  Dispatch,\n} from \"react\";\nimport \"./ShapeSelector.scss\";\nimport classNames from \"classnames\";\nimport { browserInfo } from \"../../../Common/util\";\nimport shapes from \"../../../Resource/Shape/shape\";\nimport { Shape } from \"../../../Data/Shape\";\nimport { useTranslation } from \"react-i18next\";\ninterface OpacityControlProps {\n  defaultShape: string;\n  setDefaultShape: Dispatch<SetStateAction<string>>;\n}\n\nconst ShapeSelector: React.FC<OpacityControlProps> = ({\n  defaultShape,\n  setDefaultShape,\n}) => {\n  const [showSlider, setShowSlider] = useState(false);\n  const sliderRef = useRef<HTMLDivElement>(null);\n  const toolRef = useRef<HTMLDivElement>(null);\n  const { t } = useTranslation();\n  const handleClick = () => {\n    setShowSlider(!showSlider);\n  };\n\n  useEffect(() => {\n    if (showSlider && sliderRef.current && toolRef.current) {\n      const toolRect = toolRef.current.getBoundingClientRect();\n      const viewportWidth = window.innerWidth;\n\n      if (toolRect.left + 230 > viewportWidth) {\n        sliderRef.current.style.left = \"unset\";\n        sliderRef.current.style.right = \"0\";\n        (sliderRef.current.style as any)[\"--deg\"] = \"-25deg\";\n        sliderRef.current.style.transformOrigin = \"100% 50%\";\n        toolRef.current.style.perspectiveOrigin = \"100% 50%\";\n      } else {\n        sliderRef.current.style.left = \"0\";\n        sliderRef.current.style.transformOrigin = \"0 50%\";\n        toolRef.current.style.perspectiveOrigin = \"0 50%\";\n        (sliderRef.current.style as any)[\"--deg\"] = \"25deg\";\n      }\n    }\n  }, [showSlider]);\n  useLayoutEffect(() => {\n    if (sliderRef.current) {\n      sliderRef.current.style.transition = \"0.3s ease-in-out\";\n    }\n  }, [showSlider]);\n  useEffect(() => {\n    const handleClickCapture = (event: TouchEvent | MouseEvent) => {\n      if (!toolRef.current?.contains(event.target as Node)) {\n        console.log(\"focusout\");\n        setShowSlider(false);\n      }\n    };\n    const resize = () => setShowSlider(false);\n    document.addEventListener(\"touchstart\", handleClickCapture, true);\n    document.addEventListener(\"click\", handleClickCapture, true);\n    document.addEventListener(\"resize\", resize);\n    return () => {\n      document.removeEventListener(\"touchstart\", handleClickCapture, true);\n      document.addEventListener(\"click\", handleClickCapture, true);\n      document.removeEventListener(\"resize\", resize);\n    };\n  }, []);\n  const { engine } = browserInfo;\n  const safari = engine.name === \"WebKit\";\n  const column = 4;\n  const row = 3;\n  const grid = new Array(column * row).fill(0);\n  Object.keys(shapes).forEach((shape, index) => (grid[index] = shape));\n  return (\n    <div className=\"tool\" onClick={handleClick} ref={toolRef}>\n      {\n        t(`shape.${defaultShape}`)\n      }\n      {\n        <div\n          className={classNames({ \"shape-selector-container\": 1, show: showSlider })}\n          ref={sliderRef}\n          onClick={(e) => e.stopPropagation()}\n          style={{} as CSSProperties}\n          onTransitionEnd={() => {\n            if (showSlider && sliderRef.current) {\n              sliderRef.current.style.transition = \"none\";\n            }\n          }}\n        >\n          <div className=\"color-detail\">\n            <div className=\"color-detail-choosing\">\n              {grid.map((shape, index) => {\n                const left = index % column === 0;\n                const bottom = Math.floor(index / column) === row - 1;\n                // console.log({ shape });\n                return (\n                  <div\n                    className={classNames({\n                      \"shape-container\": 1,\n                      left,\n                      bottom,\n                    })}\n                    onClick={() => {\n                      if (shape) setDefaultShape(shape);\n                    }}\n                  >\n                    <div\n                      className={classNames({\n                        \"shape-preview\": 1,\n                        \"shape-selected\": shape === defaultShape,\n                        [shape]: 1,\n                      })}\n                    >\n                      {\n                        //@ts-ignore\n                        shapes[shape]\n                      }\n                    </div>\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n        </div>\n      }\n    </div>\n  );\n};\n\nexport default ShapeSelector;\n"
  },
  {
    "path": "src/Render/Header/Menu.scss",
    "content": ".menu {\n    &.page-menu {\n        position: fixed;\n        top: 0;\n        left: 0;\n        height: 100vh;\n        width: 100vw;\n        z-index: 500;\n        background-color: rgba(255, 255, 255, 0.2);\n        backdrop-filter: blur(10px);\n        .title {\n            .tools {\n                margin-left: -50px;\n                .tool {\n                    margin-left: -5px;\n                    opacity: 0;\n                }\n            }\n        }\n        .dots {\n            width: calc(100vw - 51.6px - 51.6px);\n            transition:\n                0.3s ease-in-out opacity,\n                0.3s ease-in-out width;\n            opacity: 1;\n        }\n        .menus {\n            transition: 0.3s ease-in-out opacity;\n            opacity: 1;\n            .columns {\n                .column {\n                    @media (max-width: 710px) {\n                        margin-top: 28.5px;\n                        opacity: 1;\n                    }\n                }\n            }\n        }\n    }\n\n    &.page-title {\n        // position: fixed;\n        // top: 0;\n        // left: 0;\n        // height: 100vh;\n        // width: 100vw;\n        .title {\n            .click-panel {\n                cursor: pointer;\n            }\n            .tools {\n                margin-left: -50px;\n                .tool {\n                    margin-left: -5px;\n                    opacity: 0;\n                }\n            }\n        }\n        user-select: none;\n        z-index: -500;\n        .dots {\n            margin-top: 100.66px;\n            position: fixed;\n            opacity: 1;\n            width: 0;\n            transition:\n                0.3s ease-in-out opacity,\n                0.3s ease-in-out width;\n        }\n\n        .menus {\n            margin-top: 101.66px;\n            position: fixed;\n            opacity: 0;\n            transition: 0.3s ease-in-out opacity;\n\n            .columns {\n                justify-content: space-between;\n                transition: 0.3s ease-in-out width;\n                width: calc(70vw - 51.6px - 51.6px);\n            }\n        }\n    }\n\n    &.page-tools {\n        .title {\n        }\n        .dots {\n            margin-top: 100.66px;\n            position: fixed;\n            opacity: 1;\n            width: 0;\n            transition:\n                0.3s ease-in-out opacity,\n                0.3s ease-in-out width;\n        }\n        .menus {\n            margin-top: 101.66px;\n            position: fixed;\n            opacity: 0;\n            transition: 0.3s ease-in-out opacity;\n\n            .columns {\n                justify-content: space-between;\n                transition: 0.3s ease-in-out width;\n                width: calc(70vw - 51.6px - 51.6px);\n            }\n        }\n    }\n    .title {\n        position: fixed;\n        margin: 35.5px 0 0 51.6px;\n        z-index: 500;\n        .auto-growth-container {\n            display: inline-block;\n            * {\n                font-size: 36px;\n                font-weight: 1000;\n            }\n            input {\n                // background-color: rgba(255, 255, 255, 0.901);\n                // backdrop-filter: blur(10px);\n                // padding-left: 18px;\n                // margin-left: -18px;\n            }\n        }\n        .tools {\n            @media (max-width: 710px) {\n                // display: block !important;\n                margin-left: -21.77px;\n                .tool {\n                    margin-top: 5px;\n\n                    &:first-child {\n                        // display: none;\n                    }\n                }\n            }\n            display: inline-block;\n            transition: 0.3s ease-in-out;\n            .tool {\n                transition: 0.3s ease-in-out;\n                opacity: 1;\n                display: inline-block;\n                font-size: 18px;\n                font-weight: 500;\n                color: #ea0b2a;\n                &.tool-title{\n                    color: #00A0E8;\n                    cursor:auto;\n                }\n                margin-left: 21.77px;\n                cursor: pointer;\n                &.disabled {\n                    color: #ea0b2a55;\n                    cursor:auto;\n                }\n                svg{\n                    vertical-align: text-bottom;\n                    line-height: 26px;\n                    height: 26px;\n                    [fill=\"black\"]{\n                        fill: rgba(234, 11, 42, 0.3333333333) !important;\n                        fill-opacity: 1 !important;\n                    }\n                }\n                    \n           \n            }\n        }\n    }\n\n    .dots {\n        // margin-top: 20.16px;\n        border-bottom: dotted black 1px;\n        margin: 100.66px 51.6px 0 51.6px;\n    }\n    .menus {\n        height: calc(100vh - 101px);\n        overflow-y: overlay;\n        overflow-x: hidden;\n        &::-webkit-scrollbar {\n            display: none;\n        }\n        .columns {\n            margin: 0 51.6px 0 51.6px;\n            display: flex;\n            @media (max-width: 710px) {\n                display: grid;\n            }\n            justify-content: space-between;\n            transition: 0.3s ease-in-out width;\n            width: calc(100vw - 51.6px - 51.6px);\n            .column {\n                margin-top: 25.8px;\n                display: inline-block;\n                vertical-align: top;\n                width: 20vw;\n                transition: 0.3s ease-in-out;\n                @media (max-width: 710px) {\n                    width: auto;\n                    margin-top: -15px;\n                    opacity: 0;\n                    &:last-child{\n                        padding-bottom: 150px;\n                    }\n                }\n                .column-title {\n                    font-size: 36px;\n                    font-weight: 300;\n                }\n                .column-items {\n                    // margin-top: 17px;\n\n                    .column-item {\n                        width: fit-content;\n                        margin-top: 17px;\n                        font-size: 18px;\n                        font-weight: 500;\n                        color: #ea0b2a;\n                        cursor: pointer;\n                        &.sub-menu{\n                            margin-top: 10px;\n                            margin-left: 10px;\n                            .sub-item{\n                                margin-right: 10px;\n                            }\n                        }\n                        &.small{\n                            font-size: small;\n                        }\n                        &.author{\n                            margin-top: 4px;\n                            &:hover{\n                                // text-decoration: underline;\n                            }\n                        }\n                        &.friend{\n                            position: relative;\n                            svg{\n                                margin-left: 5px;\n                                position: absolute;\n                                margin-top: 3px;\n                                width: 17px;\n                                // height: 25px;\n                                // vertical-align: bottom;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        .notice{\n            position: fixed;\n            left: 0;\n            bottom: 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Header/Menu.tsx",
    "content": "import React, {\n  Dispatch,\n  SetStateAction,\n  forwardRef,\n  useEffect,\n  useImperativeHandle,\n  useRef,\n  useState,\n} from \"react\";\nimport { ReactComponent as ShareIcon } from \"../../Resource/Icon/share.svg\";\nimport { AutoGrowthInput } from \"../../Common/AutoGrowthInput\";\nimport \"./Menu.scss\";\nimport classNames from \"classnames\";\nimport { FunctionMode, Mode } from \"../../DataStructure/Mode\";\nimport {\n  ChangeSteps,\n  StationProps,\n  UserDataType,\n  addNewStation,\n  addStationFromRecord,\n  deleteStation,\n  dataProcessor,\n  InsertInfo,\n  RecordType,\n  LineChanges,\n  LineProps,\n  ShowNameProps,\n  DrawProps,\n  CardShowing,\n  setDataFromJson,\n  TransformProps,\n  ShowTourProps,\n  PageProps,\n} from \"../../Data/UserData\";\nimport PlusIcon from \"../../Resource/Icon/plus\";\nimport { ReactComponent as GlobeIcon } from \"../../Resource/Icon/globe.svg\";\nimport {\n  browserInfo,\n  calculateTransform,\n  deleteFileFromIndexedDB,\n  exportFile,\n  exportJson,\n  importFromFile,\n  importImage,\n  mediateMap,\n  readFileFromIndexedDB,\n  storeFileInIndexedDB,\n  stringifyData,\n} from \"../../Common/util\";\nimport moment from \"moment\";\n\nimport { toPng, toJpeg, toBlob, toPixelData, toSvg } from \"html-to-image\";\nimport download from \"downloadjs\";\nimport { getExistMap } from \"../../Common/api\";\nimport OpacityControl from \"./Component/OpacityControl\";\nimport ShapeSelector from \"./Component/ShapeSelector\";\nimport { useTranslation } from \"react-i18next\";\nimport i18n from \"../../i18n/config\";\n\ntype MenuType = {\n  setEditingMode: React.Dispatch<React.SetStateAction<Mode>>;\n  functionMode: FunctionMode;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  record: RecordType;\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>;\n  currentRecordIndex: number;\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>;\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n  saved: boolean;\n  setSaved: Dispatch<SetStateAction<boolean>>;\n  defaultShape: string;\n  setDefaultShape: Dispatch<SetStateAction<string>>;\n} & ShowNameProps &\n  DrawProps &\n  TransformProps &\n  ShowTourProps &\n  PageProps;\nexport const Menu = forwardRef(function (\n  {\n    setEditingMode,\n    functionMode,\n    setFunctionMode,\n    record,\n    setRecord,\n    currentRecordIndex,\n    setCurrentRecordIndex,\n    data,\n    setData,\n    insertInfo,\n    setInsertInfo,\n    showName,\n    setShowName,\n    autoHiddenName,\n    setAutoHiddenName,\n    setDrawing,\n    drawing,\n    cardShowing,\n    setCardShowing,\n    scale,\n    setScale,\n    translateX,\n    translateY,\n    setTranslateX,\n    setTranslateY,\n    saved,\n    setSaved,\n    setShowTour,\n    page,\n    setPage,\n    defaultShape,\n    setDefaultShape,\n  }: MenuType,\n  ref\n) {\n  const [titleEditable, setTitleEditable] = useState(false);\n  const [display, setDisplay] = useState(\"none\");\n  const inputRef = useRef<HTMLInputElement>(null);\n  const [toolsDisPlay, setToolsDisPlay] = useState(\"none\");\n  const [selectedMap, setSelectedMap] = useState<string>();\n  const [originalMap, setOriginalMap] = useState<UserDataType>();\n  const [mapData, setMapData] = useState<Map<string, UserDataType>>(new Map());\n  const undoCondition = currentRecordIndex >= 0;\n  const redoCondition = currentRecordIndex < record.length - 1;\n  const { title } = data;\n  const { t } = useTranslation();\n  const setTitle = (title: string) => setData({ ...data, title });\n  const backToTitle = () => {\n    setPage(\"title\");\n    setTitleEditable(false);\n    setFunctionMode(FunctionMode.normal);\n    setDrawing(false);\n  };\n  const { engine } = browserInfo;\n  const showTools = (e: React.MouseEvent, functionMode: FunctionMode) => {\n    e.stopPropagation();\n    setRecord([]);\n    setCurrentRecordIndex(-1);\n    setFunctionMode(functionMode);\n    setTitleEditable(false);\n    setToolsDisPlay(window.innerWidth >= 710 ? \"inline-block\" : \"block\");\n    setTimeout(() => setPage(\"tools\"));\n  };\n  const importImageClick = (e: React.MouseEvent) => {\n    importImage()\n      .then((file) => {\n        if (file) {\n          calculateTransform(file).then(\n            ({ translateX: x, translateY: y, scale: s }) => {\n              showTools(e, FunctionMode.editingCustomBackgroundPosition);\n              setData((data) => ({\n                ...data,\n                // backgroundColor: \"image\",\n                backgroundImage: file,\n                translateX: (x - translateX) / scale,\n                translateY: (y - translateY) / scale,\n                scale: s / scale,\n              }));\n              storeFileInIndexedDB(file, \"image\");\n            }\n          );\n\n          console.log(\"图片 Blob 对象:\", file);\n        } else {\n          console.log(\"未选择图片\");\n        }\n      })\n      .catch((error) => {\n        console.error(\"导入图片时出错:\", error);\n      });\n  };\n  const transfromTools = {\n    scale,\n    setScale,\n    translateX,\n    translateY,\n    setTranslateX,\n    setTranslateY,\n  };\n  useEffect(() => {\n    mediateMap(data, transfromTools);\n  }, []);\n  useImperativeHandle(\n    ref,\n    () => {\n      return {\n        backToTitle,\n        showTools,\n      };\n    },\n    []\n  );\n\n  const tools = () => {\n    switch (functionMode) {\n      case FunctionMode.addingStation: {\n        const stationRecords = record as StationProps[];\n        return (\n          <>\n            <div className=\"tool disabled\">\n              {currentRecordIndex >= 0\n                ? t(\"menu.alreadyAddStations\", {\n                    count: currentRecordIndex + 1,\n                  })\n                : t(\"menu.clickBlankToAddStation\")}\n            </div>\n            <ShapeSelector\n              defaultShape={defaultShape}\n              setDefaultShape={setDefaultShape}\n            />\n            <div\n              className={classNames({ tool: 1, disabled: !undoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (undoCondition) {\n                  const station = stationRecords[currentRecordIndex];\n                  const { stationId } = station;\n                  deleteStation(data, setData, stationId);\n                  setCurrentRecordIndex(currentRecordIndex - 1);\n                }\n              }}\n            >\n              {t(\"menu.withdraw\")}\n            </div>\n            <div\n              className={classNames({ tool: 1, disabled: !redoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (redoCondition) {\n                  const station = stationRecords[currentRecordIndex + 1];\n                  addStationFromRecord(data, setData, station);\n                  setCurrentRecordIndex(currentRecordIndex + 1);\n                }\n              }}\n            >\n              {t(\"menu.redo\")}\n            </div>\n            <div\n              className=\"tool\"\n              id=\"add-station-finish-btn\"\n              onClick={() => {\n                setPage(\"title\");\n                setTitleEditable(false);\n              }}\n            >\n              {t(\"menu.done\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.dragingStation: {\n        const changeRecords = record as ChangeSteps[];\n        return (\n          <>\n            <div className=\"tool disabled\">\n              {currentRecordIndex >= 0\n                ? t(\"menu.alreadyModified\", { count: currentRecordIndex + 1 })\n                : t(\"menu.dragToChangePoistion\")}\n            </div>\n            <div\n              className={classNames({ tool: 1, disabled: !undoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (undoCondition) {\n                  const change = changeRecords[currentRecordIndex];\n                  const { stationId, fromX, fromY } = change;\n                  const { setStationPosition } = dataProcessor(\n                    stationId,\n                    setData,\n                    data\n                  );\n                  setStationPosition(fromX, fromY);\n                  setCurrentRecordIndex(currentRecordIndex - 1);\n                }\n              }}\n            >\n              {t(\"menu.withdraw\")}\n            </div>\n            <div\n              className={classNames({ tool: 1, disabled: !redoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (redoCondition) {\n                  const change = changeRecords[currentRecordIndex + 1];\n                  const { stationId, toX, toY } = change;\n                  const { setStationPosition } = dataProcessor(\n                    stationId,\n                    setData,\n                    data\n                  );\n                  setStationPosition(toX, toY);\n                  setCurrentRecordIndex(currentRecordIndex + 1);\n                }\n              }}\n            >\n              {t(\"menu.redo\")}\n            </div>\n            <div\n              className=\"tool\"\n              onClick={() => {\n                setPage(\"title\");\n                setTitleEditable(false);\n              }}\n            >\n              {t(\"menu.done\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.lineEditing: {\n        return (\n          <>\n            <div className=\"tool disabled\">\n              {t(\"menu.chooseALineFirst\")}“\n              <PlusIcon className=\"tool-plus\" />”\n            </div>\n            <div\n              className=\"tool\"\n              onClick={() => {\n                setPage(\"title\");\n                setTitleEditable(false);\n              }}\n            >\n              {t(\"menu.done\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.backgroundEditing: {\n        const { backgroundColor = \"#ffffff\", backgroundImage } = data;\n        const setColor = (color: string) =>\n          {setData((data) => ({ ...data, backgroundColor: color }));\n      };\n        return (\n          <>\n            <div className=\"tool disabled\">{t(\"menu.backgroudSetting\")}</div>\n            <div\n              className={classNames({\n                tool: 1,\n                disabled: backgroundColor === \"#ffffff\",\n              })}\n              onClick={() => setColor(\"#ffffff\")}\n            >\n              {t(\"menu.white\")}\n            </div>\n            <div\n              className={classNames({\n                tool: 1,\n                disabled: backgroundColor === \"#fffee0\",\n              })}\n              onClick={() => setColor(\"#fffee0\")}\n            >\n              {t(\"menu.lightYellow\")}\n            </div>\n            <div\n              className={classNames({\n                tool: 1,\n                disabled: backgroundColor === \"transparent\",\n              })}\n              onClick={() => setColor(\"transparent\")}\n            >\n              {t(\"menu.transparent\")}\n            </div>\n            <div className=\"tool\">\n              <input\n                className=\"color-input\"\n                type=\"color\"\n                value={backgroundColor}\n                onInput={(e) => setColor(e.currentTarget.value)}\n              />\n            </div>\n            {backgroundImage ? (\n              <div\n                className=\"tool\"\n                onClick={(e) => {\n                  showTools(e, FunctionMode.editingCustomBackgroundPosition);\n                }}\n              >\n                {t(\"menu.changeBackgroudImage\")}...\n              </div>\n            ) : (\n              <div className=\"tool\" onClick={importImageClick}>\n                {t(\"menu.importBackgroudImage\")}...\n              </div>\n            )}\n            <div\n              className=\"tool\"\n              onClick={() => {\n                setPage(\"title\");\n                setTitleEditable(false);\n              }}\n            >\n              {t(\"menu.done\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.customBackground:\n      case FunctionMode.editingCustomBackgroundPosition: {\n        const { backgroundColor, backgroundImage, opacity = 1 } = data;\n        const setColor = (color: string) =>\n          setData((data) => ({ ...data, backgroundColor: color }));\n        const setOpacity = (opacity: number) =>\n          setData((data) => ({ ...data, opacity }));\n        return (\n          <>\n            <div className=\"tool disabled\">\n              {t(\"menu.backgroudSetting\")} / {t(\"menu.changeBackgroudImage\")}\n            </div>\n            <div className=\"tool\" onClick={importImageClick}>\n              {t(\"menu.importImage\")}\n            </div>\n            <OpacityControl opacity={opacity} setOpacity={setOpacity} />\n            {/* \n            {functionMode === FunctionMode.editingCustomBackgroundPosition ? (\n              <div className=\"tool\" onClick={(e) => showTools(e, FunctionMode.customBackground)}>调整地图</div>\n            ) : (\n              <div className={classNames({ tool: 1, disabled: !backgroundImage })} onClick={(e) => showTools(e, FunctionMode.editingCustomBackgroundPosition)}>调整位置与缩放</div>\n            )} */}\n\n            <div\n              className={classNames({ tool: 1, disabled: !backgroundImage })}\n              onClick={(e) => {\n                showTools(e, FunctionMode.customBackground);\n                setData((data) => ({\n                  ...data,\n                  backgroundImage: undefined,\n                }));\n                deleteFileFromIndexedDB(\"image\");\n              }}\n            >\n              {t(\"menu.deleteImage\")}\n            </div>\n            <div\n              className=\"tool\"\n              onClick={(e) => showTools(e, FunctionMode.backgroundEditing)}\n            >\n              {t(\"menu.back\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.selectingStation: {\n        const { insertIndex, line } = insertInfo!;\n        const { lineName } = line;\n        const changeRecords = record as LineChanges[];\n\n        return (\n          <>\n            <div className=\"tool disabled\">\n              {t(\"menu.clickAddStationToLine\", {\n                lineName,\n                insertIndex: insertIndex + 1,\n              })}\n            </div>\n            <div\n              className={classNames({ tool: 1, disabled: !undoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (undoCondition) {\n                  const change = changeRecords[currentRecordIndex];\n                  const { stationId, lineId, stationIndex } = change;\n                  const { removeStationFromLine } = dataProcessor(\n                    stationId,\n                    setData,\n                    data\n                  );\n                  removeStationFromLine(lineId, stationIndex);\n                  setInsertInfo({\n                    insertIndex: insertIndex === 0 ? 0 : insertIndex - 1,\n                    line,\n                  });\n                  setCurrentRecordIndex(currentRecordIndex - 1);\n                }\n              }}\n            >\n              {t(\"menu.withdraw\")}\n            </div>\n            <div\n              className={classNames({ tool: 1, disabled: !redoCondition })}\n              onClick={(e) => {\n                e.stopPropagation();\n                if (redoCondition) {\n                  const change = changeRecords[currentRecordIndex + 1];\n                  const { stationId, lineId, stationIndex } = change;\n                  const { addStationToLine } = dataProcessor(\n                    lineId,\n                    setData,\n                    data\n                  );\n                  addStationToLine(stationId, stationIndex);\n                  setCurrentRecordIndex(currentRecordIndex + 1);\n                  setInsertInfo({\n                    insertIndex: insertIndex === 0 ? 0 : insertIndex + 1,\n                    line,\n                  });\n                }\n              }}\n            >\n              {t(\"menu.redo\")}\n            </div>\n            <div\n              className=\"tool\"\n              id=\"add-line-finish-btn\"\n              onClick={() => {\n                setPage(\"title\");\n                setTitleEditable(false);\n                setInsertInfo({ insertIndex: -1, line });\n              }}\n            >\n              {t(\"menu.done\")}\n            </div>\n          </>\n        );\n      }\n      case FunctionMode.choosingExistMap: {\n        const existingMap = [\n          { name: t(\"shang-hai\"), id: \"shanghai\", webkit: true },\n          { name: t(\"bei-jing\"), id: \"beijing\" },\n          { name: t(\"guang-zhou\"), id: \"guangzhou\", webkit: true },\n          { name: t(\"shen-zhen\"), id: \"shenzhen\", webkit: true },\n          { name: t(\"xiang-gang\"), id: \"hongkong\", webkit: true },\n          { name: t(\"chang-sha\"), id: \"changsha\", webkit: true },\n          { name: t(\"tian-jin\"), id: \"tianjing\", webkit: true },\n        ];\n        const webkit = engine.name === \"WebKit\";\n        return (\n          <>\n            <div className=\"tool disabled\">{t(\"menu.chooseAMap\")}</div>\n            {existingMap\n              .filter((x) => (webkit ? x.webkit : true))\n              .map(({ name, id }) => {\n                return (\n                  <div\n                    onClick={async () => {\n                      let data = mapData.get(id);\n                      if (!data) {\n                        const res = await getExistMap(id);\n                        data = setDataFromJson(setData, res);\n                        mapData.set(id, data);\n                      }\n                      setData({ ...data, title });\n                      mediateMap(data, transfromTools);\n                      setSelectedMap(id);\n                    }}\n                    className={classNames({\n                      tool: 1,\n                      disabled: selectedMap !== id,\n                      [id]: 1,\n                    })}\n                  >\n                    {name}\n                  </div>\n                );\n              })}\n\n            {selectedMap ? (\n              <div\n                className=\"tool confirm-add-from-existed-map-btn\"\n                onClick={() => {\n                  setPage(\"title\");\n                  setTitleEditable(false);\n                  const data = mapData.get(selectedMap!);\n                  if (data) setData(data);\n                }}\n              >\n                {t(\"menu.useTemplate\", {\n                  name: existingMap.find((x) => x.id === selectedMap)?.name,\n                })}\n              </div>\n            ) : (\n              <></>\n            )}\n            <div\n              className=\"tool\"\n              onClick={() => {\n                setData(originalMap!);\n                mediateMap(originalMap!, transfromTools);\n                setPage(\"title\");\n                setTitleEditable(false);\n              }}\n            >\n              {t(\"menu.cancel\")}\n            </div>\n          </>\n        );\n      }\n    }\n  };\n\n  useEffect(() => {\n    if (drawing) {\n      toPng(document.querySelector(\".transform-layer\")! as HTMLElement).then(\n        (dataUrl) => {\n          setDrawing(false);\n          download(\n            dataUrl,\n            `${title}-${moment().format(\"YYYY-MM-DD_HH-mm-ss\")}.png`\n          );\n        }\n      );\n    }\n  }, [drawing]);\n\n  return (\n    <div\n      className={classNames({ menu: 1, [`page-${page}`]: 1 })}\n      onClick={backToTitle}\n      onTransitionEnd={() => {\n        if (page === \"title\" || page === \"tools\") setDisplay(\"none\");\n      }}\n    >\n      <div className=\"title\" onClick={(e) => e.stopPropagation()}>\n        <AutoGrowthInput\n          value={title}\n          onClick={(e) => {\n            e.stopPropagation();\n            if (page === \"title\" || page === \"tools\") {\n              setDisplay(\"block\");\n              setTimeout(() => setPage(\"menu\"));\n              setTitleEditable(true);\n            }\n          }}\n          onInput={(e) => setTitle(e.currentTarget.value)}\n          ref={inputRef}\n          style={{\n            cursor:\n              page === \"title\"\n                ? \"pointer\"\n                : page === \"tools\"\n                ? \"default\"\n                : titleEditable\n                ? \"auto\"\n                : \"default\",\n          }}\n          disabled={!titleEditable}\n        />\n\n        <div\n          className=\"tools\"\n          style={{ display: toolsDisPlay }}\n          onTransitionEnd={() => {\n            if (page !== \"tools\") {\n              setToolsDisPlay(\"none\");\n              setFunctionMode(FunctionMode.normal);\n            }\n          }}\n        >\n          {tools()}\n        </div>\n      </div>\n\n      <div className=\"dots\" style={{ display }}></div>\n      <div className=\"menus\" style={{ display }}>\n        <div className=\"columns\">\n          <div className=\"column\">\n            <div className=\"column-title\">{t(\"menu.station\")}</div>\n            <div className=\"column-items\">\n              <div\n                id=\"menu-add-station\"\n                className=\"column-item\"\n                onClick={(e) => showTools(e, FunctionMode.addingStation)}\n              >\n                {t(\"menu.addStation\")}...\n              </div>\n              <div\n                className=\"column-item\"\n                onClick={(e) => showTools(e, FunctionMode.dragingStation)}\n              >\n                {t(\"menu.changeStationPosition\")}...\n              </div>\n              <div\n                className=\"column-item\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  setShowName(!showName);\n                }}\n              >\n                {showName ? t(\"menu.hidden\") : t(\"menu.show\")}\n                {t(\"menu.stationName\")}...\n              </div>\n              {showName ? (\n                <div\n                  className=\"column-item auto-hidden-btn\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setAutoHiddenName(!autoHiddenName);\n                  }}\n                >\n                  {autoHiddenName ? t(\"menu.turnOff\") : t(\"menu.turnOn\")}\n                  {t(\"menu.AutoHidden\")}...\n                </div>\n              ) : (\n                <></>\n              )}\n            </div>\n          </div>\n          <div className=\"column\">\n            <div className=\"column-title\">{t(\"menu.line\")}</div>\n            <div className=\"column-items\">\n              <div\n                className=\"column-item\"\n                onClick={(e) => showTools(e, FunctionMode.lineEditing)}\n              >\n                {t(\"menu.insertStation\")}\n              </div>\n              <div\n                className=\"column-item\"\n                onClick={() => {\n                  mediateMap(data, transfromTools);\n                }}\n              >\n                {t(\"menu.mediateMap\")}\n              </div>\n              <div\n                className=\"column-item\"\n                onClick={(e) => showTools(e, FunctionMode.backgroundEditing)}\n              >\n                {t(\"menu.addBackgroundImage\")}\n              </div>\n            </div>\n          </div>\n          <div className=\"column\">\n            <div className=\"column-title\">{t(\"menu.data\")}</div>\n            <div className=\"column-items\">\n              <div\n                className=\"column-item new-map-btn\"\n                onClick={(e) => {\n                  const current = localStorage.getItem(\"current\");\n                  if (current && !saved)\n                    exportJson(\n                      current!,\n                      `${title}-autosave-${moment().format(\n                        \"YYYY-MM-DD_HH-mm-ss\"\n                      )}.json`\n                    );\n                  setData({\n                    stations: new Map(),\n                    lines: new Map(),\n                    title: t(\"menu.newMap\"),\n                  });\n                  showTools(e, FunctionMode.addingStation);\n                }}\n              >\n                {t(\"menu.addNewMap\")}\n              </div>\n              <div\n                className=\"column-item existed-map-btn\"\n                onClick={(e) => {\n                  setSelectedMap(\"\");\n                  setOriginalMap(data);\n                  showTools(e, FunctionMode.choosingExistMap);\n                }}\n              >\n                {t(\"menu.addFromTemplate\")}\n              </div>\n              <div\n                className=\"column-item import-file-btn\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  importFromFile().then((res) => {\n                    const data = setDataFromJson(setData, res);\n                    mediateMap(data, transfromTools);\n                  });\n                }}\n              >\n                {t(\"menu.importFile\")}\n              </div>\n              {engine.name === \"WebKit\" ? (\n                <></>\n              ) : (\n                <div\n                  className=\"column-item export-as-image-btn\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setDrawing(true);\n                  }}\n                >\n                  {t(\"menu.exportAsImage\")}\n                </div>\n              )}\n\n              <div\n                className=\"column-item export-as-svg-image-btn\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  setDrawing(true);\n                  setTimeout(() => {\n                    toSvg(\n                      document.querySelector(\".transform-layer\")! as HTMLElement\n                    ).then((dataUrl) => {\n                      const svg = decodeURIComponent(\n                        dataUrl.replace(\n                          /data:image\\/svg\\+xml;charset=utf-8,/,\n                          \"\"\n                        )\n                      );\n                      console.log(svg);\n                      exportFile(\n                        svg!,\n                        `${title}-${moment().format(\n                          \"YYYY-MM-DD_HH-mm-ss\"\n                        )}.svg`,\n                        \"image/svg+xml\"\n                      );\n                    });\n                  }, 300);\n                }}\n              >\n                {t(\"menu.exportAsSVG\")}\n              </div>\n              <div\n                className=\"column-item export-as-file-btn\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  const current = stringifyData(data);\n                  setSaved(true);\n                  exportJson(\n                    current!,\n                    `${title}-${moment().format(\"YYYY-MM-DD_HH-mm-ss\")}.json`\n                  );\n                }}\n              >\n                {t(\"menu.exportAsFile\")}\n              </div>\n              <div\n                className=\"column-item recover-btn\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  const current = localStorage.getItem(\"current\");\n                  if (current) {\n                    const data = setDataFromJson(setData, current);\n                    readFileFromIndexedDB(\"image\")\n                      .then((file) => {\n                        setData((data) => ({\n                          ...data,\n                          // backgroundColor: \"image\",\n                          backgroundImage: file as File,\n                        }));\n                      })\n                      .catch((e) => {\n                        console.error(e);\n                      });\n\n                    mediateMap(data, transfromTools);\n                  }\n                }}\n              >\n                {t(\"menu.recoverData\")}\n              </div>\n              <div\n                className=\"column-item export-recover-btn\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  const current = localStorage.getItem(\"last\");\n                  exportJson(\n                    current!,\n                    `${title}-recovery-${moment().format(\n                      \"YYYY-MM-DD_HH-mm-ss\"\n                    )}.json`\n                  );\n                }}\n              >\n                {t(\"menu.exportRecoveryData\")}\n              </div>\n            </div>\n          </div>\n\n          <div className=\"column\">\n            <div className=\"column-title\">{t(\"menu.about\")}</div>\n            <div className=\"column-items\">\n              <div\n                className=\"column-item\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  window.open(\n                    \"https://github.com/RyanEdo/mini-metro-web\",\n                    \"_blank\"\n                  );\n                }}\n              >\n                {t(\"menu.projectAddress\")}\n              </div>\n              <div\n                className=\"column-item tour-btn\"\n                onClick={(e) => {\n                  if (window.innerWidth >= 710) setShowTour(true);\n                  else {\n                    e.stopPropagation();\n                    window.open(\n                      \"https://www.bilibili.com/video/BV1E4421D7Yn/\",\n                      \"_blank\"\n                    );\n                  }\n                }}\n              >\n                {t(\"menu.guide\")}\n              </div>\n              {window.innerWidth >= 710 ? (\n                <div\n                  className=\"column-item tour-btn\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    window.open(\n                      \"https://www.bilibili.com/video/BV1E4421D7Yn/\",\n                      \"_blank\"\n                    );\n                  }}\n                >\n                  {t(\"menu.videoGuild\")}\n                </div>\n              ) : (\n                <></>\n              )}\n              <div\n                className=\"column-item friend\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  console.log(i18n)\n                  i18n.changeLanguage(i18n.language === \"zh-CN\"? \"en-US\": \"zh-CN\");\n                }}\n              >\n                {t(\"menu.switchLanguage\")}...\n                {/* <GlobeIcon /> */}\n              </div>\n              <div\n                className=\"column-item friend\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  window.open(\n                    \"https://railmapgen.org/?utm_source=mini-metro-web\",\n                    \"_blank\"\n                  );\n                }}\n              >\n                {t(\"menu.RMP\")}\n                <ShareIcon />\n              </div>\n\n              <div className=\"column-item small\">{t(\"menu.version\")}1.2.1</div>\n              <div\n                className=\"column-item small author\"\n                onClick={(e) => {\n                  e.stopPropagation();\n                  window.open(\"https://space.bilibili.com/8217854\", \"_blank\");\n                }}\n              >\n                {t(\"menu.author\")}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n});\n"
  },
  {
    "path": "src/Render/Layer/DevelopLayer.scss",
    "content": ".DevelopLayer {\n    .grid {\n        display: grid;\n        grid-template-columns: repeat(100, 100px);\n        grid-template-rows: repeat(50, 100px);\n        .grid-item {\n            border: 1px solid black;\n            height: 100px;\n            width: 100px;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Layer/DevelopLayer.tsx",
    "content": "import React from \"react\";\nimport \"./DevelopLayer.scss\";\nimport { Point } from \"../../DataStructure/Point\";\nimport { Station } from \"../../DataStructure/Station\";\nimport { Line } from \"../../DataStructure/Line\";\nimport LineRender from \"../Component/LineRender\";\nimport { CardShowing } from \"../../Data/UserData\";\n\nfunction DevelopLayer() {\n  // test line and station\n\n  const pointA = new Point(200, 200);\n  const pointB = new Point(300, 300);\n  const pointC = new Point(600, 300);\n  const pointD = new Point(800, 300);\n  const pointE = new Point(200, 400);\n  const pointF = new Point(800, 200);\n  const pointG = new Point(500, 500);\n\n  const A = new Station(pointA);\n  const B = new Station(pointB);\n  B._dev_tag = \"B\";\n  const C = new Station(pointC);\n  const D = new Station(pointD);\n  const E = new Station(pointE);\n  const F = new Station(pointF);\n  const G = new Station(pointG);\n\n  const line1 = new Line();\n  const line3 = new Line();\n  const line8 = new Line();\n  const line9 = new Line();\n\n  line1.linkAll([A, B, C, D]);\n  // line3.linkAll([E, B, C, D, F, E]);\n  line8._dev_tag='line8';\n  line8.linkAll([E, B, C, D]);\n  line9.linkAll([A, E, G,D,F]);\n\n  // console.log(line1, line3, line8);\n  console.log(A, B, C, D, E, F);\n\n\n  const allStationsList = [A, B, C, D, E, F, G];\n  const allLinesList = [line1, line3, line8, line9];\n\n  const renderStations = (allStationsList: Station[]) => {\n    return (\n      <div>\n        {allStationsList.map((station, index) => (\n          <div\n            style={{\n              position: \"absolute\",\n              left: station.position.x,\n              top: station.position.y,\n            }}\n          >\n            {String.fromCharCode(\"A\".charCodeAt(0) + index)}\n          </div>\n        ))}\n      </div>\n    );\n  };\n\n  // const renderLines = (allLinesList: Line[], cardShowing: CardShowing, setCardShowing: Dispatch<SetStateAction<CardShowing>>) => {\n  //   return (\n  //     <div>\n  //       {allLinesList.map((line) => {\n  //         return <LineRender line={line}           cardShowing={cardShowing}\n  //         setCardShowing={setCardShowing}/>;\n  //       })}\n  //     </div>\n  //   );\n  // };\n\n\n  return (\n    <div className=\"DevelopLayer\">\n      {/* <div className=\"grid\">\n        {new Array(100 * 50).fill(1).map((x, index) => (\n          <div className=\"grid-item\">{index}</div>\n        ))}\n      </div> */}\n      {renderStations(allStationsList)}\n      {/* {renderLines(allLinesList)} */}\n\n    </div>\n  );\n}\n\nexport default DevelopLayer;\n"
  },
  {
    "path": "src/Render/Layer/RenderLayer.scss",
    "content": ".station-render {\n  cursor: pointer;\n    .station-shape {\n        height: 30px;\n        width: 30px;\n        // transform: translate(-50%,-50%);\n        display: inline-flex;\n        // align-content: center;\n        justify-content: center;\n        align-items: center;\n        svg {\n            fill: white;\n            // &.square {\n            //     zoom: 0.9;\n            //   }\n            //   &.triangle {\n            //     zoom: 1.05;\n            //   }\n            //   &.start {\n            //     zoom: 1.15;\n            //   }\n            //   &.hexagon {\n            //     zoom: 0.9;\n            //   }\n            //   &.pentagon {\n            //     zoom: 1.1;\n            //   }\n\n            &.shadow{\n              position: absolute;\n              transform: scale(1.5);\n              transform-origin: center;\n              *{\n                fill: inherit;\n                stroke: inherit;\n              }\n            }\n        }\n    }\n    .station-name {\n        display: inline-block;\n        font-size: 18px;\n        font-weight: 500;\n        // font-size: 30px;\n        // font-weight: 1000;\n        vertical-align: top;\n        // margin-left: 5px;\n        white-space: nowrap;\n\n    }\n}\n"
  },
  {
    "path": "src/Render/Layer/RenderLayer.tsx",
    "content": "import React, {\n  CSSProperties,\n  Dispatch,\n  MouseEventHandler,\n  SetStateAction,\n  useEffect,\n  useLayoutEffect,\n  useState,\n} from \"react\";\nimport DevelopLayer from \"./DevelopLayer\";\nimport { LineCard } from \"../Card/LineCard\";\nimport { Cards } from \"../Card/Cards\";\nimport {\n  CardShowing,\n  ChangeSteps,\n  DrawProps,\n  DrawerSize,\n  InsertInfo,\n  LineChanges,\n  LineProps,\n  RecordType,\n  ShowNameProps,\n  StationProps,\n  UserDataType,\n  dataProcessor,\n} from \"../../Data/UserData\";\nimport { Station } from \"../../DataStructure/Station\";\nimport { Point } from \"../../DataStructure/Point\";\nimport { mapToArr } from \"../../Common/util\";\nimport { Line } from \"../../DataStructure/Line\";\nimport LineRender from \"../Component/LineRender\";\nimport shapes, { shapesWithStyle } from \"../../Resource/Shape/shape\";\nimport \"./RenderLayer.scss\";\nimport { FunctionMode, Mode } from \"../../DataStructure/Mode\";\nimport { Direct } from \"../../DataStructure/Direction\";\nimport { clearHandle, getHandleCommand } from \"../../Line/Handle\";\nimport {\n  getAllKeyPoints,\n  getRoundedPoints,\n  generateLineCommand,\n} from \"../../Line/LinePoints\";\nimport classNames from \"classnames\";\ntype RenderProps = {\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  functionMode: FunctionMode;\n  record: RecordType;\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>;\n  currentRecordIndex: number;\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>;\n  translateX: number;\n  translateY: number;\n  scale: number;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n  editingMode: Mode;\n} & ShowNameProps &\n  DrawProps &\n  DrawerSize;\nconst buildStations = (\n  stations: Map<string | number, StationProps>\n): Map<number, Station> => {\n  const stationMap = new Map();\n  mapToArr(stations).forEach((station) => {\n    const { position, stationId } = station;\n    const [x, y] = position;\n    const dStation = new Station(new Point(x, y));\n    dStation.displayStation = station;\n    stationMap.set(stationId, dStation);\n  });\n  return stationMap;\n};\n\nconst buildLines = (\n  lines: Map<string | number, LineProps>,\n  stationMap: Map<number, Station>\n) => {\n  const lineMap = new Map();\n  mapToArr(lines)\n    .sort((a, b) => a.order - b.order)\n    .forEach((line) => {\n      const { stationIds, lineId, bendFirst } = line;\n      const dLine = new Line();\n      dLine.displayLine = line;\n      for (let i = 1; i < stationIds.length; i++) {\n        const B = stationMap.get(stationIds[i - 1])!;\n        const C = stationMap.get(stationIds[i])!;\n\n        dLine.link(B, C, !!bendFirst[i - 1]);\n      }\n      lineMap.set(lineId, dLine);\n    });\n  return lineMap;\n};\n\nconst renderLines = (\n  allLinesList: Line[],\n  cardShowing: CardShowing,\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>,\n  commandMap: Map<Line, string>,\n  data: UserDataType,\n  setData: Dispatch<SetStateAction<UserDataType>>,\n  { drawing, setDrawing }: DrawProps,\n  { drawerX, drawerY }: DrawerSize\n) => {\n  return (\n    <div>\n      {allLinesList.map((line) => {\n        const command = commandMap.get(line);\n        return (\n          <LineRender\n            command={command!}\n            line={line}\n            cardShowing={cardShowing}\n            setCardShowing={setCardShowing}\n            data={data}\n            setData={setData}\n            drawing={drawing}\n            setDrawing={setDrawing}\n            drawerX={drawerX}\n            drawerY={drawerY}\n          />\n        );\n      })}\n    </div>\n  );\n};\n\nfunction RenderLayer({\n  data,\n  setData,\n  functionMode,\n  setFunctionMode,\n  record,\n  setRecord,\n  currentRecordIndex,\n  setCurrentRecordIndex,\n  translateX,\n  translateY,\n  scale,\n  insertInfo,\n  setInsertInfo,\n  cardShowing,\n  setCardShowing,\n  editingMode,\n  showName,\n  setShowName,\n  autoHiddenName,\n  setAutoHiddenName,\n  drawing,\n  setDrawing,\n  drawerX,\n  drawerY,\n}: RenderProps) {\n  const { lines, stations } = data;\n  const stationMap = buildStations(stations);\n  const lineMap = buildLines(lines, stationMap);\n  const allStationsList = mapToArr(stationMap);\n  const allLinesList = mapToArr(lineMap);\n  const [mouseDown, setMouseDown] = useState(false);\n  const [stationBeingDrag, setStationBeingDrag] = useState<Station>();\n  const mouseUp = (e: Event) => {\n    setMouseDown(false);\n    if (stationBeingDrag) {\n      const { displayStation, position } = stationBeingDrag;\n      const { stationId } = displayStation!;\n      const { x: fromX, y: fromY } = position;\n      const { setStationPosition } = dataProcessor(stationId, setData, data);\n      if (functionMode === FunctionMode.dragingStation && mouseDown) {\n        const { clientX, clientY } = e as MouseEvent;\n        const toX = (clientX - translateX) / scale;\n        const toY = (clientY - translateY) / scale;\n        setStationPosition(toX, toY);\n        const newRecord = record.slice(\n          0,\n          currentRecordIndex + 1\n        ) as ChangeSteps[];\n        setRecord(newRecord.concat([{ stationId, fromX, fromY, toX, toY }]));\n        setCurrentRecordIndex(currentRecordIndex + 1);\n      }\n      setStationBeingDrag(undefined);\n    }\n  };\n  const mouseMove = (e: Event) => {\n    if (stationBeingDrag) {\n      const { displayStation } = stationBeingDrag;\n      const { stationId } = displayStation!;\n      const { setStationPosition } = dataProcessor(stationId, setData, data);\n      if (functionMode === FunctionMode.dragingStation && mouseDown) {\n        setCardShowing({ stationIds: [stationId] });\n        const { clientX, clientY } = e as MouseEvent;\n        const x = (clientX - translateX) / scale;\n        const y = (clientY - translateY) / scale;\n        setStationPosition(x, y);\n      }\n    }\n  };\n\n  const touchMove = (e: Event) => {\n    if (stationBeingDrag) {\n      const { displayStation } = stationBeingDrag;\n      const { stationId } = displayStation!;\n      const { setStationPosition } = dataProcessor(stationId, setData, data);\n      if (functionMode === FunctionMode.dragingStation && mouseDown) {\n        const { touches } = e as TouchEvent;\n        if (touches.length === 1) {\n          e.stopPropagation();\n          const touch = touches[0];\n          const { clientX, clientY } = touch;\n          console.log(clientX, clientY);\n          const x = (clientX - translateX) / scale;\n          const y = (clientY - translateY) / scale;\n          setStationPosition(x, y);\n        }\n      }\n    }\n  };\n\n  const touchEnd = (e: Event) => {\n    setMouseDown(false);\n    if (stationBeingDrag) {\n      const { displayStation, position } = stationBeingDrag;\n      const { stationId } = displayStation!;\n      const { x: fromX, y: fromY } = position;\n      const { setStationPosition } = dataProcessor(stationId, setData, data);\n      if (functionMode === FunctionMode.dragingStation && mouseDown) {\n        const { changedTouches } = e as TouchEvent;\n        if (changedTouches.length === 1) {\n          e.stopPropagation();\n          const touch = changedTouches[0];\n          const { clientX, clientY } = touch;\n          const toX = (clientX - translateX) / scale;\n          const toY = (clientY - translateY) / scale;\n          console.log(\"touch end:\", clientX, clientY);\n          setStationPosition(toX, toY);\n          const newRecord = record.slice(\n            0,\n            currentRecordIndex + 1\n          ) as ChangeSteps[];\n          setRecord(newRecord.concat([{ stationId, fromX, fromY, toX, toY }]));\n          setCurrentRecordIndex(currentRecordIndex + 1);\n        }\n      }\n      setStationBeingDrag(undefined);\n    }\n  };\n \n  useEffect(() => {\n    const scaleLayer = document.querySelector(\".ScaleLayer\");\n    scaleLayer?.addEventListener(\"mouseup\", mouseUp);\n    scaleLayer?.addEventListener(\"mouseleave\", mouseUp);\n    scaleLayer?.addEventListener(\"mousemove\", mouseMove);\n    scaleLayer?.addEventListener(\"touchmove\", touchMove);\n    scaleLayer?.addEventListener(\"touchend\", touchEnd);\n    return () => {\n      scaleLayer?.removeEventListener(\"mouseup\", mouseUp);\n      scaleLayer?.removeEventListener(\"mouseleave\", mouseUp);\n      scaleLayer?.removeEventListener(\"mousemove\", mouseMove);\n      scaleLayer?.removeEventListener(\"touchmove\", touchMove);\n      scaleLayer?.removeEventListener(\"touchend\", touchEnd);\n    };\n  }, [stationBeingDrag]);\n  const [moved, setMoved] = useState(false);\n  const operationStart = (\n    e: React.MouseEvent | React.TouchEvent,\n    station: Station\n  ) => {\n    setMoved(false);\n    if (functionMode === FunctionMode.dragingStation) {\n      e.stopPropagation();\n      setMouseDown(true);\n      setStationBeingDrag(station);\n    }\n  };\n  const renderStations = (allStationsList: Station[]) => {\n    return (\n      <div>\n        {allStationsList.map((station, index) => {\n          const { displayStation, position } = station;\n          const { x, y } = position;\n          const {\n            stationName,\n            shape,\n            stationId,\n            lineIds: stationLineIds,\n            tagDirection,\n          } = displayStation!;\n          const  descend = stations.size - index;\n          const add = async () => {\n            if (!moved) setCardShowing({ stationIds: [stationId] });\n            if (functionMode === FunctionMode.selectingStation) {\n              const { insertIndex, line } = insertInfo!;\n              const { lineId } = line;\n              const { addStationToLine } = dataProcessor(lineId, setData, data);\n              const added = await addStationToLine(stationId, insertIndex);\n              console.log(insertIndex);\n              if(added)\n              setInsertInfo({\n                insertIndex: insertIndex ? insertIndex + 1 : 0,\n                line,\n              });\n              const newRecord = record.slice(\n                0,\n                currentRecordIndex + 1\n              ) as LineChanges[];\n              setRecord(\n                newRecord.concat([\n                  { stationId, lineId, stationIndex: insertIndex },\n                ])\n              );\n              setCurrentRecordIndex(currentRecordIndex + 1);\n              setCardShowing({ stationIds: [stationId], lineIds: [lineId] });\n\n              // setFunctionMode(FunctionMode.lineEditing);\n            }\n          };\n          let nameDirection: Direct = station.getBestDirectionForName();\n          if (tagDirection || tagDirection === 0) nameDirection = tagDirection;\n          const SQRT1_2 = Math.SQRT1_2;\n          const directionOffset = [\n            [0, -1],\n            [SQRT1_2, -SQRT1_2],\n            [1, 0],\n            [SQRT1_2, SQRT1_2],\n            [0, 1],\n            [-SQRT1_2, SQRT1_2],\n            [-1, 0],\n            [-SQRT1_2, -SQRT1_2],\n          ];\n          const k = 20; // distance from station to name\n          const namePosition = directionOffset[nameDirection];\n          const [dX, dY] = namePosition;\n          const nameX = dX * k + x;\n          const nameY = dY * k + y;\n          const translate = [\n            [-1, -2],\n            [0, -2],\n            [0, -1],\n            [0, 0],\n            [-1, 0],\n            [-2, 0],\n            [-2, -1],\n            [-2, -2],\n          ];\n          const [tX, tY] = translate[nameDirection];\n          const { lineIds, stationIds } = cardShowing;\n          const emphasis = stationIds?.includes(stationId);\n          const getEmphasisColor = (lineIds?: number[]) =>\n            Array.isArray(lineIds) &&\n            lineIds.length &&\n            lines.get(lineIds[0])?.color;\n          const emphasisColor =\n            getEmphasisColor(lineIds) ||\n            getEmphasisColor(stationLineIds) ||\n            \"#00000055\";\n          const nameStyle: CSSProperties = {\n            position: \"absolute\",\n            left: nameX,\n            top: nameY,\n            transform: `translate(${50 * tX}%,${50 * tY}%)`,\n          };\n          return (\n            <div\n              id={`station-${stationId}`}\n              onMouseDown={(e) => operationStart(e, station)}\n              onTouchStart={(e) => operationStart(e, station)}\n              className={classNames({ \"station-render\": 1 , [`station-trigger-descend-${descend}`]:  1})}\n              onTouchMove={() => setMoved(true)}\n              onMouseMove={() => setMoved(true)}\n              onTouchEnd={add}\n              onClick={add}\n            >\n              <div\n                className={classNames({\n                  \"station-shape\": 1,\n                  [`station-descend-${descend}`]:  1,\n                })}\n                style={{\n                  position: \"absolute\",\n                  left: station.position.x - 15,\n                  top: station.position.y - 15,\n                  whiteSpace: \"nowrap\",\n                }}\n              >\n                {emphasis && //@ts-ignore\n                  shapesWithStyle(\n                    {\n                      fill: emphasisColor,\n                      stroke: emphasisColor,\n                      // width: 31,\n                      // height: 31\n                    },\n                    \"shadow\"\n                  )[shape]}\n\n                {\n                  //@ts-ignore\n                  shapesWithStyle({ zIndex: 100 })[shape]\n                }\n              </div>\n              <div\n                className={classNames({\n                  \"station-name\": 1,\n                  [`station-name-descend-${descend}`]:  1,\n                })}\n                style={\n                  showName\n                    ? autoHiddenName\n                      ? scale < 0.65\n                        ? { display: \"none\" }\n                        : nameStyle\n                      : nameStyle\n                    : { display: \"none\" }\n                }\n                // style={{transform: `scale(${1/scale})`}}\n              >\n                {stationName}\n              </div>\n              {/* {String.fromCharCode(\"A\".charCodeAt(0) + index)} */}\n            </div>\n          );\n        })}\n      </div>\n    );\n  };\n  const commandMap = new Map<Line, string>();\n  allLinesList.map((line: Line) => {\n    const { displayLine } = line;\n    const { color, lineId, subLine } = displayLine!;\n    let command = \"\",\n      allKeyPoints: Point[] = [];\n    if (line.departureRecord?.nextLineRecord) {\n      allKeyPoints = getAllKeyPoints(line);\n      clearHandle(line);\n      const { startHandleCommand, LQLPoints, endHandleCommand } =\n        getHandleCommand(line, allKeyPoints);\n      const roundedPoints = getRoundedPoints(LQLPoints);\n      const pathCommand = generateLineCommand(roundedPoints);\n      command = startHandleCommand + pathCommand + endHandleCommand;\n      commandMap.set(line, command);\n    }\n  });\n  const stationComp = renderStations(allStationsList);\n  const lineComp = renderLines(\n    allLinesList,\n    cardShowing,\n    setCardShowing,\n    commandMap,\n    data,\n    setData,\n    { drawing, setDrawing },\n    { drawerX, drawerY }\n  );\n  const [debugError, setDebugError] = useState(false);\n  //@ts-ignore\n  window.throwError = () => {\n    setDebugError(true);\n  }\n  if(debugError){\n    throw new Error();\n  }\n  return (\n    <div className=\"RenderLayer\">\n      {lineComp}\n      {stationComp}\n      {/* <DevelopLayer /> */}\n    </div>\n  );\n}\n\nexport default RenderLayer;\n"
  },
  {
    "path": "src/Render/Layer/ScaleLayer.scss",
    "content": " .ScaleLayer{\n   width: 100vw;\n   height: 100vh;\n   overflow: hidden;\n   .layer-for-welcome-tour{\n    position: fixed;\n    z-index: -500;\n    width: 70vw;\n    height: 70vh;\n    left: 15vw;\n    top: 15vw;\n   }\n    .transform-layer{\n        transform-origin: left top;\n        // never use will-change here, it makes child elements blurry\n        // will-change: transform;\n    }\n\n    .background-layer{\n        position: absolute;\n        pointer-events: none;\n        transform-origin: left top;\n        appearance: none;\n        border: none;\n        box-shadow: none;\n        border-image-width: 0;\n\n        &:not([src]) {\n            opacity: 0 !important;\n        }\n    }\n}"
  },
  {
    "path": "src/Render/Layer/ScaleLayer.tsx",
    "content": "import React, {\n  CSSProperties,\n  Dispatch,\n  SetStateAction,\n  useMemo,\n  useState,\n} from \"react\";\nimport { FunctionMode, Mode } from \"../../DataStructure/Mode\";\nimport RenderLayer from \"./RenderLayer\";\nimport {\n  onMouseDown,\n  onMouseLeave,\n  onMouseMove,\n  onMouseUp,\n  onTouchEnd,\n  onTouchMove,\n  onTouchStart,\n  onWheel,\n} from \"../../Grid/Scale\";\nimport \"./ScaleLayer.scss\";\nimport { getCursor } from \"../../Style/Cursor\";\nimport { Point } from \"../../DataStructure/Point\";\nimport {\n  CardShowing,\n  ChangeSteps,\n  DrawProps,\n  InsertInfo,\n  PageProps,\n  RecordType,\n  ShowNameProps,\n  StationProps,\n  TransformProps,\n  UserDataType,\n} from \"../../Data/UserData\";\nimport { browserInfo, getBoundary, mapToArr } from \"../../Common/util\";\n\ntype ScaleLayerProp = {\n  editingMode: Mode;\n  setEditingMode: React.Dispatch<React.SetStateAction<Mode>>;\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  functionMode: FunctionMode;\n  setFunctionMode: React.Dispatch<React.SetStateAction<FunctionMode>>;\n  record: RecordType;\n  setRecord: React.Dispatch<React.SetStateAction<RecordType>>;\n  currentRecordIndex: number;\n  setCurrentRecordIndex: React.Dispatch<React.SetStateAction<number>>;\n  insertInfo?: InsertInfo;\n  setInsertInfo: React.Dispatch<React.SetStateAction<InsertInfo | undefined>>;\n  cardShowing: CardShowing;\n  setCardShowing: Dispatch<SetStateAction<CardShowing>>;\n  defaultShape: string;\n} & ShowNameProps &\n  DrawProps &\n  TransformProps &\n  PageProps;\nfunction ScaleLayer({\n  editingMode,\n  setEditingMode,\n  data,\n  setData,\n  functionMode,\n  setFunctionMode,\n  record,\n  setRecord,\n  currentRecordIndex,\n  setCurrentRecordIndex,\n  insertInfo,\n  setInsertInfo,\n  cardShowing,\n  setCardShowing,\n  showName,\n  setShowName,\n  autoHiddenName,\n  setAutoHiddenName,\n  drawing,\n  setDrawing,\n  scale: scaleForMap,\n  setScale: setScaleForMap,\n  translateX: translateXForMap,\n  translateY: translateYForMap,\n  setTranslateX: setTranslateXForMap,\n  setTranslateY: setTranslateYForMap,\n  page,\n  defaultShape\n}: ScaleLayerProp) {\n  // mouseRefPoint\n  // in mouse drag mode: this point record mouse start point\n  const [mouseRefPoint, setMouseRefPoint] = useState(new Point());\n  // mouseStartTranslate\n  // record translate position when mouse start\n  // translate should add this value when mouse moving\n  const [mouseStartTranslate, setMouseStartTranslate] = useState(new Point());\n\n  // touchRefPoint\n  // 1. in touch move mode: this point record touch start point\n  // 2. in touch scale mode: this point record the center position of start touch\n  const [touchRefPoint, setTouchRefPoint] = useState(new Point());\n  // touchStartDistance\n  // record distance between two finger touch points for scaling operation\n  const [touchStartDistance, setTouchStartDistance] = useState(1);\n  // touchStartScale\n  // record the scale when touch start\n  // the finnal scale will be calculated by this value\n  const [touchStartScale, setTouchStartScale] = useState(1);\n  // touchStartTranslate\n  // record translate position when touch start\n  // translate should add this value when touch moving\n  const [touchStartTranslate, setTouchStartTranslate] = useState(new Point());\n  // touches or mouse moved, that means user trying to scale or move, not adding station\n  const [moved, setMoved] = useState(false);\n\n  const {\n    scale: scaleForImage = 1,\n    translateX: translateXForImage = 0,\n    translateY: translateYForImage = 0,\n  } = data;\n  let scale = scaleForMap,\n    translateX = translateXForMap,\n    translateY = translateYForMap;\n  if (functionMode === FunctionMode.editingCustomBackgroundPosition) {\n    scale = scaleForImage * scaleForMap;\n    translateX = translateXForImage * scaleForMap + translateXForMap;\n    translateY = translateYForImage * scaleForMap + translateYForMap;\n  }\n\n  const getRelativeValue = (\n    value: number,\n    type: \"scale\" | \"translateX\" | \"translateY\"\n  ) => {\n    switch (type) {\n      case \"scale\": {\n        return value / scaleForMap;\n      }\n      case \"translateX\": {\n        return (value - translateXForMap) / scaleForMap;\n      }\n      case \"translateY\": {\n        return (value - translateYForMap) / scaleForMap;\n      }\n    }\n  };\n  // translate and scale used for map or background image\n  const createSetter = (\n    key: \"scale\" | \"translateX\" | \"translateY\",\n    originalSetter: (value: number | ((prev: number) => number)) => void\n  ) => {\n    return functionMode === FunctionMode.editingCustomBackgroundPosition\n      ? (value: number | ((prev: number) => number)) => {\n          if (typeof value === \"number\") {\n            setData((data: UserDataType) => ({\n              ...data,\n              [key]: getRelativeValue(value, key),\n            }));\n          } else {\n            setData((data: UserDataType) => ({\n              ...data,\n              [key]: getRelativeValue(value(data[key]!), key),\n            }));\n          }\n        }\n      : originalSetter;\n  };\n\n  const setScale = createSetter(\"scale\", setScaleForMap);\n  const setTranslateX = createSetter(\"translateX\", setTranslateXForMap);\n  const setTranslateY = createSetter(\"translateY\", setTranslateYForMap);\n\n  // const scaleRelative = scaleForImage/scale;\n  // const translateXRelative = translateX - translateXForImage;\n  // const translateYRelative = translateY - translateYForImage;\n  const { stations, backgroundColor, backgroundImage, opacity } = data;\n  // const backgroundColor =\n  //   _backgroundColor === \"image\" ? \"transparent\" : _backgroundColor;\n  const allStationsList = mapToArr(stations);\n  const { minX, minY, maxX, maxY } = getBoundary(data);\n  const drawerX = maxX - minX + 400;\n  const drawerY = maxY - minY + 400;\n  const style: CSSProperties = {\n    backgroundColor,\n    transform: drawing\n      ? `scale(2)`\n      : `translate(${translateXForMap}px,${translateYForMap}px) scale(${scaleForMap})`,\n    width: drawing ? drawerX * 2 : undefined,\n    height: drawing ? drawerY * 2 : undefined,\n  };\n  const drawingStationMap = new Map();\n  allStationsList.forEach((station) => {\n    const { stationId } = station;\n    const [x, y] = station.position;\n    const position = [x - minX + 200, y - minY + 200];\n    drawingStationMap.set(stationId, { ...station, position });\n  });\n  const drawingData = { ...data, stations: drawingStationMap };\n  const { engine } = browserInfo;\n  const webkit = engine.name === \"WebKit\";\n  const display =\n    stations.size > 100 && webkit && page === \"menu\" ? \"none\" : undefined;\n  const imageSrc = useMemo(\n    () => (backgroundImage ? URL.createObjectURL(backgroundImage) : undefined),\n    [backgroundImage]\n  );\n  return (\n    <div\n      className=\"ScaleLayer\"\n      onWheel={(event) =>\n        onWheel(\n          event,\n          scale,\n          setScale,\n          translateX,\n          translateY,\n          setTranslateX,\n          setTranslateY,\n          functionMode\n        )\n      }\n      onMouseDown={(event) =>\n        onMouseDown(\n          event,\n          translateX,\n          translateY,\n          setEditingMode,\n          setMouseRefPoint,\n          setMouseStartTranslate,\n          setMoved\n        )\n      }\n      onMouseUp={(event) =>\n        onMouseUp(\n          event,\n          setEditingMode,\n          editingMode,\n          functionMode,\n          data,\n          setData,\n          moved,\n          translateX,\n          translateY,\n          scale,\n          record,\n          setRecord,\n          currentRecordIndex,\n          setCurrentRecordIndex,\n          cardShowing,\n          setCardShowing,\n          defaultShape\n        )\n      }\n      onMouseLeave={(event) => onMouseLeave(event, setEditingMode)}\n      onMouseMove={(event) =>\n        onMouseMove(\n          event,\n          translateX,\n          translateY,\n          setTranslateX,\n          setTranslateY,\n          editingMode,\n          mouseRefPoint,\n          mouseStartTranslate,\n          setMoved\n        )\n      }\n      onTouchStart={(event) =>\n        onTouchStart(\n          event,\n          setEditingMode,\n          setTouchRefPoint,\n          setTouchStartDistance,\n          setTouchStartScale,\n          scale,\n          setTouchStartTranslate,\n          translateX,\n          translateY,\n          setMoved\n        )\n      }\n      onTouchMove={(event) =>\n        onTouchMove(\n          event,\n          editingMode,\n          touchRefPoint,\n          translateX,\n          translateY,\n          setTranslateX,\n          setTranslateY,\n          touchStartDistance,\n          touchStartScale,\n          setScale,\n          touchStartTranslate,\n          setMoved\n        )\n      }\n      onTouchEnd={(event) =>\n        onTouchEnd(\n          event,\n          setEditingMode,\n          editingMode,\n          functionMode,\n          data,\n          setData,\n          moved,\n          translateX,\n          translateY,\n          scale,\n          record,\n          setRecord,\n          currentRecordIndex,\n          setCurrentRecordIndex,\n          cardShowing,\n          setCardShowing,\n          defaultShape\n        )\n      }\n      style={{ cursor: getCursor(editingMode), backgroundColor }}\n    >\n      <div className=\"layer-for-welcome-tour\"></div>\n      {/* <img\n        className=\"background-layer\"\n        src={imageSrc}\n        style={{\n          opacity,\n          transform: `translate(${translateXForImage * scaleForMap +translateXForMap}px,${translateYForImage * scaleForMap +translateYForMap}px) scale(${scaleForImage*scaleForMap})`,\n        }}\n      /> */}\n      <div className=\"transform-layer\" style={style}>\n        {imageSrc?<img\n          className=\"background-layer\"\n          src={imageSrc}\n          style={{\n            opacity,\n            transform: drawing\n              ? `translate(${\n                  (translateXForImage + 200   - minX )\n                }px,${\n                  (translateYForImage + 200  - minY )\n                }px) scale(${scaleForImage})`\n              : `translate(${translateXForImage}px,${translateYForImage}px) scale(${scaleForImage})`,\n          }}\n        />:<></>}\n        <RenderLayer\n          data={drawing ? drawingData : data}\n          setData={setData}\n          translateX={translateXForMap}\n          translateY={translateYForMap}\n          scale={scaleForMap}\n          functionMode={functionMode}\n          setFunctionMode={setFunctionMode}\n          record={record}\n          setRecord={setRecord}\n          currentRecordIndex={currentRecordIndex}\n          setCurrentRecordIndex={setCurrentRecordIndex}\n          insertInfo={insertInfo}\n          setInsertInfo={setInsertInfo}\n          cardShowing={cardShowing}\n          setCardShowing={setCardShowing}\n          editingMode={editingMode}\n          showName={showName}\n          setShowName={setShowName}\n          autoHiddenName={autoHiddenName}\n          setAutoHiddenName={setAutoHiddenName}\n          drawing={drawing}\n          setDrawing={setDrawing}\n          drawerX={drawerX}\n          drawerY={drawerY}\n        />\n      </div>\n    </div>\n  );\n}\n\nexport default ScaleLayer;\n"
  },
  {
    "path": "src/Render/Recovery/Recovery.scss",
    "content": ".App{\n    perspective: 1000px;\n    perspective-origin: 100vw 105px; \n    z-index: 10000;\n}\n.recovery-notification-container {\n\n    position: fixed;\n    right: 0;\n    top: 0;\n    transform-origin: right center;\n    transition: ease-in-out 0.5s;\n\n    &.show {\n        transform: rotate3d(0, 1, 0, 0deg);\n        opacity: 1;\n    }\n    &:not(.show) {\n        transform: rotate3d(0, 1, 0, -90deg);\n        opacity: 0;\n    }\n    .recovery-notification {\n        @media screen and (max-width: 520px) {\n            display: none;\n        }\n        position: fixed;\n        top: 30px;\n        right: 30px;\n        width: 363px;\n        height: 75px;\n        display: flex;\n        // justify-content: space-between;\n        align-items: center;\n        background-color: rgb(255, 255, 255, 0.72);\n        box-shadow: 0 0 80px 0 rgba(0, 0, 0, 0.25);\n        backdrop-filter: blur(15px);\n        border-radius: 15px;\n        transition: ease-in-out 0.3s;\n\n        // zoom: 1.2;\n        &:hover {\n            background-color: rgba(255, 255, 255, 0.001);\n        }\n        .icon {\n            margin: 0 20px;\n        }\n\n        .icon,\n        .ok,\n        .no {\n            width: 36px;\n            height: 36px;\n\n            border-radius: 50%;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n        }\n\n        .ok,\n        .no {\n            cursor: pointer;\n            position: absolute;\n        }\n\n        .icon,\n        .ok {\n            background-color: rgb(235, 10, 40, 0.1);\n        }\n\n        .no {\n            background-color: #d9d9d9;\n            right: 20px;\n        }\n\n        .icon {\n            svg {\n                width: 20px;\n                height: 20px;\n            }\n        }\n\n        .ok {\n            right: 60px;\n            transition: ease-in-out 0.3s;\n            &:hover {\n                background-color: rgb(235, 10, 40, 0.2);\n            }\n            svg {\n                width: 16px;\n            }\n        }\n\n        .no {\n            transition: ease-in-out 0.3s;\n            &:hover {\n                background-color: #c9c9c9;\n            }\n            svg {\n                width: 12px;\n            }\n        }\n\n        .text {\n            .title {\n                font-size: 16px;\n            }\n            .sub-title {\n                font-size: 12px;\n            }\n            font-weight: 500;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Render/Recovery/Recovery.tsx",
    "content": "import React, {\n  Dispatch,\n  SetStateAction,\n  useEffect,\n  useRef,\n  useState,\n} from \"react\";\nimport { ReactComponent as RecoverIcon } from \"../../Resource/Icon/clock.arrow.circlepath.svg\";\nimport { ReactComponent as OkIcon } from \"../../Resource/Icon/ok.svg\";\nimport { ReactComponent as NoIcon } from \"../../Resource/Icon/no.svg\";\n\nimport \"./Recovery.scss\";\nimport { setDataFromJson, UserDataType } from \"../../Data/UserData\";\nimport { mediateMap, readFileFromIndexedDB } from \"../../Common/util\";\nimport classNames from \"classnames\";\nimport { useTranslation } from \"react-i18next\";\nexport function Recovery({\n  data,\n  setData,\n  recoveredFromError,\n  setRecoveredFromError,\n  transfromTools,\n}: {\n  data: UserDataType;\n  setData: Dispatch<SetStateAction<UserDataType>>;\n  recoveredFromError: boolean;\n  setRecoveredFromError: Dispatch<SetStateAction<boolean>>;\n  transfromTools: {\n    scale: number;\n    setScale: React.Dispatch<React.SetStateAction<number>>;\n    translateX: number;\n    translateY: number;\n    setTranslateX: React.Dispatch<React.SetStateAction<number>>;\n    setTranslateY: React.Dispatch<React.SetStateAction<number>>;\n  };\n}) {\n  const {t} = useTranslation();\n  const notificationRef = useRef<HTMLDivElement>(null);\n  const [showNotification, setShowNotification] = useState(false);\n  useEffect(() => {\n    const current = localStorage.getItem(\"current\");\n    const show = current && !recoveredFromError;\n    setRecoveredFromError(false);\n    setShowNotification(!!show);\n    const handleClickCapture = (event: TouchEvent | MouseEvent) => {\n      if (\n        notificationRef.current &&\n        !notificationRef.current.contains(event.target as Node)\n      ) {\n        console.log(\"recovery focusout\");\n        setShowNotification(false);\n      }\n    };\n    document.addEventListener(\"touchstart\", handleClickCapture, true);\n    document.addEventListener(\"click\", handleClickCapture, true);\n    return () => {\n      document.removeEventListener(\"touchstart\", handleClickCapture, true);\n      document.addEventListener(\"click\", handleClickCapture, true);\n    };\n  }, []);\n  return (\n    <div\n      ref={notificationRef}\n      className={classNames({\n        \"recovery-notification-container\": 1,\n        show: showNotification,\n      })}\n    >\n      <div\n        className={classNames({\n          \"recovery-notification\": 1,\n          show: showNotification,\n        })}\n      >\n        <div className=\"icon\">\n          <RecoverIcon />\n        </div>\n        <div className=\"text\">\n          <div className=\"title\">{t('recover.text')}</div>\n          <div className=\"sub-title\">{t('recover.subTitle')}</div>\n        </div>\n        <div\n          className=\"ok\"\n          onClick={() => {\n            const current = localStorage.getItem(\"current\");\n            if (current) {\n              const data = setDataFromJson(setData, current);\n              readFileFromIndexedDB(\"image\")\n                .then((file) => {\n                  setData((data) => ({\n                    ...data,\n                    // backgroundColor: \"image\",\n                    backgroundImage: file as File,\n                  }));\n                })\n                .catch((e) => {\n                  console.error(e);\n                });\n              mediateMap(data, transfromTools);\n            }\n            setShowNotification(false);\n          }}\n        >\n          <OkIcon />\n        </div>\n        <div\n          className=\"no\"\n          onClick={() => {\n            setShowNotification(false);\n          }}\n        >\n          <NoIcon />\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/Resource/Icon/airwave.tsx",
    "content": "import React from \"react\";\n\nconst AirWaveIcon =({className}:{className?: string})=> (\n<svg width=\"23\" height=\"21\" viewBox=\"0 0 23 21\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n<path d=\"M20.2187 6.17324C19.6375 6.75449 18.9701 7.19581 18.2167 7.4972C17.4632 7.79859 16.7097 7.94928 15.9562 7.94928C15.2028 7.94928 14.4601 7.80397 13.7281 7.51335C12.9962 7.22272 12.3396 6.77602 11.7583 6.17324L9.33646 3.75137C9.01354 3.42845 8.64757 3.18626 8.23854 3.0248C7.82951 2.86335 7.40972 2.78262 6.97917 2.78262C6.54861 2.78262 6.12882 2.86335 5.71979 3.0248C5.31076 3.18626 4.94479 3.42845 4.62187 3.75137L2.2 6.17324L0.359375 4.33262L2.78125 1.91074C3.3625 1.32949 4.0191 0.893555 4.75104 0.60293C5.48299 0.312305 6.22569 0.166992 6.97917 0.166992C7.73264 0.166992 8.46997 0.312305 9.19115 0.60293C9.91233 0.893555 10.5635 1.32949 11.1448 1.91074L13.5667 4.33262C13.9111 4.67706 14.2878 4.93001 14.6969 5.09147C15.1059 5.25293 15.5257 5.33366 15.9562 5.33366C16.3868 5.33366 16.812 5.25293 17.2318 5.09147C17.6516 4.93001 18.0337 4.67706 18.3781 4.33262L20.8 1.91074L22.6406 3.75137L20.2187 6.17324ZM20.2187 12.6316C19.6375 13.2128 18.9755 13.6488 18.2328 13.9394C17.4901 14.23 16.742 14.3753 15.9885 14.3753C15.2351 14.3753 14.487 14.23 13.7443 13.9394C13.0016 13.6488 12.3396 13.2128 11.7583 12.6316L9.33646 10.2097C9.01354 9.88678 8.64757 9.6446 8.23854 9.48314C7.82951 9.32168 7.40972 9.24095 6.97917 9.24095C6.54861 9.24095 6.12882 9.32168 5.71979 9.48314C5.31076 9.6446 4.94479 9.88678 4.62187 10.2097L2.2 12.6316L0.359375 10.8232L2.78125 8.36908C3.3625 7.78783 4.0191 7.35189 4.75104 7.06126C5.48299 6.77064 6.22569 6.62533 6.97917 6.62533C7.73264 6.62533 8.46997 6.77064 9.19115 7.06126C9.91233 7.35189 10.5635 7.78783 11.1448 8.36908L13.5667 10.791C13.9111 11.1354 14.2878 11.3883 14.6969 11.5498C15.1059 11.7113 15.5257 11.792 15.9562 11.792C16.3868 11.792 16.812 11.7113 17.2318 11.5498C17.6516 11.3883 18.0337 11.1354 18.3781 10.791L20.8 8.36908L22.6406 10.2097L20.2187 12.6316ZM20.1865 19.0899C19.6052 19.6712 18.9486 20.1071 18.2167 20.3977C17.4847 20.6883 16.742 20.8337 15.9885 20.8337C15.2351 20.8337 14.487 20.6883 13.7443 20.3977C13.0016 20.1071 12.3396 19.6712 11.7583 19.0899L9.30417 16.668C8.98125 16.3451 8.61528 16.1029 8.20625 15.9415C7.79722 15.78 7.37743 15.6993 6.94687 15.6993C6.51632 15.6993 6.09653 15.78 5.6875 15.9415C5.27847 16.1029 4.9125 16.3451 4.58958 16.668L2.16771 19.0899L0.359375 17.2816L2.78125 14.8274C3.3625 14.2462 4.0191 13.8102 4.75104 13.5196C5.48299 13.229 6.22569 13.0837 6.97917 13.0837C7.73264 13.0837 8.46997 13.229 9.19115 13.5196C9.91233 13.8102 10.5635 14.2462 11.1448 14.8274L13.5667 17.2493C13.9111 17.5937 14.2932 17.8467 14.713 18.0081C15.1328 18.1696 15.558 18.2503 15.9885 18.2503C16.4191 18.2503 16.8389 18.1696 17.2479 18.0081C17.6569 17.8467 18.0337 17.5937 18.3781 17.2493L20.8 14.8274L22.6083 16.668L20.1865 19.0899Z\" fill=\"white\"/>\n</svg>\n);\n\nexport default AirWaveIcon;"
  },
  {
    "path": "src/Resource/Icon/arrow.tsx",
    "content": "import React from \"react\";\n\nconst arrowIcon = ({ className }: { className?: string }) => (\n  <svg\n    width=\"20\"\n    height=\"20\"\n    viewBox=\"0 0 20 20\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g clip-path=\"url(#clip0_72_386)\">\n      <path\n        d=\"M9.96094 19.9219C11.3216 19.9219 12.6026 19.6615 13.8037 19.1406C15.0049 18.6198 16.0645 17.9004 16.9824 16.9824C17.9004 16.0645 18.6198 15.0049 19.1406 13.8037C19.6615 12.6026 19.9219 11.3216 19.9219 9.96094C19.9219 8.60026 19.6615 7.31933 19.1406 6.11816C18.6198 4.91699 17.9004 3.85742 16.9824 2.93945C16.0645 2.02148 15.0033 1.30208 13.7988 0.78125C12.5944 0.260417 11.3119 0 9.95117 0C8.5905 0 7.30957 0.260417 6.1084 0.78125C4.90723 1.30208 3.84928 2.02148 2.93457 2.93945C2.01986 3.85742 1.30208 4.91699 0.78125 6.11816C0.260417 7.31933 0 8.60026 0 9.96094C0 11.3216 0.260417 12.6026 0.78125 13.8037C1.30208 15.0049 2.02148 16.0645 2.93945 16.9824C3.85742 17.9004 4.91699 18.6198 6.11816 19.1406C7.31933 19.6615 8.60026 19.9219 9.96094 19.9219Z\"\n        fill=\"black\"\n        fill-opacity=\"0.41\"\n      />\n      <path\n        d=\"M15.1367 9.94141C15.1367 10.1432 15.0391 10.3418 14.8438 10.5371L11.4551 13.9453C11.3118 14.0886 11.1328 14.1602 10.918 14.1602C10.7097 14.1602 10.5355 14.0886 10.3955 13.9453C10.2555 13.8021 10.1855 13.6263 10.1855 13.418C10.1855 13.2031 10.2636 13.0208 10.4199 12.8711L11.6699 11.6406L12.8906 10.6152L10.752 10.7031H5.52734C5.30599 10.7031 5.1237 10.6315 4.98047 10.4883C4.83724 10.345 4.76562 10.1627 4.76562 9.94141C4.76562 9.72005 4.83724 9.53776 4.98047 9.39453C5.1237 9.2513 5.30599 9.17969 5.52734 9.17969H10.752L12.8809 9.26758L11.6699 8.25195L10.4199 7.01172C10.2636 6.84896 10.1855 6.66992 10.1855 6.47461C10.1855 6.26627 10.2555 6.09212 10.3955 5.95215C10.5355 5.81217 10.7097 5.74219 10.918 5.74219C11.1393 5.74219 11.3184 5.81055 11.4551 5.94727L14.8438 9.35547C15.0391 9.55078 15.1367 9.74609 15.1367 9.94141Z\"\n        fill=\"white\"\n      />\n    </g>\n    <defs>\n      <clipPath id=\"clip0_72_386\">\n        <rect width=\"19.9219\" height=\"19.9316\" fill=\"white\" />\n      </clipPath>\n    </defs>\n  </svg>\n);\n\nexport default arrowIcon;\n"
  },
  {
    "path": "src/Resource/Icon/auto.tsx",
    "content": "import React from \"react\";\n\nconst AutoIcon = ({ className }: { className?: string }) => (<svg width=\"31\" height=\"31\" viewBox=\"0 0 31 31\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<mask id=\"mask0_863_657\"     style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"31\" height=\"31\">\n<rect width=\"31\" height=\"31\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_863_657)\">\n<path d=\"M15.5026 19.3747C16.579 19.3747 17.4939 18.9979 18.2474 18.2445C19.0009 17.491 19.3776 16.5761 19.3776 15.4997C19.3776 14.4233 19.0009 13.5084 18.2474 12.7549C17.4939 12.0014 16.579 11.6247 15.5026 11.6247C14.4262 11.6247 13.5113 12.0014 12.7578 12.7549C12.0043 13.5084 11.6276 14.4233 11.6276 15.4997C11.6276 16.5761 12.0043 17.491 12.7578 18.2445C13.5113 18.9979 14.4262 19.3747 15.5026 19.3747ZM15.5026 28.4163C13.7158 28.4163 12.0366 28.0773 10.4651 27.3992C8.89358 26.721 7.52656 25.8007 6.36406 24.6382C5.20156 23.4757 4.28125 22.1087 3.60313 20.5372C2.925 18.9656 2.58594 17.2865 2.58594 15.4997C2.58594 13.7129 2.925 12.0337 3.60313 10.4622C4.28125 8.89065 5.20156 7.52363 6.36406 6.36113C7.52656 5.19863 8.89358 4.27832 10.4651 3.6002C12.0366 2.92207 13.7158 2.58301 15.5026 2.58301C17.2894 2.58301 18.9686 2.92207 20.5401 3.6002C22.1116 4.27832 23.4786 5.19863 24.6411 6.36113C25.8036 7.52363 26.724 8.89065 27.4021 10.4622C28.0802 12.0337 28.4193 13.7129 28.4193 15.4997C28.4193 17.2865 28.0802 18.9656 27.4021 20.5372C26.724 22.1087 25.8036 23.4757 24.6411 24.6382C23.4786 25.8007 22.1116 26.721 20.5401 27.3992C18.9686 28.0773 17.2894 28.4163 15.5026 28.4163ZM15.5026 25.833C18.3873 25.833 20.8307 24.832 22.8328 22.8299C24.8349 20.8278 25.8359 18.3844 25.8359 15.4997C25.8359 12.615 24.8349 10.1716 22.8328 8.16947C20.8307 6.16738 18.3873 5.16634 15.5026 5.16634C12.6179 5.16634 10.1745 6.16738 8.1724 8.16947C6.17031 10.1716 5.16927 12.615 5.16927 15.4997C5.16927 18.3844 6.17031 20.8278 8.1724 22.8299C10.1745 24.832 12.6179 25.833 15.5026 25.833Z\" fill=\"white\"/>\n</g>\n</svg>);\n\nexport default AutoIcon;\n"
  },
  {
    "path": "src/Resource/Icon/bolt.tsx",
    "content": "import React from \"react\";\n\nconst BoltIcon = ({ className }: { className?: string }) => (<svg width=\"31\" height=\"31\" viewBox=\"0 0 31 31\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<mask id=\"mask0_863_624\"       style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"31\" height=\"31\">\n<rect width=\"31\" height=\"31\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_863_624)\">\n<path d=\"M13.6245 23.508L20.3089 15.4997H15.1422L16.0786 8.16947L10.1047 16.7913H14.5932L13.6245 23.508ZM10.3307 28.4163L11.6224 19.3747H5.16406L16.7891 2.58301H19.3724L18.0807 12.9163H25.8307L12.9141 28.4163H10.3307Z\" fill=\"white\"/>\n</g>\n</svg>);\n\nexport default BoltIcon;\n\n"
  },
  {
    "path": "src/Resource/Icon/edit.tsx",
    "content": "import React from \"react\";\n\nconst edit =({className}:{className: string})=> (\n  <svg\n    width=\"22\"\n    height=\"22\"\n    viewBox=\"0 0 22 22\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    className={className}\n  >\n    <path\n      d=\"M0 11C0 12.5026 0.287581 13.9172 0.862744 15.2436C1.43791 16.5701 2.23235 17.7402 3.24607 18.7539C4.2598 19.7676 5.4299 20.5621 6.75636 21.1372C8.08283 21.7124 9.49737 22 11 22C12.5026 22 13.9172 21.7124 15.2436 21.1372C16.5701 20.5621 17.7402 19.7676 18.7539 18.7539C19.7676 17.7402 20.5621 16.5701 21.1372 15.2436C21.7124 13.9172 22 12.5026 22 11C22 9.49737 21.7124 8.08283 21.1372 6.75636C20.5621 5.4299 19.7676 4.2598 18.7539 3.24607C17.7402 2.23235 16.5683 1.43791 15.2382 0.862744C13.9082 0.287581 12.4918 0 10.9892 0C9.48659 0 8.07205 0.287581 6.74558 0.862744C5.41911 1.43791 4.25081 2.23235 3.24068 3.24607C2.23055 4.2598 1.43791 5.4299 0.862744 6.75636C0.287581 8.08283 0 9.49737 0 11ZM1.84411 11C1.84411 9.72744 2.07957 8.53757 2.55049 7.43039C3.0214 6.3232 3.67385 5.34901 4.50784 4.50784C5.34182 3.66666 6.31241 3.01061 7.4196 2.5397C8.52679 2.06879 9.71666 1.83334 10.9892 1.83334C12.2618 1.83334 13.4516 2.06879 14.5588 2.5397C15.666 3.01061 16.6402 3.66666 17.4814 4.50784C18.3226 5.34901 18.9804 6.3232 19.4549 7.43039C19.9294 8.53757 20.1666 9.72744 20.1666 11C20.1738 12.0856 20.0013 13.1155 19.649 14.0897C19.2968 15.0639 18.8007 15.9481 18.1607 16.7426C17.5209 17.537 16.7768 18.2039 15.9284 18.7432L14.5803 12.4127C14.5301 12.1539 14.4115 11.94 14.2245 11.7711C14.0376 11.6021 13.8219 11.5069 13.5774 11.4853H13.502L11.7118 6.10391C11.6326 5.87384 11.496 5.71927 11.302 5.64019C11.1078 5.5611 10.9119 5.5611 10.7142 5.64019C10.5165 5.71927 10.3781 5.87384 10.299 6.10391L8.50881 11.4853H8.43332C8.18888 11.5069 7.97319 11.6021 7.78626 11.7711C7.59934 11.94 7.48071 12.1503 7.43039 12.402L6.09313 18.7432C5.23758 18.2039 4.49166 17.5388 3.85539 16.748C3.21911 15.9572 2.72483 15.0747 2.37255 14.1005C2.02026 13.1263 1.84411 12.0928 1.84411 11ZM7.37646 19.4225L8.75685 12.8765H13.2647L14.6451 19.4225C14.0843 19.6598 13.4983 19.8431 12.8872 19.9725C12.2761 20.1019 11.647 20.1666 11 20.1666C10.3529 20.1666 9.72384 20.1037 9.11273 19.9779C8.50163 19.8521 7.92287 19.667 7.37646 19.4225Z\"\n      fill=\"black\"\n      fill-opacity=\"0.41\"\n    />\n  </svg>\n);\n\nexport default edit;"
  },
  {
    "path": "src/Resource/Icon/expand.tsx",
    "content": "import React from \"react\";\n\nconst expand =({className}:{className?: string})=> (\n<svg width=\"19\" height=\"19\" viewBox=\"0 0 19 19\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n<g clip-path=\"url(#clip0_72_433)\">\n<path d=\"M0.898438 7.90039C1.15885 7.90039 1.37207 7.81413 1.53809 7.6416C1.7041 7.46907 1.78711 7.2526 1.78711 6.99219V6.17188L1.5918 2.76367L4.16016 5.46875L7.16797 8.49609C7.33073 8.66536 7.53581 8.75 7.7832 8.75C8.06315 8.75 8.29427 8.66699 8.47656 8.50098C8.65885 8.33496 8.75 8.11523 8.75 7.8418C8.75 7.71159 8.72721 7.58789 8.68164 7.4707C8.63607 7.35351 8.57096 7.2526 8.48633 7.16797L5.46875 4.16016L2.76367 1.5918L6.18164 1.78711H6.99219C7.2526 1.78711 7.4707 1.7041 7.64648 1.53809C7.82227 1.37207 7.91016 1.15885 7.91016 0.898438C7.91016 0.638021 7.8239 0.423177 7.65137 0.253906C7.47884 0.0846353 7.25912 0 6.99219 0H1.57227C1.07748 0 0.691732 0.138346 0.415039 0.415039C0.138346 0.691732 0 1.07748 0 1.57227V6.99219C0 7.2461 0.0846353 7.46094 0.253906 7.63672C0.423177 7.8125 0.638021 7.90039 0.898438 7.90039ZM11.6113 18.6328H17.0312C17.5325 18.6328 17.9215 18.4945 18.1982 18.2178C18.4749 17.9411 18.6133 17.5553 18.6133 17.0605V11.6406C18.6133 11.3867 18.527 11.1719 18.3545 10.9961C18.182 10.8203 17.9655 10.7324 17.7051 10.7324C17.4512 10.7324 17.2396 10.8187 17.0703 10.9912C16.901 11.1637 16.8164 11.3802 16.8164 11.6406V12.4609L17.0215 15.8691L14.4434 13.1641L11.4453 10.1367C11.2826 9.96744 11.0742 9.88281 10.8203 9.88281C10.5469 9.88281 10.3174 9.96581 10.1318 10.1318C9.94628 10.2979 9.85352 10.5176 9.85352 10.791C9.85352 10.9212 9.87631 11.0449 9.92188 11.1621C9.96745 11.2793 10.0358 11.3802 10.127 11.4648L13.1348 14.4727L15.8496 17.041L12.4316 16.8457H11.6113C11.3509 16.8457 11.1328 16.9287 10.957 17.0947C10.7813 17.2608 10.6934 17.474 10.6934 17.7344C10.6934 17.9948 10.7813 18.2096 10.957 18.3789C11.1328 18.5482 11.3509 18.6328 11.6113 18.6328Z\" fill=\"black\" fill-opacity=\"0.41\"/>\n</g>\n<defs>\n<clipPath id=\"clip0_72_433\">\n<rect width=\"18.6133\" height=\"18.6426\" fill=\"white\"/>\n</clipPath>\n</defs>\n</svg>\n);\n\nexport default expand;"
  },
  {
    "path": "src/Resource/Icon/export.tsx",
    "content": "import React from \"react\";\n\nconst ExportIcon = ({ className }: { className?: string }) => (<svg width=\"31\" height=\"31\" viewBox=\"0 0 31 31\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<mask id=\"mask0_863_660\"       style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"31\" height=\"31\">\n<rect width=\"31\" height=\"31\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_863_660)\">\n<path d=\"M7.7474 29.7087C7.03698 29.7087 6.42882 29.4557 5.92292 28.9498C5.41701 28.4439 5.16406 27.8357 5.16406 27.1253V12.917C5.16406 12.2066 5.41701 11.5984 5.92292 11.0925C6.42882 10.5866 7.03698 10.3337 7.7474 10.3337H11.6224V12.917H7.7474V27.1253H23.2474V12.917H19.3724V10.3337H23.2474C23.9578 10.3337 24.566 10.5866 25.0719 11.0925C25.5778 11.5984 25.8307 12.2066 25.8307 12.917V27.1253C25.8307 27.8357 25.5778 28.4439 25.0719 28.9498C24.566 29.4557 23.9578 29.7087 23.2474 29.7087H7.7474ZM14.2057 20.667V6.23262L12.1391 8.29928L10.3307 6.45866L15.4974 1.29199L20.6641 6.45866L18.8557 8.29928L16.7891 6.23262V20.667H14.2057Z\" fill=\"white\"/>\n</g>\n</svg>);\n\nexport default ExportIcon;\n\n"
  },
  {
    "path": "src/Resource/Icon/finished.tsx",
    "content": "import React from \"react\";\n\nconst FinishedIcon =({className}:{className?: string})=> (\n<svg width=\"35\" height=\"35\" viewBox=\"0 0 35 35\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n<mask id=\"mask0_941_683\" style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"35\" height=\"35\">\n<rect width=\"35\" height=\"35\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_941_683)\">\n<path d=\"M13.9297 26.2503L5.61719 17.9378L7.69531 15.8597L13.9297 22.0941L27.3099 8.71387L29.388 10.792L13.9297 26.2503Z\" fill=\"white\"/>\n</g>\n</svg>\n\n);\n\nexport default FinishedIcon;"
  },
  {
    "path": "src/Resource/Icon/goto.tsx",
    "content": "import React from \"react\";\n\nconst GoToIcon = ({ className }: { className?: string }) => (\n  <svg\n    width=\"50\"\n    height=\"50\"\n    viewBox=\"0 0 50 50\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    className={className}\n\n  >\n    <mask\n      id=\"mask0_863_607\"\n      style={{ maskType: \"alpha\" }}\n      maskUnits=\"userSpaceOnUse\"\n      x=\"0\"\n      y=\"0\"\n      width=\"50\"\n      height=\"50\"\n    >\n      <rect\n        x=\"49.5\"\n        y=\"24.749\"\n        width=\"35\"\n        height=\"35\"\n        transform=\"rotate(135 49.5 24.749)\"\n        fill=\"#D9D9D9\"\n      />\n    </mask>\n    <g mask=\"url(#mask0_863_607)\">\n      <path\n        d=\"M21.665 15.4671L34.0394 15.4671L34.0394 27.8415L31.152 27.8415L31.152 20.4169L16.509 35.0599L14.4466 32.9975L29.0896 18.3545L21.665 18.3545L21.665 15.4671Z\"\n        fill=\"white\"\n      />\n    </g>\n  </svg>\n);\n\nexport default GoToIcon;\n"
  },
  {
    "path": "src/Resource/Icon/infinity.tsx",
    "content": "import React from \"react\";\n\nconst Infinity = ({ className }: { className?: string }) => (\n  <svg\n    width=\"31\"\n    height=\"31\"\n    viewBox=\"0 0 31 31\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    className={className}\n  >\n    <mask\n      id=\"mask0_863_587\"\n      style={{maskType:'alpha'}}\n      maskUnits=\"userSpaceOnUse\"\n      x=\"0\"\n      y=\"0\"\n      width=\"31\"\n      height=\"31\"\n    >\n      <rect width=\"31\" height=\"31\" fill=\"#D9D9D9\" />\n    </mask>\n    <g mask=\"url(#mask0_863_587)\">\n      <path\n        d=\"M7.10417 22.6038C5.12361 22.6038 3.44444 21.915 2.06667 20.5372C0.688889 19.1594 0 17.4802 0 15.4997C0 13.5191 0.688889 11.84 2.06667 10.4622C3.44444 9.0844 5.12361 8.39551 7.10417 8.39551C7.90069 8.39551 8.66493 8.53544 9.39687 8.8153C10.1288 9.09516 10.7854 9.49342 11.3667 10.0101L13.5625 12.0122L11.625 13.7559L9.62292 11.9476C9.27847 11.6462 8.89097 11.4094 8.46042 11.2372C8.02986 11.065 7.57778 10.9788 7.10417 10.9788C5.85556 10.9788 4.78993 11.4202 3.90729 12.3028C3.02465 13.1854 2.58333 14.2511 2.58333 15.4997C2.58333 16.7483 3.02465 17.8139 3.90729 18.6965C4.78993 19.5792 5.85556 20.0205 7.10417 20.0205C7.57778 20.0205 8.02986 19.9344 8.46042 19.7622C8.89097 19.59 9.27847 19.3531 9.62292 19.0518L19.6333 10.0101C20.2146 9.49342 20.8712 9.09516 21.6031 8.8153C22.3351 8.53544 23.0993 8.39551 23.8958 8.39551C25.8764 8.39551 27.5556 9.0844 28.9333 10.4622C30.3111 11.84 31 13.5191 31 15.4997C31 17.4802 30.3111 19.1594 28.9333 20.5372C27.5556 21.915 25.8764 22.6038 23.8958 22.6038C23.0993 22.6038 22.3351 22.4639 21.6031 22.184C20.8712 21.9042 20.2146 21.5059 19.6333 20.9893L17.4375 18.9872L19.375 17.2434L21.3771 19.0518C21.7215 19.3531 22.109 19.59 22.5396 19.7622C22.9701 19.9344 23.4222 20.0205 23.8958 20.0205C25.1444 20.0205 26.2101 19.5792 27.0927 18.6965C27.9753 17.8139 28.4167 16.7483 28.4167 15.4997C28.4167 14.2511 27.9753 13.1854 27.0927 12.3028C26.2101 11.4202 25.1444 10.9788 23.8958 10.9788C23.4222 10.9788 22.9701 11.065 22.5396 11.2372C22.109 11.4094 21.7215 11.6462 21.3771 11.9476L11.3667 20.9893C10.7854 21.5059 10.1288 21.9042 9.39687 22.184C8.66493 22.4639 7.90069 22.6038 7.10417 22.6038Z\"\n        fill=\"white\"\n      />\n    </g>\n  </svg>\n);\n\nexport default Infinity;\n"
  },
  {
    "path": "src/Resource/Icon/pageview.tsx",
    "content": "import React from \"react\";\n\nconst PageViewIcon =({className}:{className?: string})=> (<svg width=\"31\" height=\"31\" viewBox=\"0 0 31 31\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<mask id=\"mask0_863_614\"       style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"31\" height=\"31\">\n<rect width=\"31\" height=\"31\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_863_614)\">\n<path d=\"M20.3464 25.8337H5.16927C4.45885 25.8337 3.85069 25.5807 3.34479 25.0748C2.83889 24.5689 2.58594 23.9607 2.58594 23.2503V7.75033C2.58594 7.03991 2.83889 6.43175 3.34479 5.92585C3.85069 5.41994 4.45885 5.16699 5.16927 5.16699H25.8359C26.5464 5.16699 27.1545 5.41994 27.6604 5.92585C28.1663 6.43175 28.4193 7.03991 28.4193 7.75033V23.2503C28.4193 23.9607 28.1663 24.5689 27.6604 25.0748C27.1545 25.5807 26.5464 25.8337 25.8359 25.8337H24.0276L17.9568 19.7628C17.5047 20.0642 17.0149 20.2903 16.4875 20.4409C15.9601 20.5916 15.4165 20.667 14.8568 20.667C13.2422 20.667 11.8698 20.1019 10.7396 18.9717C9.60938 17.8415 9.04427 16.4691 9.04427 14.8545C9.04427 13.2399 9.60938 11.8675 10.7396 10.7373C11.8698 9.6071 13.2422 9.04199 14.8568 9.04199C16.4714 9.04199 17.8438 9.6071 18.974 10.7373C20.1042 11.8675 20.6693 13.2399 20.6693 14.8545C20.6693 15.4357 20.5939 15.9847 20.4432 16.5014C20.2925 17.018 20.0665 17.5024 19.7651 17.9545L25.0609 23.2503H25.8359V7.75033H5.16927V23.2503H17.763L20.3464 25.8337ZM14.8568 18.0837C15.7609 18.0837 16.5252 17.7715 17.1495 17.1472C17.7738 16.5229 18.0859 15.7587 18.0859 14.8545C18.0859 13.9503 17.7738 13.1861 17.1495 12.5618C16.5252 11.9375 15.7609 11.6253 14.8568 11.6253C13.9526 11.6253 13.1884 11.9375 12.5641 12.5618C11.9398 13.1861 11.6276 13.9503 11.6276 14.8545C11.6276 15.7587 11.9398 16.5229 12.5641 17.1472C13.1884 17.7715 13.9526 18.0837 14.8568 18.0837Z\" fill=\"white\"/>\n</g>\n</svg>\n);\n\nexport default PageViewIcon;"
  },
  {
    "path": "src/Resource/Icon/plus.tsx",
    "content": "import React from \"react\";\n\nconst plusIcon = ({ className }: { className?: string }) => (\n  <svg\n    width=\"20\"\n    height=\"20\"\n    viewBox=\"0 0 20 20\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g clip-path=\"url(#clip0_459_278)\">\n      <path\n        d=\"M9.96094 19.9219C11.3216 19.9219 12.6026 19.6615 13.8037 19.1406C15.0049 18.6198 16.0645 17.9004 16.9824 16.9824C17.9004 16.0645 18.6198 15.0049 19.1406 13.8037C19.6615 12.6026 19.9219 11.3216 19.9219 9.96094C19.9219 8.60026 19.6615 7.31933 19.1406 6.11816C18.6198 4.91699 17.9004 3.85742 16.9824 2.93945C16.0645 2.02148 15.0033 1.30208 13.7988 0.78125C12.5944 0.260417 11.3119 0 9.95117 0C8.5905 0 7.30957 0.260417 6.1084 0.78125C4.90723 1.30208 3.84928 2.02148 2.93457 2.93945C2.01986 3.85742 1.30208 4.91699 0.78125 6.11816C0.260417 7.31933 0 8.60026 0 9.96094C0 11.3216 0.260417 12.6026 0.78125 13.8037C1.30208 15.0049 2.02148 16.0645 2.93945 16.9824C3.85742 17.9004 4.91699 18.6198 6.11816 19.1406C7.31933 19.6615 8.60026 19.9219 9.96094 19.9219Z\"\n        fill=\"black\"\n        fill-opacity=\"0.41\"\n      />\n      <path\n        d=\"M5.19531 9.9707C5.19531 9.71679 5.27669 9.51009 5.43945 9.35059C5.60221 9.19108 5.81055 9.11133 6.06445 9.11133H9.12109V6.05469C9.12109 5.80078 9.19759 5.59245 9.35059 5.42969C9.50359 5.26693 9.70378 5.18555 9.95117 5.18555C10.2051 5.18555 10.4118 5.26693 10.5713 5.42969C10.7308 5.59245 10.8105 5.80078 10.8105 6.05469V9.11133H13.877C14.1309 9.11133 14.3376 9.19108 14.4971 9.35059C14.6566 9.51009 14.7363 9.71679 14.7363 9.9707C14.7363 10.2181 14.6549 10.4183 14.4922 10.5713C14.3294 10.7243 14.1243 10.8008 13.877 10.8008H10.8105V13.8672C10.8105 14.1211 10.7308 14.3278 10.5713 14.4873C10.4118 14.6468 10.2051 14.7266 9.95117 14.7266C9.70378 14.7266 9.50359 14.6468 9.35059 14.4873C9.19759 14.3278 9.12109 14.1211 9.12109 13.8672V10.8008H6.06445C5.81055 10.8008 5.60221 10.7243 5.43945 10.5713C5.27669 10.4183 5.19531 10.2181 5.19531 9.9707Z\"\n        fill=\"white\"\n      />\n    </g>\n    <defs>\n      <clipPath id=\"clip0_459_278\">\n        <rect width=\"19.9219\" height=\"19.9316\" fill=\"white\" />\n      </clipPath>\n    </defs>\n  </svg>\n);\n\nexport default plusIcon;\n"
  },
  {
    "path": "src/Resource/Icon/shrink.tsx",
    "content": "import React from \"react\";\n\nconst shrink =({className}:{className: string})=> (\n<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n<g clip-path=\"url(#clip0_61_611)\">\n<path d=\"M1.75781 8.84766H7.17773C7.67904 8.84766 8.06641 8.70931 8.33984 8.43262C8.61328 8.15593 8.75 7.76693 8.75 7.26562V1.85547C8.75 1.60156 8.66536 1.38672 8.49609 1.21094C8.32682 1.03516 8.11198 0.947266 7.85156 0.947266C7.59115 0.947266 7.37793 1.03353 7.21191 1.20605C7.0459 1.37858 6.96289 1.59505 6.96289 1.85547V2.67578L7.16797 6.08398L4.58984 3.37891L1.5918 0.351562C1.42253 0.175781 1.21419 0.0878906 0.966797 0.0878906C0.686849 0.0878906 0.455729 0.172526 0.273438 0.341797C0.091146 0.511068 0 0.732422 0 1.00586C0 1.13607 0.0227865 1.25814 0.0683594 1.37207C0.113932 1.486 0.182292 1.58854 0.273438 1.67969L3.28125 4.6875L5.98633 7.25586L2.57812 7.06055H1.75781C1.4974 7.06055 1.2793 7.14356 1.10352 7.30957C0.927736 7.47558 0.839844 7.6888 0.839844 7.94922C0.839844 8.20963 0.927736 8.42448 1.10352 8.59375C1.2793 8.76302 1.4974 8.84766 1.75781 8.84766ZM11.123 18.7598C11.3769 18.7598 11.5885 18.6735 11.7578 18.501C11.9271 18.3285 12.0117 18.112 12.0117 17.8516V16.9238L11.8066 13.5254L14.3848 16.2305L17.4512 19.3164C17.6139 19.4922 17.8223 19.5801 18.0762 19.5801C18.3496 19.5801 18.5775 19.4955 18.7598 19.3262C18.9421 19.1569 19.0332 18.9356 19.0332 18.6621C19.0332 18.5319 19.0104 18.4098 18.9648 18.2959C18.9193 18.182 18.8542 18.0794 18.7695 17.9883L15.6934 14.9121L12.9785 12.3438L16.3965 12.5391H17.3242C17.5846 12.5391 17.8027 12.4577 17.9785 12.2949C18.1543 12.1322 18.2422 11.9206 18.2422 11.6602C18.2422 11.3933 18.1543 11.1768 17.9785 11.0107C17.8027 10.8447 17.5846 10.7617 17.3242 10.7617H11.7969C11.2956 10.7617 10.9082 10.8984 10.6348 11.1719C10.3613 11.4453 10.2246 11.8327 10.2246 12.334V17.8516C10.2246 18.112 10.3092 18.3285 10.4785 18.501C10.6478 18.6735 10.8626 18.7598 11.123 18.7598Z\" fill=\"black\" fill-opacity=\"0.41\"/>\n</g>\n<defs>\n<clipPath id=\"clip0_61_611\">\n<rect width=\"19.0332\" height=\"19.5801\" fill=\"white\"/>\n</clipPath>\n</defs>\n</svg>\n);\n\nexport default shrink;"
  },
  {
    "path": "src/Resource/Icon/touch.tsx",
    "content": "import React from \"react\";\n\nconst TouchIcon = ({ className }: { className?: string }) => (<svg width=\"31\" height=\"31\" viewBox=\"0 0 31 31\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<mask id=\"mask0_863_654\"  style={{ maskType: \"alpha\" }} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"31\" height=\"31\">\n<rect width=\"31\" height=\"31\" fill=\"#D9D9D9\"/>\n</mask>\n<g mask=\"url(#mask0_863_654)\">\n<path d=\"M13.5281 28.417C12.9253 28.417 12.3602 28.2878 11.8328 28.0295C11.3054 27.7712 10.8587 27.4052 10.4927 26.9316L3.45312 17.9868L4.06667 17.341C4.49722 16.8889 5.01389 16.6198 5.61667 16.5337C6.21944 16.4475 6.77917 16.5659 7.29583 16.8889L9.68542 18.342V7.75033C9.68542 7.38435 9.8092 7.07758 10.0568 6.83001C10.3043 6.58244 10.6111 6.45866 10.9771 6.45866C11.3431 6.45866 11.6552 6.58244 11.9135 6.83001C12.1719 7.07758 12.301 7.38435 12.301 7.75033V22.992L9.16875 21.0545L12.5271 25.3493C12.6562 25.5 12.8069 25.6184 12.9792 25.7045C13.1514 25.7906 13.3344 25.8337 13.5281 25.8337H20.6646C21.375 25.8337 21.9832 25.5807 22.4891 25.0748C22.995 24.5689 23.2479 23.9607 23.2479 23.2503V18.0837C23.2479 17.7177 23.1241 17.4109 22.8766 17.1633C22.629 16.9158 22.3222 16.792 21.9562 16.792H14.8844V14.2087H21.9562C23.0326 14.2087 23.9476 14.5854 24.701 15.3389C25.4545 16.0923 25.8313 17.0073 25.8313 18.0837V23.2503C25.8313 24.6712 25.3253 25.8875 24.3135 26.8993C23.3017 27.9111 22.0854 28.417 20.6646 28.417H13.5281ZM5.39062 10.9795C5.11076 10.5059 4.89549 9.9946 4.74479 9.44564C4.5941 8.89668 4.51875 8.33158 4.51875 7.75033C4.51875 5.96352 5.14844 4.44043 6.40781 3.18105C7.66719 1.92168 9.19028 1.29199 10.9771 1.29199C12.7639 1.29199 14.287 1.92168 15.5464 3.18105C16.8057 4.44043 17.4354 5.96352 17.4354 7.75033C17.4354 8.33158 17.3601 8.89668 17.2094 9.44564C17.0587 9.9946 16.8434 10.5059 16.5635 10.9795L14.3354 9.68783C14.5076 9.38644 14.6368 9.07967 14.7229 8.76751C14.809 8.45536 14.8521 8.1163 14.8521 7.75033C14.8521 6.67394 14.4753 5.75901 13.7219 5.00553C12.9684 4.25206 12.0535 3.87533 10.9771 3.87533C9.90069 3.87533 8.98576 4.25206 8.23229 5.00553C7.47882 5.75901 7.10208 6.67394 7.10208 7.75033C7.10208 8.1163 7.14514 8.45536 7.23125 8.76751C7.31736 9.07967 7.44653 9.38644 7.61875 9.68783L5.39062 10.9795Z\" fill=\"white\"/>\n</g>\n</svg>);\n\nexport default TouchIcon;\n"
  },
  {
    "path": "src/Resource/Shape/shape.tsx",
    "content": "import React, { CSSProperties } from \"react\";\nconst shapes = {\n  cicle: (\n    <svg\n      width=\"29\"\n      height=\"29\"\n      viewBox=\"0 0 29 29\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <circle cx=\"14.5\" cy=\"14.5\" r=\"11.5\" stroke=\"black\" stroke-width=\"6\" />\n    </svg>\n  ),\n  square: (\n    <svg\n      width=\"25\"\n      height=\"25\"\n      viewBox=\"0 0 25 25\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <rect\n        x=\"3\"\n        y=\"3\"\n        width=\"19\"\n        height=\"19\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  triangle: (\n    <svg\n      width=\"32\"\n      height=\"27\"\n      viewBox=\"0 0 32 27\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M5.6077 24L16 6L26.3923 24H5.6077Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  start: (\n    <svg\n      width=\"37\"\n      height=\"34\"\n      viewBox=\"0 0 37 34\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M18.5 6.47214L20.7514 13.4012L21.2004 14.7832H22.6535H29.9392L24.0449 19.0656L22.8694 19.9197L23.3184 21.3017L25.5698 28.2307L19.6756 23.9483L18.5 23.0942L17.3244 23.9483L11.4302 28.2307L13.6816 21.3017L14.1306 19.9197L12.9551 19.0656L7.06082 14.7832H14.3465H15.7996L16.2486 13.4012L18.5 6.47214Z\"\n        stroke=\"black\"\n        stroke-width=\"4\"\n      />\n    </svg>\n  ),\n  pentagon: (\n    <svg\n      width=\"31\"\n      height=\"29\"\n      viewBox=\"0 0 31 29\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M4.28534 11.8561L15.5 3.7082L26.7147 11.8561L22.431 25.0398H8.56896L4.28534 11.8561Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  hexagon: (\n    <svg\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 27 31\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M3.07661 9.48205L13.5 3.4641L23.9234 9.48205V21.518L13.5 27.5359L3.07661 21.518V9.48205Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  cross: (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 48 49\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M14.0078 17.8038H17.0078V14.8038V7.80371V3.80371H24.0078H31.0078V7.80371V14.8038V17.8038H34.0078H41.0078H45.0078V24.8038V31.8038H41.0078H34.0078H31.0078V34.8038V41.8038V45.8038H24.0078H17.0078V41.8038V34.8038V31.8038H14.0078H7.0078H3.00781V24.8038V17.8038H7.0078H14.0078Z\"\n        stroke=\"black\"\n        stroke-width=\"7\"\n      />\n    </svg>\n  ),\n  rhombus: (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 51 51\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M15.513 15.7015L15.5133 15.7012C18.8428 12.3633 22.0048 9.32509 24.3359 7.12001C24.7553 6.72331 25.1476 6.35381 25.5088 6.01462C25.8574 6.3452 26.2365 6.70727 26.6436 7.09843C28.9315 9.29671 32.0289 12.3422 35.3794 15.7012C38.7441 19.0744 41.8032 22.1405 44.0212 24.3634L44.7901 25.1339L35.1213 34.7795L25.4463 44.4313L15.7714 34.7795L6.10233 25.1337L15.513 15.7015Z\"\n        stroke=\"black\"\n        stroke-width=\"8\"\n      />\n    </svg>\n  ),\n  diamond: (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 57 41\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M43.7269 4.5L51.0098 9.65874L28.5264 34.5089L6.3981 9.61457L13.3178 4.5H43.7269Z\"\n        stroke=\"black\"\n        stroke-width=\"10\"\n      />\n    </svg>\n  ),\n  leaf: (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"-2.5 0 50 45\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M5.87643 20.7882C9.15211 13.6711 16.3212 7.23708 23.6396 4.84533C27.6724 3.52687 38.5667 3.8122 40.0294 5.27415C40.643 5.88746 41.0073 8.93024 40.9999 13.3891C40.99 19.582 40.689 21.094 38.7152 24.8567C35.4797 31.0259 31.5593 35.0313 25.6445 38.2126C20.9463 40.7388 19.8864 40.9799 13.3662 40.9996C8.5803 41.0135 5.87887 40.67 5.1627 39.955C3.3005 38.0954 3.77468 25.3536 5.87643 20.7882Z\"\n        stroke=\"black\"\n        stroke-width=\"8\"\n      />\n    </svg>\n  ),\n  ginkgo: (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 45 45\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M22.1354 7L5 27.2553C5 27.2553 9.375 41 22.1354 41C37.4479 41 40 27.2553 40 27.2553L22.1354 7Z\"\n        stroke=\"black\"\n        stroke-width=\"8\"\n      />\n    </svg>\n  ),\n};\nexport const shapesWithStyle = (style?: CSSProperties, className?: string) => ({\n  cicle: (\n    <svg\n      style={style}\n      className={className}\n      width=\"29\"\n      height=\"29\"\n      viewBox=\"0 0 29 29\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <circle cx=\"14.5\" cy=\"14.5\" r=\"11.5\" stroke=\"black\" stroke-width=\"6\" />\n    </svg>\n  ),\n  square: (\n    <svg\n      style={style}\n      className={className}\n      width=\"25\"\n      height=\"25\"\n      viewBox=\"0 0 25 25\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <rect\n        x=\"3\"\n        y=\"3\"\n        width=\"19\"\n        height=\"19\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  triangle: (\n    <svg\n      className={className}\n      style={style}\n      width=\"32\"\n      height=\"27\"\n      viewBox=\"0 0 32 27\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M5.6077 24L16 6L26.3923 24H5.6077Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  start: (\n    <svg\n      className={className}\n      style={style}\n      width=\"37\"\n      height=\"34\"\n      viewBox=\"0 0 37 34\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M18.5 6.47214L20.7514 13.4012L21.2004 14.7832H22.6535H29.9392L24.0449 19.0656L22.8694 19.9197L23.3184 21.3017L25.5698 28.2307L19.6756 23.9483L18.5 23.0942L17.3244 23.9483L11.4302 28.2307L13.6816 21.3017L14.1306 19.9197L12.9551 19.0656L7.06082 14.7832H14.3465H15.7996L16.2486 13.4012L18.5 6.47214Z\"\n        stroke=\"black\"\n        stroke-width=\"4\"\n      />\n    </svg>\n  ),\n  pentagon: (\n    <svg\n      className={className}\n      style={style}\n      width=\"31\"\n      height=\"29\"\n      viewBox=\"0 0 31 29\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M4.28534 11.8561L15.5 3.7082L26.7147 11.8561L22.431 25.0398H8.56896L4.28534 11.8561Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  hexagon: (\n    <svg\n      className={className}\n      style={style}\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 27 31\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M3.07661 9.48205L13.5 3.4641L23.9234 9.48205V21.518L13.5 27.5359L3.07661 21.518V9.48205Z\"\n        stroke=\"black\"\n        stroke-width=\"6\"\n      />\n    </svg>\n  ),\n  cross: (\n    <svg\n      className={className}\n      style={style}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 48 49\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M14.0078 17.8038H17.0078V14.8038V7.80371V3.80371H24.0078H31.0078V7.80371V14.8038V17.8038H34.0078H41.0078H45.0078V24.8038V31.8038H41.0078H34.0078H31.0078V34.8038V41.8038V45.8038H24.0078H17.0078V41.8038V34.8038V31.8038H14.0078H7.0078H3.00781V24.8038V17.8038H7.0078H14.0078Z\"\n        stroke=\"black\"\n        stroke-width=\"8\"\n      />\n    </svg>\n  ),\n  rhombus: (\n    <svg\n      className={className}\n      style={style}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 51 51\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M15.513 15.7015L15.5133 15.7012C18.8428 12.3633 22.0048 9.32509 24.3359 7.12001C24.7553 6.72331 25.1476 6.35381 25.5088 6.01462C25.8574 6.3452 26.2365 6.70727 26.6436 7.09843C28.9315 9.29671 32.0289 12.3422 35.3794 15.7012C38.7441 19.0744 41.8032 22.1405 44.0212 24.3634L44.7901 25.1339L35.1213 34.7795L25.4463 44.4313L15.7714 34.7795L6.10233 25.1337L15.513 15.7015Z\"\n        stroke=\"black\"\n        stroke-width=\"10\"\n      />\n    </svg>\n  ),\n  diamond: (\n    <svg\n      className={className}\n      style={style}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 57 41\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M43.7269 4.5L51.0098 9.65874L28.5264 34.5089L6.3981 9.61457L13.3178 4.5H43.7269Z\"\n        stroke=\"black\"\n        stroke-width=\"10\"\n      />\n    </svg>\n  ),\n  leaf: (\n    <svg\n      className={className}\n      style={style}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"-2.5 0 50 45\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M5.87643 20.7882C9.15211 13.6711 16.3212 7.23708 23.6396 4.84533C27.6724 3.52687 38.5667 3.8122 40.0294 5.27415C40.643 5.88746 41.0073 8.93024 40.9999 13.3891C40.99 19.582 40.689 21.094 38.7152 24.8567C35.4797 31.0259 31.5593 35.0313 25.6445 38.2126C20.9463 40.7388 19.8864 40.9799 13.3662 40.9996C8.5803 41.0135 5.87887 40.67 5.1627 39.955C3.3005 38.0954 3.77468 25.3536 5.87643 20.7882Z\"\n        stroke=\"black\"\n        stroke-width=\"10\"\n      />\n    </svg>\n  ),\n  ginkgo: (\n    <svg\n      className={className}\n      style={style}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"27\"\n      height=\"31\"\n      viewBox=\"0 0 45 45\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M22.1354 7L5 27.2553C5 27.2553 9.375 41 22.1354 41C37.4479 41 40 27.2553 40 27.2553L22.1354 7Z\"\n        stroke=\"black\"\n        stroke-width=\"10\"\n      />\n    </svg>\n  ),\n});\n\nexport default shapes;\n"
  },
  {
    "path": "src/Style/Cursor.ts",
    "content": "import { Mode } from \"../DataStructure/Mode\";\n\nexport const getCursor = (mode: Mode)=>{\n    let cursor;\n    //chrome has bug here, the cursor won't change sometimes while DOM already updated.\n    switch(mode){\n        case Mode.moving:{\n            cursor = 'grabbing';\n            break;\n        }\n        default:{\n            cursor = 'default';\n            break;\n        }\n    }\n    return cursor;\n}"
  },
  {
    "path": "src/WelcomeTour/Driver.ts",
    "content": "import { driver as Driver, Config } from \"driver.js\";\nimport {t} from 'i18next';\nexport const showTour = async (id: string, callback: Function) => {\n  const driver = Driver();\n  const { getSteps } = await import(/* webpackMode: \"eager\" */ `./Steps/${id}`);\n  const eventListeners: EventListenerOrEventListenerObject[] = [];\n  const touch = window.ontouchend === null;\n  const eventName =// touch ? \"touchend\" : \n  \"click\";\n  const config: Config = {\n    prevBtnText: t('shang-yi-bu'),\n    doneBtnText: t('wan-cheng'),\n    nextBtnText: t('xia-yi-bu'),\n    progressText: \"{{current}} / {{total}}\",\n    showProgress: true,\n    allowClose: false,\n    showButtons: [\"close\"],\n    // onPrevClick:(ele)=>{\n    //   if(ele){\n    //     const element = ele as HTMLElement;\n    //     eventListeners.forEach(listener=>{\n    //       element.removeEventListener('click',listener);\n    //     })\n    //     driver.movePrevious();\n    //   }\n    // },\n    onHighlighted: (ele, step, opt) => {\n      const steps = opt.config.steps!;\n      const last = step === steps[steps.length - 1];\n      const next = steps[opt.state.activeIndex! + 1];\n\n      if (ele) {\n        const element = ele as HTMLElement;\n        const moveToNext = () => {\n          const gotoNext = () => {\n            // element.removeEventListener(eventName, moveToNext);\n            element.removeEventListener(\"click\", moveToNext);\n            element.removeEventListener(\"touchend\", moveToNext);\n            if(driver.getActiveStep()===step)\n            driver.moveNext();\n          };\n          setTimeout(() => {\n            if (!next || document.querySelector(next.element as string)) {\n              gotoNext();\n            }else{\n              setTimeout(()=>{\n                if (!next || document.querySelector(next.element as string))\n                gotoNext()\n              },300)\n            }\n          }, 100);\n        };\n        eventListeners.push(moveToNext);\n        element.addEventListener(\"click\", moveToNext);\n        element.addEventListener(\"touchend\", moveToNext);\n      }\n    },\n    onNextClick: (ele) => {\n      if (ele) {\n        const element = ele as HTMLElement;\n        element.dispatchEvent(\n          new Event(\"click\", { bubbles: true, cancelable: true })\n        );\n      }\n    },\n    steps: getSteps(driver),\n    onDestroyed: (ele,step) => {\n      if (ele) {\n        const element = ele as HTMLElement;\n        if(step.element!==\".tour-btn\")\n        element.dispatchEvent(\n          new Event(\"click\", { bubbles: true, cancelable: true })\n        );\n      }\n      callback();\n    },\n  };\n  driver.setConfig(config);\n\n  driver.drive();\n};\n"
  },
  {
    "path": "src/WelcomeTour/HightLights.tsx",
    "content": "import React from \"react\";\nimport Infinity from \"../Resource/Icon/infinity\";\nimport AirWaveIcon from \"../Resource/Icon/airwave\";\nimport PageViewIcon from \"../Resource/Icon/pageview\";\nimport BoltIcon from \"../Resource/Icon/bolt\";\nimport TouchIcon from \"../Resource/Icon/touch\";\nimport AutoIcon from \"../Resource/Icon/auto\";\nimport ExportIcon from \"../Resource/Icon/export\";\nimport {t} from 'i18next';\nexport const hightLights = [\n  {\n    id:'common-operation',\n    icon: <Infinity />,\n    title: t('wu-xian-zi-chan'),\n    subTitle: t('wu-xian-da-hua-bu'),\n    introText: [\n      [false, t('zhi-chi'), t('wu-xian-tiao-xian-lu')],\n      [false, t('zhi-chi'), t('wu-xian-ge-zhan-dian')],\n    ],\n    more: t('le-jie-ji-ben-cao-zuo')\n  },\n  {\n    id:'line-card',\n    icon: <AirWaveIcon className=\"air\"/>,\n    title: t('ling-huo-zou-xian'),\n    subTitle: t('yi-tiao-xian-lu-neng-duo-ci-chuan-guo-tong-yi-zhan'),\n    introText: [\n      [false, t('zhi-chi'), t('q-zi-zou-xian-yu-zou-xian')],\n      [false, t('zhi-chi-she-zhi'), t('zhi-xian')],\n    ],\n    more: t('le-jie-xian-lu-she-zhi')\n  },\n  {\n    id:'station-card',\n    icon: <PageViewIcon />,\n    title: t('fang-bian-cha-kan'),\n    subTitle: t('ka-pian-hua-zhan-shi-zhan-dian-yu-xian-lu'),\n    introText: [\n      [false, t('zhan-dian-xian-lu-hu-xiang'), t('guan-lian')],\n      [true, t('gao-liang'), t(\"zhan-shi-xuan-zhong-zhan-dian-yu-xian-lu\"),]\n    ],\n    more: t('le-jie-zhan-dian-ka-pian')\n  },\n  {\n    id:'quick-edit',\n    icon: <BoltIcon />,\n    title: t('gao-xiao-bian-ji'),\n    subTitle: t('lian-xu-chuang-jian-zhan-dian-mo-shi'),\n    introText: [\n      [true, t('lian-xu-tian-jia-zhan-dian'), t('mo-shi')],\n      [false, t('zhi-chi'), t('che-hui'), t('yu'), t('zhong-zuo')],\n    ],\n    more: t('le-jie-kuai-su-chuang-jian')\n  },\n  {\n    id:'mobile',\n    icon: <TouchIcon />,\n    title: t('yi-dong-duan-zhi-chi'),\n    subTitle: t('wan-zheng-de-chu-kong-shi-jian-zhi-chi'),\n    introText: [\n      [true, t('dan-zhi'), t('tuo-dong'), t('shuang-zhi'), t('suo-fang-di-tu')],\n      [false, t('shi-bie-dong-zuo-yi-tu'), t('jian-shao-wu-cao-zuo')],\n    ],\n    more: t('zai-ping-ban-shang-ti-yan')\n  },\n  {\n    id:'tag-setting',\n    icon: <AutoIcon />,\n    title: t('zi-dong-bi-rang'),\n    subTitle: t('zi-dong-tian-jia-pian-yi-zhi'),\n    introText: [\n      [false, t('gong-xian-xian-lu'), t('bu-hui-zhong-die')],\n      [false, t('zhan-dian-ming-cheng-zi-dong-xuan-ze-bai-fang-wei-zhi')],\n    ],\n    more: t('le-jie-biao-qian-she-zhi')\n  },\n  {\n    id:'export',\n    icon: <ExportIcon />,\n    title: t('dao-ru-dao-chu'),\n    subTitle: t('dao-chu-gao-fen-bian-shuai-tu-pian'),\n    introText: [\n      [false, t('dao-chu'), t('pngsvg-tu-pian')],\n      [false, t('zhi-chi-cong-mo-ban-chuang-jian')],\n    ],\n    more: t('le-jie-dao-ru-dao-chu')\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/common-operation.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport {t} from 'i18next';\n\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".ScaleLayer\",\n    onHighlighted:()=>{},\n    popover: {\n      title: t('tour.tryScale'),\n      description: window.ontouchend === null? t('tour.touchScale'): t('tour.mouseScale'),\n      showButtons:['next'],\n      onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".title .click-panel\",\n    popover: {\n      title: t('tour.clickTile'),\n      description: t('tour.clickOpenMenu'),\n    },\n  },\n  {\n    element: \".title\",\n    popover: {\n      title: t('zai-ci-dian-ji-biao-ti'),\n      description: t('ke-yi-xiu-gai-biao-ti'),\n    },\n  },\n  {\n    element: \".menu\",\n    popover: {\n      title: t('dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan'),\n      description: t('tui-chu-cai-dan'),\n    },\n  },\n  {\n    element: \".station-descend-31\",\n    popover: {\n      title: t('dian-ji-zhan-dian'),\n      description: t('yi-da-kai-zhan-dian-ka-pian'),\n    },\n  },\n  {\n    element: \".station-card\",\n    popover: {\n      title: t('zhan-dian-ka-pian'),\n      description: t('ke-yi-zai-zhe-li-bian-ji-zhan-dian-de-suo-you-she-zhi'),\n      showButtons:[\"next\"],\n    //   onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".ScaleLayer\",\n    popover: {\n      title: t('chang-shi-dian-ji-xian-lu'),\n      description: t('tu-zhong-de-cai-se-xian-tiao-ji-wei-xian-lu-ru-guo-wu-fa-xuan-zhong-ke-yi-chang-shi-fang-da-di-tu-zai-dian-xuan'),\n    },\n  },\n  {\n    element: \".line-card\",\n    popover: {\n      title: t('xian-lu-ka-pian'),\n      description: t('ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi'),\n      showButtons:[\"next\"],\n    //   onNextClick:driver.moveNext\n    },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/export.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport { browserInfo } from \"../../Common/util\";\nimport {t} from 'i18next';\nexport const getSteps = (driver: Driver): DriveStep[] => {\n  const { engine } = browserInfo;\n  const webkit = engine.name === \"WebKit\";\n  return[\n  {\n    element: \".title .click-panel\",\n    popover: {\n      title: t('dian-ji-biao-ti'),\n      description: t('dian-ji-biao-ti-da-kai-cai-dan'),\n    },\n  },\n  {\n    element: \".existed-map-btn\",\n    popover: {\n      title: t('cong-mo-ban-xin-jian'),\n      description: t('zai-yi-you-de-di-tu-shang-xiu-gai'),\n    },\n  },\n  {\n    element: \".tools\",\n    onHighlighted:()=>{},\n    popover: {\n      title: t('xuan-ze-yi-ge-ni-xi-huan-de-cheng-shi'),\n      description: t('ran-hou-dian-ji-xia-yi-bu'),\n      showButtons:[\"next\"],\n      onNextClick:()=>{\n        driver.moveNext();\n      }\n    },\n  },\n  {\n    element: \".confirm-add-from-existed-map-btn\",\n    popover: {\n      title: t('yi-ci-wei-mo-ban-xin-jian'),\n      description: t('que-ren-xin-jian-qian-qing-que-bao-yi-jing-bao-cun-le-dang-qian-de-di-tu'),\n    },\n  },\n  {\n    element: \".title .click-panel\",\n    popover: {\n      title: t('da-kai-cai-dan'),\n      description: t('xuan-ze-zuo-wei-wen-jian-dao-chu'),\n    },\n  },\n  {\n    element: \".export-as-file-btn\",\n    popover: {\n      title: t('zuo-wei-wen-jian-dao-chu'),\n      description: t('xuan-ze-zuo-wei-wen-jian-dao-chu-0'),\n    },\n  },\n  {\n    element: \".import-file-btn\",\n    onHighlighted:()=>{},\n    popover: {\n      title: t('dao-ru-gang-cai-dao-chu-wen-jian'),\n      description: t('xia-ci-dian-ji-dao-ru-wen-jian-ke-yi-ji-xu-bian-ji'),\n      showButtons:[\"next\"],\n      onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: `.export-as${webkit?'-svg':''}-image-btn`,\n    popover: {\n      title: t('dao-chu-tu-pian'),\n      description: t('dian-ji-dao-chu-tu-pian-dao-chu-ke-neng-hui-dao-zhi-ka-dun-ji-miao-shu-yu-zheng-chang-xian-xiang'),\n    },\n  },\n  {\n    element: `.recover-btn`,\n    popover: {\n      title: t('cong-huan-cun-zhong-hui-fu-shu-ju'),\n      description: t('ru-guo-mei-bao-cun-de-shi-hou-bu-xiao-xin-shua-xin-ke-yi-dian-ji-zhe-li-hui-fu-shu-ju'),\n    },\n  },\n  {\n    element: `.export-recover-btn`,\n    popover: {\n      title: t('dao-chu-hui-fu-shu-ju'),\n      description: t('ru-guo-mou-yi-bu-cao-zuo-hou-dao-zhi-bao-cuo-huo-beng-kui-dian-ji-zhe-li-dao-chu-zui-hou-yi-ci-zheng-que-de-shu-ju-ru-guo-yu-dao-zhe-zhong-qing-kuang-qing-fan-kui-gei-zuo-zhe'),\n    },\n  },\n];\n}"
  },
  {
    "path": "src/WelcomeTour/Steps/line-card.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport {t} from 'i18next';\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".ScaleLayer\",\n    popover: {\n      title: t('dian-ji-ren-yi-xian-lu'),\n      description: t('tu-zhong-cai-se-qu-xian-biao-shi-di-tie-xian-lu'),\n    },\n  },\n  {\n    element: \".line-card\",\n    popover: {\n      title: t('xian-lu-ka-pian-0'),\n      description: t('ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi-0'),\n      showButtons:[\"next\"],\n      // onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".bend-first\",\n    popover: {\n      title: t('dian-ji-ci-chu-kong-zhi-xian-lu-zai-liang-zhan-zhi-jian-de-zou-xiang'),\n      description: t('zhan-dian-qu-jian-lian-xian-zhi-you-liang-zhong-fang-shi-xie-xian-yu-zhi-xian'),\n    },\n  },\n  {\n    element: \".expand\",\n    popover: { title: t('fang-da-an-niu'), description: t('ke-yi-tuo-kuan-xian-lu-ka-pian') },\n  },\n  {\n    element: \".shrink\",\n    popover: { title: t('suo-xiao-an-niu'), description: t('zai-suo-xiao-zhuang-tai-ke-yi-dian-ji-geng-duo-she-zhi') },\n  },\n  {\n    element: \".edit\",\n    popover: { title: t('bian-ji-an-niu'), description: t('jin-ru-geng-duo-she-zhi-mian-ban') },\n  },\n  {\n    element: \".name-detail\",\n    popover: { title: t('ci-chu-xiu-gai-xian-lu-ming-cheng-yu-biao-shi'), description: t('pai-xu-ke-yi-kong-zhi-xian-lu-jian-de-zhe-dang-guan-xi') ,showButtons:[\"next\"],onNextClick:driver.moveNext},\n  },\n  {\n    element: \".edit-tool.color\",\n    popover: { title: t('dian-ji-ci-chu-xiu-gai-xian-lu-biao-shi-se'), description: t('zuo-xia-jiao-de-yan-se-xuan-ze-qi-ke-yi-qu-se') ,side:\"right\"},\n  },\n  {\n    element: \".edit-tool.operation\",\n    popover: { title: t('dian-ji-ci-chu-shan-chu-xian-lu-huo-zhe-she-zhi-zhi-xian'), description: t('she-zhi-zhi-xian-hou-xian-lu-hui-yi-xu-xian-xian-shi-qie-lian-jie-chu-bu-zai-xian-shi-ba-shou'),side:\"right\" },\n  },\n  {\n    element: \".done\",\n    popover: { title: t('dian-ji-ci-chu-wan-cheng-she-zhi'), description: t('hui-dao-zhan-dian-ye') },\n  },\n  {\n    element: \".stations-count\",\n    popover: { title: t('xian-shi-tu-jing-zhan-dian-ka-pian'), description: t('dian-ji-ci-chu-suo-yi-tu-jing-de-zhan-dian-ka-pian') },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/quick-edit.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport {t} from 'i18next';\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".title .click-panel\",\n    popover: {\n      title: t('da-kai-cai-dan-0'),\n      description: t('dian-ji-biao-ti-da-kai-cai-dan-0'),\n    },\n  },\n  {\n    element: \"#menu-add-station\",\n    popover: {\n      title: t('dian-ji-tian-jia-zhan-dian'),\n      description: t('jin-ru-tian-jia-zhan-dian-mo-shi'),\n    },\n  },\n  {\n    element: \".ScaleLayer\",\n    onHighlighted: () => {},\n    popover: {\n      title: t('dian-ji-ren-yi-kong-bai-chu-tian-jia-zhan-dian'),\n      description: t('tian-jia-hao-zhi-hou-dian-ji-xia-yi-bu-jian-yi-nin-zai-ping-mu-zuo-shang-jiao-de-kong-bai-qu-yu-tian-jia-san-ge-zhan-dian'),\n      showButtons: [\"next\"],\n      onNextClick: () => {\n        driver.moveNext();\n      },\n    },\n  },\n  {\n    element: \"#add-station-finish-btn\",\n    popover: { title: t('dian-ji-wan-cheng'), description: t('tui-chu-bian-ji-mo-shi') },\n  },\n  {\n    element: \".station-descend-1\",\n    popover: {\n      title: t('dian-ji-gang-cai-chuang-jian-de-zhan-dian'),\n      description: t('da-kai-zhan-dian-xin-xi-ka-pian'),\n    },\n  },\n  {\n    element: \".station-card-operation\",\n    popover: { title: t('dian-ji-cao-zuo-xuan-xiang-ka'), description: t('wo-men-lai-tian-jia-xian-lu') },\n  },\n  {\n    element: \".add-new-line-btn\",\n    popover: {\n      title: t('dian-ji-yi-ci-wei-qi-dian-xin-jian-xian-lu'),\n      description: t('jin-ru-tian-jia-xian-lu-mo-shi'),\n    },\n  },\n  {\n    element: \".station-descend-2\",\n    popover: {\n      title: t('dian-ji-zhan-dian-0'),\n      description: t('lian-jie-zhan-dian'),\n    },\n  },\n  {\n    element: \".station-descend-3\",\n    popover: {\n      title: t('dian-ji-zhan-dian'),\n      description: t('lian-jie-zhan-dian'),\n    },\n  },\n  {\n    element: \"#add-line-finish-btn\",\n    popover: { title: t('dian-ji-wan-cheng'), description: t('xian-lu-jiu-chuang-jian-hao-le') },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/skip.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\n\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".title .click-panel\",\n    // onHighlighted:()=>{},\n    popover: {\n      title: \"下次可以点这里再次打开教程\",\n      description: \"点击标题打开菜单\",\n      showButtons:[\"next\"],\n      // onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".tour-btn\",\n    onHighlighted:()=>{},\n    popover: {\n      title: \"使用教程\",\n      description: \"点这里再次打开\",\n      showButtons:[\"next\"],\n      onNextClick: driver.moveNext,\n    },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/station-card.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport {t} from 'i18next';\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".station-descend-31\",\n    popover: {\n      title: t('dian-ji-zhan-dian'),\n      description: t('yi-da-kai-zhan-dian-ka-pian-0'),\n    },\n  },\n  {\n    element: \".station-card\",\n    popover: {\n      title: t('zhan-dian-ka-pian'),\n      description: t('ke-yi-zai-zhe-li-bian-ji-zhan-dian-de-suo-you-she-zhi'),\n      showButtons:[\"next\"],\n      // onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".name-detail\",\n    popover: {\n      title: t('bian-ji-zhan-dian-wei-zhi'),\n      description: t('dian-ji-zuo-biao-zhi-hou-shi-yong-shu-biao-gun-lun-ke-yi-jing-que-tiao-jie'),\n      showButtons:[\"next\"],\n      // onNextClick:driver.moveNext\n    },\n  },\n  {\n    element: \".edit-tool.color\",\n    popover: { title: t('dian-ji-ci-chu-xiu-gai-zhan-dian-xing-zhuang'), description: t('xiu-gai-xing-zhuang') ,side:\"right\"},\n  },\n  {\n    element: \".edit-tool.operation\",\n    popover: { title: t('dian-ji-ci-chu-shan-chu-zhan-dian-huo-xin-jian-xian-lu'), description: t('shan-chu-huo-xin-jian'),side:\"right\" },\n  },\n  {\n    element: \".edit-tool.operation.tag\",\n    popover: { title: t('dian-ji-ci-chu-she-zhi-zhan-dian-ming-cheng-wei-zhi'), description: t('zhan-dian-ming-wei-zhi') },\n  },\n  {\n    element: \".tag-detail\",\n    popover: { title: t('dian-ji-hui-se-de-fang-kuai-xuan-ze-fang-wei'), description: t('dian-ji-zhong-jian-de-wen-zi-hui-fu-zi-dong-wei-zhi'),showButtons:['next'],onNextClick:driver.moveNext },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/Steps/tag-setting.ts",
    "content": "import { DriveStep, Driver } from \"driver.js\";\nimport {t} from 'i18next';\nexport const getSteps = (driver: Driver): DriveStep[] => [\n  {\n    element: \".title .click-panel\",\n    popover: {\n      title: t('dian-ji-biao-ti'),\n      description: t('dian-ji-biao-ti-da-kai-cai-dan-1'),\n    },\n  },\n  {\n    element: \".auto-hidden-btn\",\n    popover: {\n      title: t('guan-bi-zi-dong-yin-cang'),\n      description: t('zhan-dian-ming-hui-zai-di-tu-suo-fang-dao-xiao-chi-du-shi-zi-dong-yin-cang-guan-bi-zi-dong-yin-cang-yi-que-bao-ke-yi-yi-zhi-xian-shi-zhan-dian-ming-cheng'),\n    },\n  },\n  {\n    element: \".menu\",\n    popover: {\n      title: t('dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan-0'),\n      description: t('tui-chu-cai-dan-0'),\n    },\n  },\n  {\n    element: \".station-descend-31\",\n    popover: {\n      title: t('dian-ji-zhan-dian'),\n      description: t('yi-da-kai-zhan-dian-ka-pian-1'),\n    },\n  },\n  {\n    element: \".edit-tools\",\n    popover: { title: t('zai-zhe-li-xiang-xia-gun-dong-yi-xia'), description: t('zai-dian-ji-biao-qian-an-niu') },\n  },\n  {\n    element: \".tag-detail\",\n    popover: { title: t('chang-shi-gai-bian-zhan-dian-ming-dao-you-xia-jiao'), description: t('dian-ji-you-xia-jiao-de-hui-se-fang-kuai') },\n  },\n  {\n    element: \".station-name-descend-31\",\n    popover: { title: t('ke-yi-kan-dao-zhan-dian-ming-yi-jing-wei-yu-zhan-dian-you-xia-jiao-le'), description: t('ke-yi-yong-zhe-zhong-fang-fa-xiu-gai-zhan-dian-ming-wei-zhi'), showButtons:[\"next\"],onNextClick:driver.moveNext },\n  },\n  {\n    element: \".tag-item.center\",\n    popover: { title: t('dian-ji-zhong-jian-de-wen-zi-hui-fu-dao-zi-dong-xuan-ze-wei-zhi'), description: t('hui-fu-dao-zi-dong-xuan-ze-wei-zhi') },\n  },\n];\n"
  },
  {
    "path": "src/WelcomeTour/WelcomeTour.scss",
    "content": ".welcome-tour-container {\n    position: fixed;\n    height: 100vh;\n    width: 100vw;\n    left: 0;\n    top: 0;\n    background-color: rgba(0, 0, 0, 0.4);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    z-index: 2000;\n    font-weight: 500;\n    font-size: 18px;\n    .welcome-tour {\n        margin-top: -10vh;\n        // width: 800px;\n        // min-width: 45vw;\n        width: 80vw;\n        max-width: 800px;\n        height: 475px;\n        background-color: #454545;\n        border-radius: 12px;\n        .header {\n            margin: 33.3px 33.3px 20px 33.3px;\n            white-space: nowrap;\n            position: relative;\n            .icon {\n                img {\n                    width: 40px;\n                    height: 40px;\n                    border-radius: 5px;\n                }\n            }\n            .title {\n                display: inline-block;\n                margin-left: 13px;\n                vertical-align: top;\n                .sub-title {\n                    font-size: 12px;\n                    color: white;\n                    width: fit-content;\n                    margin-top: -2px;\n                }\n                .main-title {\n                    color: white;\n                    font-weight: 800;\n                    width: fit-content;\n                }\n            }\n            .control {\n                display: inline-flex;\n                vertical-align: top;\n                font-size: 12px;\n                position: absolute;\n                right: 0;\n                height: 40px;\n                justify-content: center;\n                align-items: center;\n\n                .skip-tour {\n                    color: rgba(255, 255, 255, 0.6);\n                    margin: 0 20px;\n                    cursor: pointer;\n                    // text-transform: capitalize;\n                }\n                .start-tour {\n                    text-transform: capitalize;\n                    cursor: pointer;\n                    color: white;\n                    padding: 7.33px 20px;\n                    background-color: #2196f3;\n                    border-radius: 35px;\n                }\n            }\n        }\n        .divider {\n            border-bottom: rgba(255, 255, 255, 0.27) solid 1px;\n        }\n        .body {\n            white-space: nowrap;\n            overflow-x: scroll;\n            position: relative;\n            &::-webkit-scrollbar {\n                display: none;\n            }\n            .intro {\n                display: inline-block;\n                color: white;\n                width: 285px;\n                margin-left: 38px;\n                margin-top: 36.67px;\n                vertical-align: top;\n                &:last-child{\n                    margin-right: 38px;\n                }\n                .hight-light {\n                    display: inline-flex;\n                    justify-content: center;\n                    align-items: center;\n                    background-color: #727272;\n                    padding: 4px 15px;\n                    border-radius: 35px;\n                    .icon {\n                        height: 20px;\n                        width: 20px;\n                        svg {\n                            height: 20px;\n                            width: 20px;\n                        }\n                        .air{\n                            width: 16px;\n                            margin-left: 2px;\n                        }\n                    }\n                    .title {\n                        margin-left: 5px;\n                        text-transform: capitalize;\n                    }\n                }\n                .detail-card {\n                    height: 240px;\n                    background-color: #727272;\n                    border-radius: 14px;\n                    margin-top: 17.3px;\n                    display: flow-root;\n                    position: relative;\n                    .qrcode-container{\n                        position: absolute;\n                        border-radius: 14px;\n                        margin: auto;\n                        left: 0;\n                        right: 0;\n                        top:0;\n                        bottom: 0;\n                        width: 100%;\n                        height: 100%;\n                        background-color: #0000002e;\n                        backdrop-filter: blur(10px);\n                        cursor: pointer;\n                        opacity: 0;\n                        pointer-events: none;\n                        transition: 0.3s ease-in-out;\n                        &.show{\n                            opacity: 1;\n                            pointer-events: auto;\n                        }\n                      canvas{\n                        position: absolute;\n                        border-radius: 14px;\n                        margin: auto;\n                        left: 0;\n                        right: 0;\n                        top:0;\n                        bottom: 0;\n                    }  \n                    }\n                    \n                    .title {\n                        margin-top: 20.67px;\n                        margin-left: 24px;\n                        width: 265px;\n                        white-space: normal;\n                        text-transform: capitalize;\n                    }\n                    .left-down {\n                        position: absolute;\n                        left: 24px;\n                        bottom: 20.67px;\n                        .intro-text {\n                            .intro-text-line {\n                                &:not(.line-card-text){\n                                  text-transform: capitalize;  \n                                }\n                                :not(.emphasis) {\n                                    color: rgba(255, 255, 255, 0.6);\n                                }\n                            }\n                        }\n                        .more {\n                            margin-top: 26px;\n                            cursor: pointer;\n                            &:hover{\n                                // text-decoration: underline;\n                                opacity: 0.9;\n                            }\n                            .more-text {\n                                text-transform: capitalize;\n                                &.finished{\n                                    opacity: 0.6;\n                                }\n                            }\n                            .more-icon {\n                                height: 20px;\n                                width: 28px;\n                                vertical-align: top;\n                                display: inline-block;\n                                svg {\n                                    height: 28px;\n                                    width: 28px;\n                                    &.finished{\n                                        width: 21px;\n                                        // margin-top: -1px;\n                                        margin-left: 2px;\n                                        opacity: 0.6;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/WelcomeTour/WelcomeTour.tsx",
    "content": "import React, {\n  LegacyRef,\n  MutableRefObject,\n  RefObject,\n  useEffect,\n  useRef,\n  useState,\n  useTransition,\n} from \"react\";\nimport \"./WelcomeTour.scss\";\nimport Infinity from \"../Resource/Icon/infinity\";\nimport GoToIcon from \"../Resource/Icon/goto\";\nimport { hightLights } from \"./HightLights\";\nimport classNames from \"classnames\";\nimport { onWheelX } from \"../Common/util\";\nimport { showTour } from \"./Driver\";\nimport { ShowTourProps, UserDataType } from \"../Data/UserData\";\nimport FinishedIcon from \"../Resource/Icon/finished\";\nimport QRCode from \"qrcode\";\nimport { useTranslation } from \"react-i18next\";\nexport function WelcomeTour({\n  showTour: show,\n  setShowTour: setShow,\n}: ShowTourProps) {\n  const [qrCode, setQRCode] = useState(false);\n  const {t} = useTranslation();\n  const [visitedSteps, setVisitedSteps] = useState<string[]>(() => {\n    const visitedStepsJson = localStorage.getItem(\"visited-steps\");\n    return visitedStepsJson ? JSON.parse(visitedStepsJson) : [];\n  });\n  const setVisited = (step: string) => {\n    const steps = visitedSteps.concat([step]);\n    localStorage.setItem(\"visited-steps\", JSON.stringify(steps));\n    setVisitedSteps(steps);\n  };\n  const reset = () => {\n    localStorage.setItem(\"visited-steps\", JSON.stringify([]));\n    setVisitedSteps([]);\n    localStorage.setItem(\"skip-tour-viewed\", \"Y\");\n  };\n  const next = hightLights.find(\n    (highlight) => !visitedSteps.includes(highlight.id)\n  );\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const showQRCode = () => {\n    setQRCode(true);\n    setVisited(\"mobile\");\n    setTimeout(() => {\n      QRCode.toCanvas(canvasRef.current, window.location.href);\n    });\n  };\n  const scrollToNext = ()=>{\n    setTimeout(() => {\n      const contianer = document.querySelector(\".welcome-tour .body\");\n      if(next && contianer){\n        const nextIntro = document.querySelector(`.intro-${next.id}`)\n        if(nextIntro){\n          const {offsetLeft} = nextIntro as HTMLDivElement;\n          contianer.scrollTo(offsetLeft-38,0);\n        }\n      }\n    },100);\n  }\n  useEffect(() => {\n    scrollToNext();\n  }, []);\n  return (\n    <div\n      className=\"welcome-tour-container\"\n      style={show ? {} : { display: \"none\" }}\n    >\n      <div className=\"welcome-tour\">\n        <div className=\"header\">\n          <span className=\"icon\">\n            <img src=\"/app-icon.png\" />\n          </span>\n          <span className=\"title\">\n            <div className=\"sub-title\">{t('welcome.welcome')}</div>\n            <div className=\"main-title\">{t('welecome.minimetroweb')}</div>\n          </span>\n          <div className=\"control\">\n            {next ? (\n              <>\n                <span\n                  className=\"skip-tour\"\n                  onClick={() => {\n                    setShow(false);\n                    // if (!localStorage.getItem(\"skip-tour-viewed\"))\n                    //   showTour(\"skip\", () => {\n                        localStorage.setItem(\"skip-tour-viewed\", \"Y\");\n                    //   });\n                  }}\n                >\n                  {t('welcome.skip')}\n                </span>\n                <span\n                  className=\"start-tour\"\n                  onClick={() => {\n                    if (next.id === \"mobile\") {\n                      showQRCode();\n                    } else {\n                      setShow(false);\n                      showTour(next.id, () => {\n                        setShow(true);\n                        setVisited(next.id);\n                        scrollToNext();\n                      });\n                    }\n                  }}\n                >\n                  {visitedSteps.length ? t('welcome.goOn') : \"\"}\n                  {next.more}\n                </span>\n              </>\n            ) : (\n              <>\n                <span className=\"skip-tour\" onClick={reset}>\n                  {t('welcome.restart')}\n                </span>\n                <span\n                  className=\"start-tour\"\n                  onClick={() => {\n                    localStorage.setItem(\"skip-tour-viewed\", \"Y\");\n                    setShow(false);\n                  }}\n                >\n                  {t('welcome.done')}\n                </span>\n              </>\n            )}\n          </div>\n        </div>\n        <div className=\"divider\"></div>\n        <div className=\"body\" onWheel={onWheelX}>\n          {hightLights.map((hightLight) => {\n            const { id, icon, title, subTitle, introText, more } = hightLight;\n            const finished = visitedSteps.includes(id);\n            return (\n              <div className={classNames({ intro: 1, [\"intro-\" + id]: 1 })}>\n                <div className=\"hight-light\">\n                  <span className=\"icon\">{icon}</span>\n                  <span className=\"title\">{title}</span>\n                </div>\n                <div className=\"detail-card\">\n                  <div className=\"title\">{subTitle}</div>\n                  <div className=\"left-down\">\n                    <div className=\"intro-text\">\n                      {introText.map((line) => {\n                        const emphasisStart = line[0];\n                        const lineText = line.slice(1);\n                        return (\n                          <div className={`intro-text-line ${id}-text`}>\n                            {lineText.map((text, index) => {\n                              const emphasis =\n                                (Number(emphasisStart) + index) % 2;\n                              return (\n                                <span className={classNames({ emphasis })}>\n                                  {text}\n                                </span>\n                              );\n                            })}\n                          </div>\n                        );\n                      })}\n                    </div>\n                    <div\n                      className=\"more\"\n                      onClick={() => {\n                        if (id === \"mobile\") {\n                          showQRCode();\n                        } else {\n                          showTour(id, () => {\n                            setVisited(id);\n                            setShow(true);\n                            scrollToNext();\n                          });\n                          setShow(false);\n                        }\n                      }}\n                    >\n                      <span\n                        className={classNames({ \"more-text\": 1, finished })}\n                      >\n                        {more}\n                      </span>\n                      <span className=\"more-icon\">\n                        {finished ? (\n                          <FinishedIcon className=\"finished\" />\n                        ) : (\n                          <GoToIcon />\n                        )}\n                      </span>\n                    </div>\n                  </div>\n                  {id === \"mobile\" ? (\n                    <div\n                      className={classNames({\n                        \"qrcode-container\": 1,\n                        show: qrCode,\n                      })}\n                      onClick={() => setQRCode(false)}\n                    >\n                      <canvas id=\"qrcode\" ref={canvasRef} />\n                    </div>\n                  ) : (\n                    <></>\n                  )}\n                </div>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/i18n/config.ts",
    "content": "\nimport i18n from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport translation_en from './locales/en.json';\nimport translation_zh from './locales/zh.json';\nimport LanguageDetector from 'i18next-browser-languagedetector';\nconst resources = {\n  en: { translation: translation_en },\n  zh: { translation: translation_zh },\n};\n\ni18n\n  .use(LanguageDetector) \n  .use(initReactI18next)\n  .init({\n    resources,\n    fallbackLng: 'en',\n    detection: {\n      order: ['queryString', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],\n      caches: ['localStorage', 'cookie']\n    },\n    interpolation: { escapeValue: false },\n  });\n\nexport default i18n;\n"
  },
  {
    "path": "src/i18n/locales/en.json",
    "content": "{\n  \"language\": \"english\",\n  \"menu\": {\n    \"alreadyAddStations\": \"{{count}} stations added\",\n    \"clickBlankToAddStation\": \"Click on the blank space to add a new station\",\n    \"redo\": \"Redo\",\n    \"withdraw\": \"Withdraw\",\n    \"AutoHidden\": \" Auto Hide\",\n    \"addStation\": \"Add Station\",\n    \"alreadyModified\": \"Modified {{count}} times\",\n    \"back\": \"Return\",\n    \"backgroudSetting\": \"Background Settings\",\n    \"cancel\": \"Cancel\",\n    \"changeBackgroudImage\": \"Modify Background Image\",\n    \"changeStationPosition\": \"Adjust Station Location\",\n    \"chooseALineFirst\": \"First select a line, then click\",\n    \"chooseAMap\": \"Choose a Map\",\n    \"clickAddStationToLine\": \"Click the station to insert it into the {{insertIndex}} station of {{lineName}}\",\n    \"deleteImage\": \"Delete Picture\",\n    \"done\": \"Finish\",\n    \"dragToChangePoistion\": \"Drag station to change location\",\n    \"hidden\": \"Hide\",\n    \"importBackgroudImage\": \"Import Background Image\",\n    \"importImage\": \"Import Picture\",\n    \"lightYellow\": \"Yellow\",\n    \"line\": \"Line\",\n    \"show\": \"Show\",\n    \"station\": \"Station\",\n    \"stationName\": \" Station Name\",\n    \"transparent\": \"Transparent\",\n    \"turnOff\": \"Disable\",\n    \"turnOn\": \"Enable\",\n    \"useTemplate\": \"Confirm\",\n    \"white\": \"White\",\n    \"RMP\": \"Rail Map Toolkit\",\n    \"about\": \"About\",\n    \"addBackgroundImage\": \"Set Background...\",\n    \"addFromTemplate\": \"Create Map From Template...\",\n    \"addNewMap\": \"New Blank Map...\",\n    \"author\": \"Author: Ryan\",\n    \"data\": \"Data\",\n    \"exportAsFile\": \"Export as File...\",\n    \"exportAsImage\": \"Export as Image...\",\n    \"exportAsSVG\": \"Export as Vector Image...\",\n    \"exportRecoveryData\": \"Export Recovered Data...\",\n    \"guide\": \"Usage Tutorial...\",\n    \"importFile\": \"Import File...\",\n    \"insertStation\": \"Insert Station...\",\n    \"mediateMap\": \"Centered Roadmap...\",\n    \"projectAddress\": \"Project Address...\",\n    \"recoverData\": \"Recover Data...\",\n    \"version\": \"Version: \",\n    \"videoGuild\": \"Video Tutorial...\",\n    \"symbol\": \"logo\",\n    \"newMap\": \"New Map\",\n    \"switchLanguage\": \"使用中文\"\n  },\n  \"bei-jing\": \"Beijing\",\n  \"chang-sha\": \"Changsha\",\n  \"guang-zhou\": \"Guangzhou\",\n  \"shang-hai\": \"Shanghai\",\n  \"shen-zhen\": \"Shenzhen\",\n  \"tian-jin\": \"Tianjin\",\n  \"xiang-gang\": \"Hongkong\",\n  \"station\": {\n    \"auto\": \"automatic\",\n    \"delete\": \"Delete Station...\",\n    \"down\": \"bottom\",\n    \"downLeft\": \"lower left\",\n    \"left\": \"left side\",\n    \"leftUp\": \"upper left\",\n    \"lines\": \" Lines\",\n    \"operateDes\": \"new line / delete\",\n    \"operation\": \"Operate\",\n    \"poisition\": \"Position\",\n    \"remove\": \"Remove From {{lineName}}({{stationIndex}})\",\n    \"right\": \"right side\",\n    \"rightDown\": \"lower right\",\n    \"shape\": \"Shape\",\n    \"startHere\": \"New Line Starts Here...\",\n    \"stationName\": \"Label\",\n    \"up\": \"top\",\n    \"upRight\": \"upper right\",\n    \"x\": \"x-axios\",\n    \"y\": \"y-axios\"\n  },\n  \"shape\": {\n    \"cicle\": \"circle\",\n    \"cross\": \"cross\",\n    \"diamond\": \"diamond\",\n    \"ginkgo\": \"ginkgo\",\n    \"hexagon\": \"hexagon\",\n    \"leaf\": \"leaf\",\n    \"pentagon\": \"pentagon\",\n    \"rhombus\": \"diamond\",\n    \"square\": \"square\",\n    \"start\": \"star\",\n    \"triangle\": \"triangle\"\n  },\n  \"line\": {\n    \"asSubline\": \"Set as Subline line\",\n    \"bendFirst\": \"Bend First\",\n    \"color\": \"Color\",\n    \"delete\": \"delete\",\n    \"deleteLine\": \"Delete Line...\",\n    \"done\": \"Done\",\n    \"fromTo\": \"From {{from}} to {{to}}\",\n    \"insertHere\": \"insert here\",\n    \"insertStation\": \"insert here\",\n    \"name\": \"name\",\n    \"notInUse\": \"Not Yet Open\",\n    \"notSubLineAnymore\": \"Not as Subline\",\n    \"operation\": \"Operate\",\n    \"order\": \"order\",\n    \"stations\": \" Stations\",\n    \"straight\": \"Linar First\"\n  },\n  \"opacity\": \"Opacity\",\n  \"recover\": {\n    \"subTitle\": \"Recently edited maps detected.\",\n    \"text\": \"Need to recover data?\"\n  },\n  \"error\": {\n    \"dontWorry\": \"But don't worry, your map won't lost\",\n    \"exportError\": \"export the map file contains error...\",\n    \"exportNoErrorFile\": \"Export the map file before the error occurred\",\n    \"metError\": \"Sorry! \\nProgram Error\",\n    \"orYouCould\": \"Or you can \",\n    \"recoverFromCache\": \"Restore the pre-error map from cache\",\n    \"sendAuthor\": \"In order to send it to the author to analyze the cause of the error.\"\n  },\n  \"huan-ying-shi-yong\": \"Welcome\",\n  \"welcome\": {\n    \"done\": \"Finish\",\n    \"goOn\": \"continue \",\n    \"restart\": \"restart \",\n    \"skip\": \"Skip for Now\",\n    \"welcome\": \"Welcome to\"\n  },\n  \"welecome\": {\n    \"minimetroweb\": \"Mini Metro Map Building Tool\"\n  },\n  \"chang-shi-dian-ji-xian-lu\": \"Try clicking the line\",\n  \"dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan\": \"Click on any empty area to exit the menu\",\n  \"dian-ji-zhan-dian\": \"click station\",\n  \"ke-yi-xiu-gai-biao-ti\": \"Title can be modified\",\n  \"ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi\": \"All settings for the route can be edited here\",\n  \"ke-yi-zai-zhe-li-bian-ji-zhan-dian-de-suo-you-she-zhi\": \"All settings for the station can be edited here\",\n  \"tour\": {\n    \"clickOpenMenu\": \"Click on the title to open the menu\",\n    \"clickTile\": \"click title\",\n    \"mouseScale\": \"Hold down the left mouse button and drag to move the map, scroll the mouse wheel to zoom the map\",\n    \"touchScale\": \"Drag the map with one finger and zoom the map with two fingers\",\n    \"tryScale\": \"Try zooming or moving the map\"\n  },\n  \"tu-zhong-de-cai-se-xian-tiao-ji-wei-xian-lu-ru-guo-wu-fa-xuan-zhong-ke-yi-chang-shi-fang-da-di-tu-zai-dian-xuan\": \"The colored lines in the picture are the lines. If you cannot select it, you can try to enlarge the map and click on it.\",\n  \"tui-chu-cai-dan\": \"Exit menu\",\n  \"xian-lu-ka-pian\": \"line card\",\n  \"yi-da-kai-zhan-dian-ka-pian\": \"to open the station card\",\n  \"zai-ci-dian-ji-biao-ti\": \"Click on the title again\",\n  \"zhan-dian-ka-pian\": \"station card\",\n  \"bu-hui-zhong-die\": \" won't overlap\",\n  \"che-hui\": \" withdraw\",\n  \"dan-zhi\": \"using finger\",\n  \"dao-chu\": \"Export\",\n  \"dao-chu-gao-fen-bian-shuai-tu-pian\": \"Export high-resolution images\",\n  \"dao-ru-dao-chu\": \"Import and export\",\n  \"fang-bian-cha-kan\": \"Easy to view\",\n  \"gao-liang\": \"Highlight\",\n  \"gao-xiao-bian-ji\": \"Efficient editing\",\n  \"gong-xian-xian-lu\": \"collinear lines\",\n  \"guan-lian\": \" linked\",\n  \"jian-shao-wu-cao-zuo\": \"Reduce misoperation\",\n  \"ka-pian-hua-zhan-shi-zhan-dian-yu-xian-lu\": \"Card display of stations and routes\",\n  \"le-jie-biao-qian-she-zhi\": \"Learn about label settings\",\n  \"le-jie-dao-ru-dao-chu\": \"Learn import and export\",\n  \"le-jie-ji-ben-cao-zuo\": \"Learn basic operations\",\n  \"le-jie-kuai-su-chuang-jian\": \"Learn about quick creat\",\n  \"le-jie-xian-lu-she-zhi\": \"Learn about line settings\",\n  \"le-jie-zhan-dian-ka-pian\": \"Learn about station cards\",\n  \"lian-xu-chuang-jian-zhan-dian-mo-shi\": \"Continuous station creation mode\",\n  \"lian-xu-tian-jia-zhan-dian\": \"Add stations continuously\",\n  \"ling-huo-zou-xian\": \"Flexible wiring\",\n  \"mo-shi\": \"\",\n  \"pngsvg-tu-pian\": \" PNG/SVG images\",\n  \"q-zi-zou-xian-yu-zou-xian\": \" Q shaped routing\",\n  \"shi-bie-dong-zuo-yi-tu\": \"\",\n  \"shuang-zhi\": \" or \",\n  \"suo-fang-di-tu\": \"Zoom\",\n  \"tuo-dong\": \" drag\",\n  \"wan-zheng-de-chu-kong-shi-jian-zhi-chi\": \"Complete touch event support\",\n  \"wu-xian-da-hua-bu\": \"infinite canvas\",\n  \"wu-xian-ge-zhan-dian\": \" Unlimited stations\",\n  \"wu-xian-tiao-xian-lu\": \" Unlimited lines\",\n  \"wu-xian-zi-chan\": \"unlimited assets\",\n  \"yi-dong-duan-zhi-chi\": \"Mobile support\",\n  \"yi-tiao-xian-lu-neng-duo-ci-chuan-guo-tong-yi-zhan\": \"A line can pass through the same station multiple times\",\n  \"yu\": \" and\",\n  \"zai-ping-ban-shang-ti-yan\": \"Experience it on tablet\",\n  \"zhan-dian-ming-cheng-zi-dong-xuan-ze-bai-fang-wei-zhi\": \"label automatically place\",\n  \"zhan-dian-xian-lu-hu-xiang\": \"stations and lines\",\n  \"zhan-shi-xuan-zhong-zhan-dian-yu-xian-lu\": \" selected\",\n  \"zhi-chi\": \"support\",\n  \"zhi-chi-cong-mo-ban-chuang-jian\": \"creat from templates\",\n  \"zhi-chi-she-zhi\": \"Support settings\",\n  \"zhi-xian\": \" sub line\",\n  \"zhong-zuo\": \" redo\",\n  \"zi-dong-bi-rang\": \"automatic avoidance\",\n  \"zi-dong-tian-jia-pian-yi-zhi\": \"Automatically add offset values\",\n  \"cong-huan-cun-zhong-hui-fu-shu-ju\": \"Recover data from cache\",\n  \"cong-mo-ban-xin-jian\": \"New from template\",\n  \"da-kai-cai-dan\": \"Open menu\",\n  \"dao-chu-hui-fu-shu-ju\": \"Export recovery data\",\n  \"dao-chu-tu-pian\": \"Export pictures\",\n  \"dao-ru-gang-cai-dao-chu-wen-jian\": \"Import the file you just exported\",\n  \"dian-ji-biao-ti\": \"click title\",\n  \"dian-ji-biao-ti-da-kai-cai-dan\": \"Click on the title to open the menu\",\n  \"dian-ji-dao-chu-tu-pian-dao-chu-ke-neng-hui-dao-zhi-ka-dun-ji-miao-shu-yu-zheng-chang-xian-xiang\": \"Click to export the image. \\nExporting may cause lag for a few seconds, which is normal.\",\n  \"que-ren-xin-jian-qian-qing-que-bao-yi-jing-bao-cun-le-dang-qian-de-di-tu\": \"Please make sure you have saved the current map before confirming the new creation.\",\n  \"ran-hou-dian-ji-xia-yi-bu\": \"Then click next\",\n  \"ru-guo-mei-bao-cun-de-shi-hou-bu-xiao-xin-shua-xin-ke-yi-dian-ji-zhe-li-hui-fu-shu-ju\": \"If you accidentally refresh without saving, you can click here to restore the data.\",\n  \"ru-guo-mou-yi-bu-cao-zuo-hou-dao-zhi-bao-cuo-huo-beng-kui-dian-ji-zhe-li-dao-chu-zui-hou-yi-ci-zheng-que-de-shu-ju-ru-guo-yu-dao-zhe-zhong-qing-kuang-qing-fan-kui-gei-zuo-zhe\": \"If a certain step results in an error or crash, click here to export the last correct data. \\n(If you encounter this situation, please give feedback to the author)\",\n  \"xia-ci-dian-ji-dao-ru-wen-jian-ke-yi-ji-xu-bian-ji\": \"Click to import the file next time to continue editing.\",\n  \"xuan-ze-yi-ge-ni-xi-huan-de-cheng-shi\": \"Choose a city you like\",\n  \"xuan-ze-zuo-wei-wen-jian-dao-chu\": \"Select Export as file\",\n  \"xuan-ze-zuo-wei-wen-jian-dao-chu-0\": \"Select Export as file\",\n  \"yi-ci-wei-mo-ban-xin-jian\": \"Use this as a template to create a new\",\n  \"zai-yi-you-de-di-tu-shang-xiu-gai\": \"Modify on existing map\",\n  \"zuo-wei-wen-jian-dao-chu\": \"Export as file\",\n  \"bian-ji-an-niu\": \"edit button\",\n  \"ci-chu-xiu-gai-xian-lu-ming-cheng-yu-biao-shi\": \"Modify the line name and identification here\",\n  \"dian-ji-ci-chu-kong-zhi-xian-lu-zai-liang-zhan-zhi-jian-de-zou-xiang\": \"Click here to control the direction of the line between two stations\",\n  \"dian-ji-ci-chu-shan-chu-xian-lu-huo-zhe-she-zhi-zhi-xian\": \"Click here to delete a line or set up a sub line\",\n  \"dian-ji-ci-chu-suo-yi-tu-jing-de-zhan-dian-ka-pian\": \"Click here for site cards for all routes\",\n  \"dian-ji-ci-chu-wan-cheng-she-zhi\": \"Click here to complete setup\",\n  \"dian-ji-ci-chu-xiu-gai-xian-lu-biao-shi-se\": \"Click here to modify the line identification color\",\n  \"dian-ji-ren-yi-xian-lu\": \"Click on any line\",\n  \"fang-da-an-niu\": \"magnify button\",\n  \"hui-dao-zhan-dian-ye\": \"Return to site page\",\n  \"jin-ru-geng-duo-she-zhi-mian-ban\": \"Enter more settings panel\",\n  \"ke-yi-tuo-kuan-xian-lu-ka-pian\": \"Line cards can be expanded\",\n  \"ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi-0\": \"All settings for the route can be edited here\",\n  \"pai-xu-ke-yi-kong-zhi-xian-lu-jian-de-zhe-dang-guan-xi\": \"Sorting can control the occlusion relationship between lines\",\n  \"she-zhi-zhi-xian-hou-xian-lu-hui-yi-xu-xian-xian-shi-qie-lian-jie-chu-bu-zai-xian-shi-ba-shou\": \"After setting up the sub line, the line will be displayed as a dotted line, and the handle will no longer be displayed at the connection.\",\n  \"suo-xiao-an-niu\": \"zoom out button\",\n  \"tu-zhong-cai-se-qu-xian-biao-shi-di-tie-xian-lu\": \"The colored curves in the figure represent subway lines\",\n  \"xian-lu-ka-pian-0\": \"line card\",\n  \"xian-shi-tu-jing-zhan-dian-ka-pian\": \"Show route site cards\",\n  \"zai-suo-xiao-zhuang-tai-ke-yi-dian-ji-geng-duo-she-zhi\": \"In the zoomed-out state, you can click on more settings\",\n  \"zhan-dian-qu-jian-lian-xian-zhi-you-liang-zhong-fang-shi-xie-xian-yu-zhi-xian\": \"There are only two ways to connect sites, diagonal lines and straight lines.\",\n  \"zuo-xia-jiao-de-yan-se-xuan-ze-qi-ke-yi-qu-se\": \"The color picker in the lower left corner can select colors\",\n  \"da-kai-cai-dan-0\": \"Open menu\",\n  \"da-kai-zhan-dian-xin-xi-ka-pian\": \"Open the site information card\",\n  \"dian-ji-biao-ti-da-kai-cai-dan-0\": \"Click on the title to open the menu\",\n  \"dian-ji-cao-zuo-xuan-xiang-ka\": \"Click on the Actions tab\",\n  \"dian-ji-gang-cai-chuang-jian-de-zhan-dian\": \"Click on the site you just created\",\n  \"dian-ji-ren-yi-kong-bai-chu-tian-jia-zhan-dian\": \"Click any blank space to add a site\",\n  \"dian-ji-tian-jia-zhan-dian\": \"Click to add site\",\n  \"dian-ji-wan-cheng\": \"Click Finish\",\n  \"dian-ji-yi-ci-wei-qi-dian-xin-jian-xian-lu\": \"Click to create a new route starting from this point\",\n  \"dian-ji-zhan-dian-0\": \"click site\",\n  \"jin-ru-tian-jia-xian-lu-mo-shi\": \"Enter add line mode\",\n  \"jin-ru-tian-jia-zhan-dian-mo-shi\": \"Enter add site mode\",\n  \"lian-jie-zhan-dian\": \"connect site\",\n  \"tian-jia-hao-zhi-hou-dian-ji-xia-yi-bu-jian-yi-nin-zai-ping-mu-zuo-shang-jiao-de-kong-bai-qu-yu-tian-jia-san-ge-zhan-dian\": \"After adding, click Next (it is recommended that you add three sites in the blank area in the upper left corner of the screen)\",\n  \"tui-chu-bian-ji-mo-shi\": \"Exit edit mode\",\n  \"wo-men-lai-tian-jia-xian-lu\": \"Let's add the line\",\n  \"xian-lu-jiu-chuang-jian-hao-le\": \"The line is created\",\n  \"bian-ji-zhan-dian-wei-zhi\": \"Edit site location\",\n  \"dian-ji-ci-chu-shan-chu-zhan-dian-huo-xin-jian-xian-lu\": \"Click here to delete a site or create a new route\",\n  \"dian-ji-ci-chu-she-zhi-zhan-dian-ming-cheng-wei-zhi\": \"Click here to set site name location\",\n  \"dian-ji-ci-chu-xiu-gai-zhan-dian-xing-zhuang\": \"Click here to modify site shape\",\n  \"dian-ji-hui-se-de-fang-kuai-xuan-ze-fang-wei\": \"Click on the gray square to select the direction\",\n  \"dian-ji-zhong-jian-de-wen-zi-hui-fu-zi-dong-wei-zhi\": \"Click on the text in the middle to restore the automatic position\",\n  \"dian-ji-zuo-biao-zhi-hou-shi-yong-shu-biao-gun-lun-ke-yi-jing-que-tiao-jie\": \"Click the coordinates and use the mouse wheel to adjust accurately\",\n  \"shan-chu-huo-xin-jian\": \"Delete or create new\",\n  \"xiu-gai-xing-zhuang\": \"Modify shape\",\n  \"yi-da-kai-zhan-dian-ka-pian-0\": \"to open the site card\",\n  \"zhan-dian-ming-wei-zhi\": \"Site name location\",\n  \"chang-shi-gai-bian-zhan-dian-ming-dao-you-xia-jiao\": \"Try changing the site name to the lower right corner\",\n  \"dian-ji-biao-ti-da-kai-cai-dan-1\": \"Click on the title to open the menu\",\n  \"dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan-0\": \"Click on any empty area to exit the menu\",\n  \"dian-ji-you-xia-jiao-de-hui-se-fang-kuai\": \"Click on the gray square in the lower right corner\",\n  \"dian-ji-zhong-jian-de-wen-zi-hui-fu-dao-zi-dong-xuan-ze-wei-zhi\": \"Click on the text in the middle to return to the automatically selected position\",\n  \"guan-bi-zi-dong-yin-cang\": \"Turn off auto-hide\",\n  \"hui-fu-dao-zi-dong-xuan-ze-wei-zhi\": \"Revert to automatically selected location\",\n  \"ke-yi-kan-dao-zhan-dian-ming-yi-jing-wei-yu-zhan-dian-you-xia-jiao-le\": \"You can see that the site name is already in the lower right corner of the site\",\n  \"ke-yi-yong-zhe-zhong-fang-fa-xiu-gai-zhan-dian-ming-wei-zhi\": \"You can use this method to modify the location of the site name\",\n  \"tui-chu-cai-dan-0\": \"Exit menu\",\n  \"yi-da-kai-zhan-dian-ka-pian-1\": \"to open the site card\",\n  \"zai-dian-ji-biao-qian-an-niu\": \"Click the label button again\",\n  \"zai-zhe-li-xiang-xia-gun-dong-yi-xia\": \"Scroll down a bit here\",\n  \"zhan-dian-ming-hui-zai-di-tu-suo-fang-dao-xiao-chi-du-shi-zi-dong-yin-cang-guan-bi-zi-dong-yin-cang-yi-que-bao-ke-yi-yi-zhi-xian-shi-zhan-dian-ming-cheng\": \"Site names are automatically hidden when the map is zoomed to a smaller scale. \\nTurn off auto-hide to ensure the site name is always visible\",\n  \"di-current-bu-gong-total-bu\": \"Step {0} of {1} steps\",\n  \"shang-yi-bu\": \"Previous Step\",\n  \"wan-cheng\": \"Finish\",\n  \"xia-yi-bu\": \"Next Step\",\n  \"delete\": {\n    \"cancel\": \"Cancel\",\n    \"delete\": \"delete\",\n    \"remove\": \"Remove\",\n    \"subtile\": \"No longer as the {{index}} station of {{lineName}}\"\n  },\n  \"que-shi-yao-deletetext-ma\": \"Do you really want to {{deleteText}}?\",\n  \"teyvat\": \"Teyvat\",\n  \"newStation\": \"New Station\",\n  \"lineNo\": \"Line {{lineId}}\",\n  \"Common-teyvat-192be7b183f6eee79-1\": \"Eagle Beach\",\n  \"Common-teyvat-192be7b183f6eee79-10\": \"Fengshen Statue Station\",\n  \"Common-teyvat-192be7b183f6eee79-11\": \"Mondstadt\",\n  \"Common-teyvat-192be7b183f6eee79-12\": \"Qingquan Town\",\n  \"Common-teyvat-192be7b183f6eee79-13\": \"Dawn Winery\",\n  \"Common-teyvat-192be7b183f6eee79-14\": \"Benlangling\",\n  \"Common-teyvat-192be7b183f6eee79-15\": \"Benlangling North\",\n  \"Common-teyvat-192be7b183f6eee79-16\": \"Fenglong Scenic Area\",\n  \"Common-teyvat-192be7b183f6eee79-17\": \"Mingguan Gorge\",\n  \"Common-teyvat-192be7b183f6eee79-18\": \"Fenglong International Airport\",\n  \"Common-teyvat-192be7b183f6eee79-19\": \"Snow Mountain Foot Station\",\n  \"Common-teyvat-192be7b183f6eee79-2\": \"dadaupa valley\",\n  \"Common-teyvat-192be7b183f6eee79-20\": \"formless ice\",\n  \"Common-teyvat-192be7b183f6eee79-21\": \"Xueshanshan Station\",\n  \"Common-teyvat-192be7b183f6eee79-22\": \"Seven-day God Statue Station\",\n  \"Common-teyvat-192be7b183f6eee79-23\": \"snow mountain lake\",\n  \"Common-teyvat-192be7b183f6eee79-24\": \"salt of the earth\",\n  \"Common-teyvat-192be7b183f6eee79-25\": \"Wangshu Inn\",\n  \"Common-teyvat-192be7b183f6eee79-26\": \"Shimen\",\n  \"Common-teyvat-192be7b183f6eee79-27\": \"Qingce Village\",\n  \"Common-teyvat-192be7b183f6eee79-28\": \"Wangshunan\",\n  \"Common-teyvat-192be7b183f6eee79-29\": \"Return to the original\",\n  \"Common-teyvat-192be7b183f6eee79-3\": \"Formless Thunder\",\n  \"Common-teyvat-192be7b183f6eee79-30\": \"Luhuachi South\",\n  \"Common-teyvat-192be7b183f6eee79-31\": \"Liyue Port\",\n  \"Common-teyvat-192be7b183f6eee79-32\": \"gold house\",\n  \"Common-teyvat-192be7b183f6eee79-33\": \"Qingxupu\",\n  \"Common-teyvat-192be7b183f6eee79-34\": \"Lingju International Airport\",\n  \"Common-teyvat-192be7b183f6eee79-35\": \"Tianheng Mountain\",\n  \"Common-teyvat-192be7b183f6eee79-36\": \"Escape Yuling\",\n  \"Common-teyvat-192be7b183f6eee79-37\": \"Luhuachi\",\n  \"Common-teyvat-192be7b183f6eee79-38\": \"cuijuepo\",\n  \"Common-teyvat-192be7b183f6eee79-39\": \"Taishan Mansion\",\n  \"Common-teyvat-192be7b183f6eee79-4\": \"Oath Point Airport\",\n  \"Common-teyvat-192be7b183f6eee79-40\": \"Airport East\",\n  \"Common-teyvat-192be7b183f6eee79-41\": \"Qingyun International Airport\",\n  \"Common-teyvat-192be7b183f6eee79-42\": \"Mount Ozura\",\n  \"Common-teyvat-192be7b183f6eee79-43\": \"Hulao Mountain\",\n  \"Common-teyvat-192be7b183f6eee79-44\": \"Fulong tree\",\n  \"Common-teyvat-192be7b183f6eee79-45\": \"Nantianmen\",\n  \"Common-teyvat-192be7b183f6eee79-46\": \"Tianqiu Valley\",\n  \"Common-teyvat-192be7b183f6eee79-47\": \"Fuao Valley\",\n  \"Common-teyvat-192be7b183f6eee79-48\": \"Xiangzuipo\",\n  \"Common-teyvat-192be7b183f6eee79-49\": \"No thick forest\",\n  \"Common-teyvat-192be7b183f6eee79-5\": \"Fengqidi Station\",\n  \"Common-teyvat-192be7b183f6eee79-50\": \"Casazzale\",\n  \"Common-teyvat-192be7b183f6eee79-51\": \"Fungus Cave\",\n  \"Common-teyvat-192be7b183f6eee79-52\": \"Xumi City\",\n  \"Common-teyvat-192be7b183f6eee79-53\": \"Huachengguo\",\n  \"Common-teyvat-192be7b183f6eee79-54\": \"dansha cliff\",\n  \"Common-teyvat-192be7b183f6eee79-55\": \"Subdue all the demons in Shandong\",\n  \"Common-teyvat-192be7b183f6eee79-56\": \"Subdue all the demonic mountains\",\n  \"Common-teyvat-192be7b183f6eee79-57\": \"Porto Ormos North\",\n  \"Common-teyvat-192be7b183f6eee79-58\": \"puerto olmos\",\n  \"Common-teyvat-192be7b183f6eee79-59\": \"vimo village\",\n  \"Common-teyvat-192be7b183f6eee79-6\": \"Star falls in Hunan\",\n  \"Common-teyvat-192be7b183f6eee79-60\": \"jhana garden\",\n  \"Common-teyvat-192be7b183f6eee79-61\": \"Praise to the secluded place\",\n  \"Common-teyvat-192be7b183f6eee79-62\": \"Huana Lanna\",\n  \"Common-teyvat-192be7b183f6eee79-63\": \"Five Oasis\",\n  \"Common-teyvat-192be7b183f6eee79-64\": \"Kawanyi\",\n  \"Common-teyvat-192be7b183f6eee79-65\": \"Water and Sky Jungle\",\n  \"Common-teyvat-192be7b183f6eee79-66\": \"The seat of Tuha\",\n  \"Common-teyvat-192be7b183f6eee79-67\": \"A Ru Village\",\n  \"Common-teyvat-192be7b183f6eee79-68\": \"Transfiguration Hall\",\n  \"Common-teyvat-192be7b183f6eee79-69\": \"Vibrant House\",\n  \"Common-teyvat-192be7b183f6eee79-7\": \"Xingluo Lake\",\n  \"Common-teyvat-192be7b183f6eee79-70\": \"Oasis of plenty\",\n  \"Common-teyvat-192be7b183f6eee79-71\": \"Tomb of the Red King\",\n  \"Common-teyvat-192be7b183f6eee79-72\": \"Line 1\",\n  \"Common-teyvat-192be7b183f6eee79-73\": \"Line 2\",\n  \"Common-teyvat-192be7b183f6eee79-74\": \"Line 3\",\n  \"Common-teyvat-192be7b183f6eee79-75\": \"Line 4\",\n  \"Common-teyvat-192be7b183f6eee79-76\": \"Line 5\",\n  \"Common-teyvat-192be7b183f6eee79-77\": \"Line 6\",\n  \"Common-teyvat-192be7b183f6eee79-78\": \"Line 7\",\n  \"Common-teyvat-192be7b183f6eee79-79\": \"Line 8\",\n  \"Common-teyvat-192be7b183f6eee79-8\": \"Phaseless Wind Station\",\n  \"Common-teyvat-192be7b183f6eee79-80\": \"Xumi Line 2\",\n  \"Common-teyvat-192be7b183f6eee79-81\": \"Xumi Line 1\",\n  \"Common-teyvat-192be7b183f6eee79-82\": \"Xumi Line 3\",\n  \"Common-teyvat-192be7b183f6eee79-83\": \"Xumi Line 4\",\n  \"Common-teyvat-192be7b183f6eee79-9\": \"Wangfeng Development Zone\",\n  \"qian-feng-shen-dian-zhan\": \"Thousand Winds Temple Station\",\n  \"wang-feng-jiao-zhan\": \"Lookout Point Station\",\n  \"zhai-xing-ya-zhan\": \"Zhaixingya Station\"\n}\n"
  },
  {
    "path": "src/i18n/locales/zh.json",
    "content": "{\n  \"language\": \"中文\",\n  \"menu\": {\n    \"alreadyAddStations\": \"已添加{{count}}站\",\n    \"clickBlankToAddStation\": \"点击空白处新增站点\",\n    \"redo\": \"重做\",\n    \"done\": \"完成\",\n    \"alreadyModified\": \"已修改{{count}}次\",\n    \"dragToChangePoistion\": \"拖动站点更改位置\",\n    \"withdraw\": \"撤销\",\n    \"chooseALineFirst\": \"先选择一条线路，再点击线路卡片上的\",\n    \"backgroudSetting\": \"背景设定\",\n    \"white\": \"纯白\",\n    \"lightYellow\": \"浅黄\",\n    \"transparent\": \"透明\",\n    \"changeBackgroudImage\": \"修改背景图\",\n    \"importBackgroudImage\": \"导入背景图\",\n    \"importImage\": \"导入图片\",\n    \"deleteImage\": \"删除图片\",\n    \"back\": \"返回\",\n    \"clickAddStationToLine\": \"点击站点将它插入到{{lineName}}的第{{insertIndex}}站\",\n    \"chooseAMap\": \"选择一张地图\",\n    \"useTemplate\": \"以{{name}}为模板新建地图\",\n    \"cancel\": \"取消\",\n    \"station\": \"站点\",\n    \"addStation\": \"添加站点\",\n    \"changeStationPosition\": \"调整站点位置\",\n    \"hidden\": \"隐藏\",\n    \"show\": \"显示\",\n    \"stationName\": \"站点名称\",\n    \"turnOn\": \"启用\",\n    \"AutoHidden\": \"自动隐藏\",\n    \"line\": \"线路\",\n    \"turnOff\": \"关闭\",\n    \"insertStation\": \"插入站点...\",\n    \"mediateMap\": \"居中路线图...\",\n    \"addBackgroundImage\": \"设定背景...\",\n    \"data\": \"数据\",\n    \"addNewMap\": \"新建空白地图...\",\n    \"addFromTemplate\": \"从已有地图新建...\",\n    \"importFile\": \"导入文件...\",\n    \"exportAsImage\": \"作为图片导出...\",\n    \"exportAsSVG\": \"作为矢量图片导出...\",\n    \"exportAsFile\": \"作为文件导出...\",\n    \"recoverData\": \"恢复数据...\",\n    \"exportRecoveryData\": \"导出恢复数据...\",\n    \"about\": \"关于\",\n    \"projectAddress\": \"项目地址...\",\n    \"guide\": \"使用教程...\",\n    \"videoGuild\": \"视频教程...\",\n    \"RMP\": \"线路图工具包\",\n    \"version\": \"版本 : \",\n    \"author\": \"作者 : 江户川瑞安\",\n    \"symbol\": \"标识\",\n    \"newMap\": \"新地图\",\n    \"switchLanguage\": \"Switch to English\"\n  },\n  \"shang-hai\": \"上海\",\n  \"bei-jing\": \"北京\",\n  \"guang-zhou\": \"广州\",\n  \"shen-zhen\": \"深圳\",\n  \"xiang-gang\": \"香港\",\n  \"chang-sha\": \"长沙\",\n  \"tian-jin\": \"天津\",\n  \"station\": {\n    \"up\": \"顶端\",\n    \"upRight\": \"右上角\",\n    \"right\": \"右侧\",\n    \"rightDown\": \"右下角\",\n    \"down\": \"底部\",\n    \"downLeft\": \"左下角\",\n    \"left\": \"左侧\",\n    \"leftUp\": \"左上角\",\n    \"auto\": \"自动\",\n    \"x\": \"横坐标\",\n    \"y\": \"纵坐标\",\n    \"startHere\": \"以此为起点新建线路...\",\n    \"remove\": \"从{{lineName}}的第{{stationIndex}}站移除\",\n    \"delete\": \"删除站点...\",\n    \"lines\": \"条线路\",\n    \"poisition\": \"位置\",\n    \"shape\": \"形状\",\n    \"operation\": \"操作\",\n    \"operateDes\": \"删除\",\n    \"stationName\": \"标签\"\n  },\n  \"shape\": {\n    \"cicle\": \"圆形\",\n    \"square\": \"正方形\",\n    \"triangle\": \"三角形\",\n    \"start\": \"五角星\",\n    \"pentagon\": \"五边形\",\n    \"hexagon\": \"六边形\",\n    \"cross\": \"十字形\",\n    \"rhombus\": \"菱形\",\n    \"diamond\": \"钻石\",\n    \"leaf\": \"叶子\",\n    \"ginkgo\": \"银杏\"\n  },\n  \"line\": {\n    \"name\": \"名称\",\n    \"order\": \"排序\",\n    \"notSubLineAnymore\": \"不再作为支线\",\n    \"asSubline\": \"设为支线\",\n    \"deleteLine\": \"删除线路...\",\n    \"stations\": \"个站点\",\n    \"notInUse\": \"尚未开通\",\n    \"fromTo\": \"从{{from}}开往{{to}}\",\n    \"insertHere\": \"插入到这\",\n    \"insertStation\": \"插入站点\",\n    \"bendFirst\": \"斜向优先\",\n    \"straight\": \"直线优先\",\n    \"color\": \"颜色\",\n    \"operation\": \"操作\",\n    \"delete\": \"删除\",\n    \"done\": \"完成\"\n  },\n  \"opacity\": \"透明度\",\n  \"recover\": {\n    \"text\": \"需要恢复数据吗？\",\n    \"subTitle\": \"缓存中有不久前编辑过的地图\"\n  },\n  \"error\": {\n    \"metError\": \"抱歉！程序出现错误\",\n    \"dontWorry\": \"不过不用担心，您的地图没有丢失\",\n    \"recoverFromCache\": \"从缓存中恢复错误发生前的地图\",\n    \"exportNoErrorFile\": \"导出错误发生前的地图文件\",\n    \"orYouCould\": \"或者您可以\",\n    \"exportError\": \"导出当前包含错误的地图文件...\",\n    \"sendAuthor\": \"以便发送给作者分析错误原因。\"\n  },\n  \"huan-ying-shi-yong\": \"欢迎使用\",\n  \"welcome\": {\n    \"welcome\": \"欢迎使用\",\n    \"skip\": \"暂时跳过\",\n    \"goOn\": \"继续\",\n    \"restart\": \"重新开始\",\n    \"done\": \"完成\"\n  },\n  \"welecome\": {\n    \"minimetroweb\": \"迷你地铁地图构建工具\"\n  },\n  \"tour\": {\n    \"tryScale\": \"尝试缩放或者移动地图\",\n    \"touchScale\": \"单指拖动地图，双指缩放地图\",\n    \"mouseScale\": \"按住鼠标左键拖动移动地图，滚动鼠标滚轮缩放地图\",\n    \"clickTile\": \"点击标题\",\n    \"clickOpenMenu\": \"点击标题打开菜单\"\n  },\n  \"zai-ci-dian-ji-biao-ti\": \"再次点击标题\",\n  \"ke-yi-xiu-gai-biao-ti\": \"可以修改标题\",\n  \"dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan\": \"点击任意空白区域退出菜单\",\n  \"tui-chu-cai-dan\": \"退出菜单\",\n  \"dian-ji-zhan-dian\": \"点击站点\",\n  \"yi-da-kai-zhan-dian-ka-pian\": \"以打开站点卡片\",\n  \"zhan-dian-ka-pian\": \"站点卡片\",\n  \"ke-yi-zai-zhe-li-bian-ji-zhan-dian-de-suo-you-she-zhi\": \"可以在这里编辑站点的所有设置\",\n  \"chang-shi-dian-ji-xian-lu\": \"尝试点击线路\",\n  \"tu-zhong-de-cai-se-xian-tiao-ji-wei-xian-lu-ru-guo-wu-fa-xuan-zhong-ke-yi-chang-shi-fang-da-di-tu-zai-dian-xuan\": \"图中的彩色线条即为线路,如果无法选中可以尝试放大地图再点选\",\n  \"xian-lu-ka-pian\": \"线路卡片\",\n  \"ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi\": \"可以在这里编辑线路的所有设置\",\n  \"wu-xian-zi-chan\": \"无限资产\",\n  \"wu-xian-da-hua-bu\": \"无限大画布\",\n  \"zhi-chi\": \"支持\",\n  \"wu-xian-tiao-xian-lu\": \"无限条线路\",\n  \"wu-xian-ge-zhan-dian\": \"无限个站点\",\n  \"le-jie-ji-ben-cao-zuo\": \"了解基本操作\",\n  \"ling-huo-zou-xian\": \"灵活走线\",\n  \"yi-tiao-xian-lu-neng-duo-ci-chuan-guo-tong-yi-zhan\": \"一条线路能多次穿过同一站\",\n  \"q-zi-zou-xian-yu-zou-xian\": \"Q字走线与α走线\",\n  \"zhi-chi-she-zhi\": \"支持设置\",\n  \"zhi-xian\": \"支线\",\n  \"le-jie-xian-lu-she-zhi\": \"了解线路设置\",\n  \"fang-bian-cha-kan\": \"方便查看\",\n  \"ka-pian-hua-zhan-shi-zhan-dian-yu-xian-lu\": \"卡片化展示站点与线路\",\n  \"zhan-dian-xian-lu-hu-xiang\": \"站点线路互相\",\n  \"guan-lian\": \"关联\",\n  \"gao-liang\": \"高亮\",\n  \"zhan-shi-xuan-zhong-zhan-dian-yu-xian-lu\": \"展示选中站点与线路\",\n  \"le-jie-zhan-dian-ka-pian\": \"了解站点卡片\",\n  \"gao-xiao-bian-ji\": \"高效编辑\",\n  \"lian-xu-chuang-jian-zhan-dian-mo-shi\": \"连续创建站点模式\",\n  \"lian-xu-tian-jia-zhan-dian\": \"连续添加站点\",\n  \"mo-shi\": \"模式\",\n  \"che-hui\": \"撤回\",\n  \"yu\": \"与\",\n  \"zhong-zuo\": \"重做\",\n  \"le-jie-kuai-su-chuang-jian\": \"了解快速创建\",\n  \"yi-dong-duan-zhi-chi\": \"移动端支持\",\n  \"wan-zheng-de-chu-kong-shi-jian-zhi-chi\": \"完整的触控事件支持\",\n  \"dan-zhi\": \"单指\",\n  \"tuo-dong\": \"拖动\",\n  \"shuang-zhi\": \"双指\",\n  \"suo-fang-di-tu\": \"缩放地图\",\n  \"shi-bie-dong-zuo-yi-tu\": \"识别动作意图\",\n  \"jian-shao-wu-cao-zuo\": \"减少误操作\",\n  \"zai-ping-ban-shang-ti-yan\": \"在平板上体验\",\n  \"zi-dong-bi-rang\": \"自动避让\",\n  \"zi-dong-tian-jia-pian-yi-zhi\": \"自动添加偏移值\",\n  \"gong-xian-xian-lu\": \"共线线路\",\n  \"bu-hui-zhong-die\": \"不会重叠\",\n  \"zhan-dian-ming-cheng-zi-dong-xuan-ze-bai-fang-wei-zhi\": \"站点名称自动选择摆放位置\",\n  \"le-jie-biao-qian-she-zhi\": \"了解标签设置\",\n  \"dao-ru-dao-chu\": \"导入导出\",\n  \"dao-chu-gao-fen-bian-shuai-tu-pian\": \"导出高分辨率图片\",\n  \"dao-chu\": \"导出\",\n  \"pngsvg-tu-pian\": \"PNG/SVG图片\",\n  \"zhi-chi-cong-mo-ban-chuang-jian\": \"支持从模版创建\",\n  \"le-jie-dao-ru-dao-chu\": \"了解导入导出\",\n  \"dian-ji-biao-ti\": \"点击标题\",\n  \"dian-ji-biao-ti-da-kai-cai-dan\": \"点击标题打开菜单\",\n  \"cong-mo-ban-xin-jian\": \"从模板新建\",\n  \"zai-yi-you-de-di-tu-shang-xiu-gai\": \"在已有的地图上修改\",\n  \"xuan-ze-yi-ge-ni-xi-huan-de-cheng-shi\": \"选择一个你喜欢的城市\",\n  \"ran-hou-dian-ji-xia-yi-bu\": \"然后点击下一步\",\n  \"yi-ci-wei-mo-ban-xin-jian\": \"以此为模板新建\",\n  \"que-ren-xin-jian-qian-qing-que-bao-yi-jing-bao-cun-le-dang-qian-de-di-tu\": \"确认新建前请确保已经保存了当前的地图\",\n  \"da-kai-cai-dan\": \"打开菜单\",\n  \"xuan-ze-zuo-wei-wen-jian-dao-chu\": \"选择作为文件导出\",\n  \"zuo-wei-wen-jian-dao-chu\": \"作为文件导出\",\n  \"xuan-ze-zuo-wei-wen-jian-dao-chu-0\": \"选择作为文件导出\",\n  \"dao-ru-gang-cai-dao-chu-wen-jian\": \"导入刚才导出文件\",\n  \"xia-ci-dian-ji-dao-ru-wen-jian-ke-yi-ji-xu-bian-ji\": \"下次点击导入文件可以继续编辑\",\n  \"dao-chu-tu-pian\": \"导出图片\",\n  \"dian-ji-dao-chu-tu-pian-dao-chu-ke-neng-hui-dao-zhi-ka-dun-ji-miao-shu-yu-zheng-chang-xian-xiang\": \"点击导出图片。导出可能会导致卡顿几秒属于正常现象\",\n  \"cong-huan-cun-zhong-hui-fu-shu-ju\": \"从缓存中恢复数据\",\n  \"ru-guo-mei-bao-cun-de-shi-hou-bu-xiao-xin-shua-xin-ke-yi-dian-ji-zhe-li-hui-fu-shu-ju\": \"如果没保存的时候不小心刷新，可以点击这里恢复数据\",\n  \"dao-chu-hui-fu-shu-ju\": \"导出恢复数据\",\n  \"ru-guo-mou-yi-bu-cao-zuo-hou-dao-zhi-bao-cuo-huo-beng-kui-dian-ji-zhe-li-dao-chu-zui-hou-yi-ci-zheng-que-de-shu-ju-ru-guo-yu-dao-zhe-zhong-qing-kuang-qing-fan-kui-gei-zuo-zhe\": \"如果某一步操作后导致报错或崩溃，点击这里导出最后一次正确的数据。（如果遇到这种情况，请反馈给作者）\",\n  \"dian-ji-ren-yi-xian-lu\": \"点击任意线路\",\n  \"tu-zhong-cai-se-qu-xian-biao-shi-di-tie-xian-lu\": \"图中彩色曲线表示地铁线路\",\n  \"xian-lu-ka-pian-0\": \"线路卡片\",\n  \"ke-yi-zai-zhe-li-bian-ji-xian-lu-de-suo-you-she-zhi-0\": \"可以在这里编辑线路的所有设置\",\n  \"dian-ji-ci-chu-kong-zhi-xian-lu-zai-liang-zhan-zhi-jian-de-zou-xiang\": \"点击此处控制线路在两站之间的走向\",\n  \"zhan-dian-qu-jian-lian-xian-zhi-you-liang-zhong-fang-shi-xie-xian-yu-zhi-xian\": \"站点区间连线只有两种方式，斜线与直线\",\n  \"fang-da-an-niu\": \"放大按钮\",\n  \"ke-yi-tuo-kuan-xian-lu-ka-pian\": \"可以拓宽线路卡片\",\n  \"suo-xiao-an-niu\": \"缩小按钮\",\n  \"zai-suo-xiao-zhuang-tai-ke-yi-dian-ji-geng-duo-she-zhi\": \"在缩小状态可以点击更多设置\",\n  \"bian-ji-an-niu\": \"编辑按钮\",\n  \"jin-ru-geng-duo-she-zhi-mian-ban\": \"进入更多设置面板\",\n  \"ci-chu-xiu-gai-xian-lu-ming-cheng-yu-biao-shi\": \"此处修改线路名称与标识\",\n  \"pai-xu-ke-yi-kong-zhi-xian-lu-jian-de-zhe-dang-guan-xi\": \"排序可以控制线路间的遮挡关系\",\n  \"dian-ji-ci-chu-xiu-gai-xian-lu-biao-shi-se\": \"点击此处修改线路标识色\",\n  \"zuo-xia-jiao-de-yan-se-xuan-ze-qi-ke-yi-qu-se\": \"左下角的颜色选择器可以取色\",\n  \"dian-ji-ci-chu-shan-chu-xian-lu-huo-zhe-she-zhi-zhi-xian\": \"点击此处删除线路或者设置支线\",\n  \"she-zhi-zhi-xian-hou-xian-lu-hui-yi-xu-xian-xian-shi-qie-lian-jie-chu-bu-zai-xian-shi-ba-shou\": \"设置支线后线路会以虚线显示，且连接处不再显示把手\",\n  \"dian-ji-ci-chu-wan-cheng-she-zhi\": \"点击此处完成设置\",\n  \"hui-dao-zhan-dian-ye\": \"回到站点页\",\n  \"xian-shi-tu-jing-zhan-dian-ka-pian\": \"显示途径站点卡片\",\n  \"dian-ji-ci-chu-suo-yi-tu-jing-de-zhan-dian-ka-pian\": \"点击此处所以途径的站点卡片\",\n  \"da-kai-cai-dan-0\": \"打开菜单\",\n  \"dian-ji-biao-ti-da-kai-cai-dan-0\": \"点击标题打开菜单\",\n  \"dian-ji-tian-jia-zhan-dian\": \"点击添加站点\",\n  \"jin-ru-tian-jia-zhan-dian-mo-shi\": \"进入添加站点模式\",\n  \"dian-ji-ren-yi-kong-bai-chu-tian-jia-zhan-dian\": \"点击任意空白处添加站点\",\n  \"tian-jia-hao-zhi-hou-dian-ji-xia-yi-bu-jian-yi-nin-zai-ping-mu-zuo-shang-jiao-de-kong-bai-qu-yu-tian-jia-san-ge-zhan-dian\": \"添加好之后点击下一步（建议您在屏幕左上角的空白区域添加三个站点）\",\n  \"dian-ji-wan-cheng\": \"点击完成\",\n  \"tui-chu-bian-ji-mo-shi\": \"退出编辑模式\",\n  \"dian-ji-gang-cai-chuang-jian-de-zhan-dian\": \"点击刚才创建的站点\",\n  \"da-kai-zhan-dian-xin-xi-ka-pian\": \"打开站点信息卡片\",\n  \"dian-ji-cao-zuo-xuan-xiang-ka\": \"点击操作选项卡\",\n  \"wo-men-lai-tian-jia-xian-lu\": \"我们来添加线路\",\n  \"dian-ji-yi-ci-wei-qi-dian-xin-jian-xian-lu\": \"点击以此为起点新建线路\",\n  \"jin-ru-tian-jia-xian-lu-mo-shi\": \"进入添加线路模式\",\n  \"dian-ji-zhan-dian-0\": \"点击站点\",\n  \"lian-jie-zhan-dian\": \"连接站点\",\n  \"xian-lu-jiu-chuang-jian-hao-le\": \"线路就创建好了\",\n  \"yi-da-kai-zhan-dian-ka-pian-0\": \"以打开站点卡片\",\n  \"bian-ji-zhan-dian-wei-zhi\": \"编辑站点位置\",\n  \"dian-ji-zuo-biao-zhi-hou-shi-yong-shu-biao-gun-lun-ke-yi-jing-que-tiao-jie\": \"点击坐标之后使用鼠标滚轮可以精确调节\",\n  \"dian-ji-ci-chu-xiu-gai-zhan-dian-xing-zhuang\": \"点击此处修改站点形状\",\n  \"xiu-gai-xing-zhuang\": \"修改形状\",\n  \"dian-ji-ci-chu-shan-chu-zhan-dian-huo-xin-jian-xian-lu\": \"点击此处删除站点或新建线路\",\n  \"shan-chu-huo-xin-jian\": \"删除或新建\",\n  \"dian-ji-ci-chu-she-zhi-zhan-dian-ming-cheng-wei-zhi\": \"点击此处设置站点名称位置\",\n  \"zhan-dian-ming-wei-zhi\": \"站点名位置\",\n  \"dian-ji-hui-se-de-fang-kuai-xuan-ze-fang-wei\": \"点击灰色的方块选择方位\",\n  \"dian-ji-zhong-jian-de-wen-zi-hui-fu-zi-dong-wei-zhi\": \"点击中间的文字恢复自动位置\",\n  \"dian-ji-biao-ti-da-kai-cai-dan-1\": \"点击标题打开菜单\",\n  \"guan-bi-zi-dong-yin-cang\": \"关闭自动隐藏\",\n  \"zhan-dian-ming-hui-zai-di-tu-suo-fang-dao-xiao-chi-du-shi-zi-dong-yin-cang-guan-bi-zi-dong-yin-cang-yi-que-bao-ke-yi-yi-zhi-xian-shi-zhan-dian-ming-cheng\": \"站点名会在地图缩放到小尺度时自动隐藏。关闭自动隐藏以确保可以一直显示站点名称\",\n  \"dian-ji-ren-yi-kong-bai-qu-yu-tui-chu-cai-dan-0\": \"点击任意空白区域退出菜单\",\n  \"tui-chu-cai-dan-0\": \"退出菜单\",\n  \"yi-da-kai-zhan-dian-ka-pian-1\": \"以打开站点卡片\",\n  \"zai-zhe-li-xiang-xia-gun-dong-yi-xia\": \"在这里向下滚动一下\",\n  \"zai-dian-ji-biao-qian-an-niu\": \"再点击标签按钮\",\n  \"chang-shi-gai-bian-zhan-dian-ming-dao-you-xia-jiao\": \"尝试改变站点名到右下角\",\n  \"dian-ji-you-xia-jiao-de-hui-se-fang-kuai\": \"点击右下角的灰色方块\",\n  \"ke-yi-kan-dao-zhan-dian-ming-yi-jing-wei-yu-zhan-dian-you-xia-jiao-le\": \"可以看到站点名已经位于站点右下角了\",\n  \"ke-yi-yong-zhe-zhong-fang-fa-xiu-gai-zhan-dian-ming-wei-zhi\": \"可以用这种方法修改站点名位置\",\n  \"dian-ji-zhong-jian-de-wen-zi-hui-fu-dao-zi-dong-xuan-ze-wei-zhi\": \"点击中间的文字恢复到自动选择位置\",\n  \"hui-fu-dao-zi-dong-xuan-ze-wei-zhi\": \"恢复到自动选择位置\",\n  \"shang-yi-bu\": \"上一步\",\n  \"wan-cheng\": \"完成\",\n  \"xia-yi-bu\": \"下一步\",\n  \"di-current-bu-gong-total-bu\": \"第{0}步，共{1}步\",\n  \"delete\": {\n    \"remove\": \"移除\",\n    \"delete\": \"删除\",\n    \"subtile\": \"不再作为{{lineName}}的第{{index}}站\",\n    \"cancel\": \"取消\"\n  },\n  \"que-shi-yao-deletetext-ma\": \"确实要{{deleteText}}吗?\",\n  \"teyvat\": \"提瓦特\",\n  \"wang-feng-jiao-zhan\": \"望风角站\",\n  \"zhai-xing-ya-zhan\": \"摘星崖站\",\n  \"qian-feng-shen-dian-zhan\": \"千风神殿站\",\n  \"newStation\": \"新增站点\",\n  \"lineNo\": \"{{lineId}} 号线\",\n  \"Common-teyvat-192be7b183f6eee79-1\": \"鹰翔海滩\",\n  \"Common-teyvat-192be7b183f6eee79-2\": \"达达乌帕谷\",\n  \"Common-teyvat-192be7b183f6eee79-3\": \"无相之雷\",\n  \"Common-teyvat-192be7b183f6eee79-4\": \"誓言岬机场\",\n  \"Common-teyvat-192be7b183f6eee79-5\": \"风起地站\",\n  \"Common-teyvat-192be7b183f6eee79-6\": \"星落湖南\",\n  \"Common-teyvat-192be7b183f6eee79-7\": \"星落湖\",\n  \"Common-teyvat-192be7b183f6eee79-8\": \"无相之风站\",\n  \"Common-teyvat-192be7b183f6eee79-9\": \"望风开发区\",\n  \"Common-teyvat-192be7b183f6eee79-10\": \"风神像站\",\n  \"Common-teyvat-192be7b183f6eee79-11\": \"蒙德站\",\n  \"Common-teyvat-192be7b183f6eee79-12\": \"清泉镇\",\n  \"Common-teyvat-192be7b183f6eee79-13\": \"晨曦酒庄\",\n  \"Common-teyvat-192be7b183f6eee79-14\": \"奔狼岭\",\n  \"Common-teyvat-192be7b183f6eee79-15\": \"奔狼岭北\",\n  \"Common-teyvat-192be7b183f6eee79-16\": \"风龙风景区\",\n  \"Common-teyvat-192be7b183f6eee79-17\": \"明冠峡\",\n  \"Common-teyvat-192be7b183f6eee79-18\": \"风龙国际机场\",\n  \"Common-teyvat-192be7b183f6eee79-19\": \"雪山脚站\",\n  \"Common-teyvat-192be7b183f6eee79-20\": \"无相之冰\",\n  \"Common-teyvat-192be7b183f6eee79-21\": \"雪山顶站\",\n  \"Common-teyvat-192be7b183f6eee79-22\": \"七天神像站\",\n  \"Common-teyvat-192be7b183f6eee79-23\": \"雪山湖\",\n  \"Common-teyvat-192be7b183f6eee79-24\": \"地中之盐\",\n  \"Common-teyvat-192be7b183f6eee79-25\": \"望舒客栈\",\n  \"Common-teyvat-192be7b183f6eee79-26\": \"石门\",\n  \"Common-teyvat-192be7b183f6eee79-27\": \"轻策庄\",\n  \"Common-teyvat-192be7b183f6eee79-28\": \"望舒南\",\n  \"Common-teyvat-192be7b183f6eee79-29\": \"归离原\",\n  \"Common-teyvat-192be7b183f6eee79-30\": \"渌华池南\",\n  \"Common-teyvat-192be7b183f6eee79-31\": \"璃月港\",\n  \"Common-teyvat-192be7b183f6eee79-32\": \"黄金屋\",\n  \"Common-teyvat-192be7b183f6eee79-33\": \"青墟浦\",\n  \"Common-teyvat-192be7b183f6eee79-34\": \"灵矩国际机场\",\n  \"Common-teyvat-192be7b183f6eee79-35\": \"天衡山\",\n  \"Common-teyvat-192be7b183f6eee79-36\": \"遁玉陵\",\n  \"Common-teyvat-192be7b183f6eee79-37\": \"渌华池\",\n  \"Common-teyvat-192be7b183f6eee79-38\": \"翠玦坡\",\n  \"Common-teyvat-192be7b183f6eee79-39\": \"太山府\",\n  \"Common-teyvat-192be7b183f6eee79-40\": \"机场东\",\n  \"Common-teyvat-192be7b183f6eee79-41\": \"庆云国际机场\",\n  \"Common-teyvat-192be7b183f6eee79-42\": \"奥藏山\",\n  \"Common-teyvat-192be7b183f6eee79-43\": \"琥牢山\",\n  \"Common-teyvat-192be7b183f6eee79-44\": \"伏龙树\",\n  \"Common-teyvat-192be7b183f6eee79-45\": \"南天门\",\n  \"Common-teyvat-192be7b183f6eee79-46\": \"天遒谷\",\n  \"Common-teyvat-192be7b183f6eee79-47\": \"伏鳌谷\",\n  \"Common-teyvat-192be7b183f6eee79-48\": \"香醉坡\",\n  \"Common-teyvat-192be7b183f6eee79-49\": \"无郁稠林\",\n  \"Common-teyvat-192be7b183f6eee79-50\": \"卡萨扎莱宫\",\n  \"Common-teyvat-192be7b183f6eee79-51\": \"茸蕈窟\",\n  \"Common-teyvat-192be7b183f6eee79-52\": \"须弥城\",\n  \"Common-teyvat-192be7b183f6eee79-53\": \"化城郭\",\n  \"Common-teyvat-192be7b183f6eee79-54\": \"丹砂崖\",\n  \"Common-teyvat-192be7b183f6eee79-55\": \"降诸魔山东\",\n  \"Common-teyvat-192be7b183f6eee79-56\": \"降诸魔山\",\n  \"Common-teyvat-192be7b183f6eee79-57\": \"奥摩斯港北\",\n  \"Common-teyvat-192be7b183f6eee79-58\": \"奥摩斯港\",\n  \"Common-teyvat-192be7b183f6eee79-59\": \"维摩庄\",\n  \"Common-teyvat-192be7b183f6eee79-60\": \"禅那园\",\n  \"Common-teyvat-192be7b183f6eee79-61\": \"谒颂幽境\",\n  \"Common-teyvat-192be7b183f6eee79-62\": \"桓那兰那\",\n  \"Common-teyvat-192be7b183f6eee79-63\": \"五绿洲\",\n  \"Common-teyvat-192be7b183f6eee79-64\": \"喀万驿\",\n  \"Common-teyvat-192be7b183f6eee79-65\": \"水天丛林\",\n  \"Common-teyvat-192be7b183f6eee79-66\": \"荼诃之座\",\n  \"Common-teyvat-192be7b183f6eee79-67\": \"阿如村\",\n  \"Common-teyvat-192be7b183f6eee79-68\": \"圣显厅\",\n  \"Common-teyvat-192be7b183f6eee79-69\": \"活力之家\",\n  \"Common-teyvat-192be7b183f6eee79-70\": \"丰饶绿洲\",\n  \"Common-teyvat-192be7b183f6eee79-71\": \"赤王陵\",\n  \"Common-teyvat-192be7b183f6eee79-72\": \"1号线\",\n  \"Common-teyvat-192be7b183f6eee79-73\": \"2号线\",\n  \"Common-teyvat-192be7b183f6eee79-74\": \"3号线\",\n  \"Common-teyvat-192be7b183f6eee79-75\": \"4号线\",\n  \"Common-teyvat-192be7b183f6eee79-76\": \"5号线\",\n  \"Common-teyvat-192be7b183f6eee79-77\": \"6号线\",\n  \"Common-teyvat-192be7b183f6eee79-78\": \"7号线\",\n  \"Common-teyvat-192be7b183f6eee79-79\": \"8号线\",\n  \"Common-teyvat-192be7b183f6eee79-80\": \"须弥2号线\",\n  \"Common-teyvat-192be7b183f6eee79-81\": \"须弥1号线\",\n  \"Common-teyvat-192be7b183f6eee79-82\": \"须弥3号线\",\n  \"Common-teyvat-192be7b183f6eee79-83\": \"须弥4号线\"\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\n\nimport App from './Entrance/App';\nimport reportWebVitals from './Entrance/reportWebVitals';\n\nconst root = ReactDOM.createRoot(document.getElementById('root'));\nroot.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();"
  },
  {
    "path": "src/types/svg.d.ts",
    "content": "declare module '*.svg' {\n  import React = require('react');\n  export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;\n  const src: string;\n  export default src;\n}"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"jsx\": \"react\",\n    /* Visit https://aka.ms/tsconfig.json to read more about this file */\n\n    /* Basic Options */\n    // \"incremental\": true,                   /* Enable incremental compilation */\n    \"target\": \"ES2015\",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */\n    \"module\": \"commonjs\",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */\n    // \"lib\": [],                             /* Specify library files to be included in the compilation. */\n    // \"allowJs\": true,                       /* Allow javascript files to be compiled. */\n    // \"checkJs\": true,                       /* Report errors in .js files. */\n    // \"jsx\": \"preserve\",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */\n    // \"declaration\": true,                   /* Generates corresponding '.d.ts' file. */\n    // \"declarationMap\": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */\n    // \"sourceMap\": true,                     /* Generates corresponding '.map' file. */\n    // \"outFile\": \"./\",                       /* Concatenate and emit output to single file. */\n    // \"outDir\": \"./\",                        /* Redirect output structure to the directory. */\n    // \"rootDir\": \"./\",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */\n    // \"composite\": true,                     /* Enable project compilation */\n    // \"tsBuildInfoFile\": \"./\",               /* Specify file to store incremental compilation information */\n    // \"removeComments\": true,                /* Do not emit comments to output. */\n    // \"noEmit\": true,                        /* Do not emit outputs. */\n    // \"importHelpers\": true,                 /* Import emit helpers from 'tslib'. */\n    // \"downlevelIteration\": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */\n    // \"isolatedModules\": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */\n\n    /* Strict Type-Checking Options */\n    \"strict\": true,                           /* Enable all strict type-checking options. */\n    // \"noImplicitAny\": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */\n    // \"strictNullChecks\": true,              /* Enable strict null checks. */\n    // \"strictFunctionTypes\": true,           /* Enable strict checking of function types. */\n    // \"strictBindCallApply\": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */\n    // \"strictPropertyInitialization\": true,  /* Enable strict checking of property initialization in classes. */\n    // \"noImplicitThis\": true,                /* Raise error on 'this' expressions with an implied 'any' type. */\n    // \"alwaysStrict\": true,                  /* Parse in strict mode and emit \"use strict\" for each source file. */\n\n    /* Additional Checks */\n    // \"noUnusedLocals\": true,                /* Report errors on unused locals. */\n    // \"noUnusedParameters\": true,            /* Report errors on unused parameters. */\n    // \"noImplicitReturns\": true,             /* Report error when not all code paths in function return a value. */\n    // \"noFallthroughCasesInSwitch\": true,    /* Report errors for fallthrough cases in switch statement. */\n\n    /* Module Resolution Options */\n    // \"moduleResolution\": \"node\",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */\n    // \"baseUrl\": \"./\",                       /* Base directory to resolve non-absolute module names. */\n    // \"paths\": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */\n    // \"rootDirs\": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */\n    // \"typeRoots\": [],                       /* List of folders to include type definitions from. */\n    // \"types\": [],                           /* Type declaration files to be included in compilation. */\n    // \"allowSyntheticDefaultImports\": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */\n   \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */\n    // \"preserveSymlinks\": true,              /* Do not resolve the real path of symlinks. */\n    // \"allowUmdGlobalAccess\": true,          /* Allow accessing UMD globals from modules. */\n\n    /* Source Map Options */\n    // \"sourceRoot\": \"\",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */\n    // \"mapRoot\": \"\",                         /* Specify the location where debugger should locate map files instead of generated locations. */\n    // \"inlineSourceMap\": true,               /* Emit a single file with source maps instead of having a separate file. */\n    // \"inlineSources\": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */\n\n    /* Experimental Options */\n    // \"experimentalDecorators\": true,        /* Enables experimental support for ES7 decorators. */\n    // \"emitDecoratorMetadata\": true,         /* Enables experimental support for emitting type metadata for decorators. */\n\n    /* Advanced Options */\n    \"skipLibCheck\": true,                     /* Skip type checking of declaration files. */\n    \"forceConsistentCasingInFileNames\": true  /* Disallow inconsistently-cased references to the same file. */\n  }\n}\n"
  }
]