diff --git a/public/images/facilities/airport_london.svg b/public/images/facilities/airport_london.svg new file mode 100644 index 00000000..3993d978 --- /dev/null +++ b/public/images/facilities/airport_london.svg @@ -0,0 +1,5 @@ + + + diff --git a/public/images/facilities/coach_station_london.svg b/public/images/facilities/coach_station_london.svg new file mode 100644 index 00000000..d816ac93 --- /dev/null +++ b/public/images/facilities/coach_station_london.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/public/images/facilities/river_craft.svg b/public/images/facilities/river_craft.svg new file mode 100644 index 00000000..69d99f9a --- /dev/null +++ b/public/images/facilities/river_craft.svg @@ -0,0 +1,11 @@ + + + + diff --git a/src/components/panels/details/specific-attrs.tsx b/src/components/panels/details/specific-attrs.tsx index c63743e9..44dea9e6 100644 --- a/src/components/panels/details/specific-attrs.tsx +++ b/src/components/panels/details/specific-attrs.tsx @@ -1,6 +1,6 @@ import { Text } from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; -import { MiscNodeId, StnId } from '../../../constants/constants'; +import { AttrsProps, MiscNodeId, StnId } from '../../../constants/constants'; import { useRootDispatch, useRootSelector } from '../../../redux'; import { saveGraph } from '../../../redux/param/param-slice'; import { refreshEdgesThunk, refreshNodesThunk } from '../../../redux/runtime/runtime-slice'; @@ -18,7 +18,7 @@ export const NodeSpecificAttributes = () => { const [id] = selected; const type = window.graph.getNodeAttribute(id, 'type'); - const AttrsComponent = type in nodes && nodes[type].attrsComponent; + const AttrsComponent = type in nodes && (nodes[type].attrsComponent as React.FC>); const attrs = (window.graph.getNodeAttribute(id, type) ?? {}) as any; const handleAttrsUpdate = (selectedFirst: string, attrs: any) => { diff --git a/src/components/svg-canvas-graph.tsx b/src/components/svg-canvas-graph.tsx index 569c4793..1bf7b9a4 100644 --- a/src/components/svg-canvas-graph.tsx +++ b/src/components/svg-canvas-graph.tsx @@ -27,6 +27,13 @@ import singleColor from './svgs/lines/styles/single-color'; import miscNodes from './svgs/nodes/misc-nodes'; import { default as stations } from './svgs/stations/stations'; +const connectableNodesType = [ + ...Object.values(StationType), + MiscNodeType.Virtual, + MiscNodeType.Master, + MiscNodeType.LondonArrow, +]; + const SvgCanvas = () => { const dispatch = useRootDispatch(); const graph = React.useRef(window.graph); @@ -114,7 +121,6 @@ const SvgCanvas = () => { if (mode.startsWith('line')) { if (!keepLastPath) dispatch(setMode('free')); - const connectableNodesType = [...Object.values(StationType), MiscNodeType.Virtual, MiscNodeType.Master]; const couldActiveBeConnected = graph.current.hasNode(active) && connectableNodesType.includes(graph.current.getNodeAttribute(active, 'type')); diff --git a/src/components/svgs/lines/lines.ts b/src/components/svgs/lines/lines.ts index ac49f1c7..409e1095 100644 --- a/src/components/svgs/lines/lines.ts +++ b/src/components/svgs/lines/lines.ts @@ -25,6 +25,10 @@ import lrtSingleColor from './styles/lrt-single-color'; import londonTubeInternalInt from './styles/london-tube-internal-int'; import londonTube10MinWalk from './styles/london-tube-10-min-walk'; import londonTubeTerminal from './styles/london-tube-terminal'; +import londonRail from './styles/london-rail'; +import londonSandwich from './styles/london-sandwich'; +import londonLutonAirportDART from './styles/london-DART'; +import londonIFSCloudCableCar from './styles/london-ifs-could-cable-car'; import guangdongIntercityRailway from './styles/guangdong-intercity-railway'; export const linePaths = { @@ -57,5 +61,9 @@ export const lineStyles = { [LineStyleType.LondonTubeTerminal]: londonTubeTerminal, [LineStyleType.LondonTubeInternalInt]: londonTubeInternalInt, [LineStyleType.LondonTube10MinWalk]: londonTube10MinWalk, + [LineStyleType.LondonRail]: londonRail, + [LineStyleType.LondonSandwich]: londonSandwich, + [LineStyleType.LondonLutonAirportDART]: londonLutonAirportDART, + [LineStyleType.LondonIFSCloudCableCar]: londonIFSCloudCableCar, [LineStyleType.GuangdongIntercityRailway]: guangdongIntercityRailway, }; diff --git a/src/components/svgs/lines/styles/dual-color.tsx b/src/components/svgs/lines/styles/dual-color.tsx index ddd6bccf..100b3b6b 100644 --- a/src/components/svgs/lines/styles/dual-color.tsx +++ b/src/components/svgs/lines/styles/dual-color.tsx @@ -88,15 +88,17 @@ const DualColorSwitch = () => { }; const dualColorAttrsComponent = (props: AttrsProps) => { + const { t } = useTranslation(); + const fields: RmgFieldsField[] = [ { type: 'custom', - label: 'panel.details.lines.dualColor.swap', + label: t('panel.details.lines.dualColor.swap'), component: , }, { type: 'custom', - label: 'panel.details.lines.dualColor.colorA', + label: t('panel.details.lines.dualColor.colorA'), component: ( ) => { }, { type: 'custom', - label: 'panel.details.lines.dualColor.colorB', + label: t('panel.details.lines.dualColor.colorB'), component: ( ) => { + const { id, path, styleAttrs, handlePointerDown } = props; + const { color = defaultLondonLutonAirportDARTAttributes.color } = + styleAttrs ?? defaultLondonLutonAirportDARTAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + + return ( + + + + + ); +}; + +/** + * LondonLutonAirportDART specific props. + */ +export interface LondonLutonAirportDARTAttributes extends LinePathAttributes, AttributesWithColor {} + +const defaultLondonLutonAirportDARTAttributes: LondonLutonAirportDARTAttributes = { + color: [CityCode.London, 'rail', '#d6ae00', MonoColour.white], +}; + +const londonLutonAirportDARTAttrsComponent = (props: AttrsProps) => { + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'custom', + label: t('color'), + component: ( + + ), + }, + ]; + + return ; +}; + +const londonLutonAirportDART: LineStyle = { + component: LondonLutonAirportDART, + defaultAttrs: defaultLondonLutonAirportDARTAttributes, + attrsComponent: londonLutonAirportDARTAttrsComponent, + metadata: { + displayName: 'panel.details.lines.londonLutonAirportDART.displayName', + supportLinePathType: [LinePathType.Diagonal, LinePathType.Perpendicular, LinePathType.RotatePerpendicular], + }, +}; + +export default londonLutonAirportDART; diff --git a/src/components/svgs/lines/styles/london-ifs-could-cable-car.tsx b/src/components/svgs/lines/styles/london-ifs-could-cable-car.tsx new file mode 100644 index 00000000..e1271bf0 --- /dev/null +++ b/src/components/svgs/lines/styles/london-ifs-could-cable-car.tsx @@ -0,0 +1,72 @@ +import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; +import { MonoColour } from '@railmapgen/rmg-palette-resources'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { AttrsProps, CityCode } from '../../../../constants/constants'; +import { + LinePathAttributes, + LinePathType, + LineStyle, + LineStyleComponentProps, + LineStyleType, +} from '../../../../constants/lines'; +import { AttributesWithColor, ColorField } from '../../../panels/details/color-field'; + +const LondonIFSCloudCableCar = (props: LineStyleComponentProps) => { + const { id, path, styleAttrs, handlePointerDown } = props; + const { color = defaultLondonIFSCloudCableCarAttributes.color } = + styleAttrs ?? defaultLondonIFSCloudCableCarAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + + return ( + + + + + + ); +}; + +/** + * LondonIFSCloudCableCar specific props. + */ +export interface LondonIFSCloudCableCarAttributes extends LinePathAttributes, AttributesWithColor {} + +const defaultLondonIFSCloudCableCarAttributes: LondonIFSCloudCableCarAttributes = { + color: [CityCode.London, 'dangleway', '#dc241f', MonoColour.white], +}; + +const LondonIFSCloudCableCarAttrsComponent = (props: AttrsProps) => { + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'custom', + label: t('color'), + component: ( + + ), + }, + ]; + + return ; +}; + +const londonIFSCloudCableCar: LineStyle = { + component: LondonIFSCloudCableCar, + defaultAttrs: defaultLondonIFSCloudCableCarAttributes, + attrsComponent: LondonIFSCloudCableCarAttrsComponent, + metadata: { + displayName: 'panel.details.lines.londonIFSCloudCableCar.displayName', + supportLinePathType: [LinePathType.Diagonal, LinePathType.Perpendicular, LinePathType.RotatePerpendicular], + }, +}; + +export default londonIFSCloudCableCar; diff --git a/src/components/svgs/lines/styles/london-rail.tsx b/src/components/svgs/lines/styles/london-rail.tsx new file mode 100644 index 00000000..80743033 --- /dev/null +++ b/src/components/svgs/lines/styles/london-rail.tsx @@ -0,0 +1,110 @@ +import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; +import { MonoColour } from '@railmapgen/rmg-palette-resources'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { AttrsProps, CityCode, Theme } from '../../../../constants/constants'; +import { + LinePathAttributes, + LinePathType, + LineStyle, + LineStyleComponentProps, + LineStyleType, +} from '../../../../constants/lines'; +import { ColorField } from '../../../panels/details/color-field'; + +const LondonRail = (props: LineStyleComponentProps) => { + const { id, path, styleAttrs, handlePointerDown } = props; + const { + colorBackground = defaultLondonRailAttributes.colorBackground, + colorForeground = defaultLondonRailAttributes.colorForeground, + limitedService = defaultLondonRailAttributes.limitedService, + } = styleAttrs ?? defaultLondonRailAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + + return !limitedService ? ( + + + + + ) : ( + + + + + + ); +}; + +/** + * LondonRail specific props. + */ +export interface LondonRailAttributes extends LinePathAttributes { + colorBackground: Theme; + colorForeground: Theme; + limitedService: boolean; +} + +const defaultLondonRailAttributes: LondonRailAttributes = { + colorBackground: [CityCode.London, 'thameslink', '#d28db0', MonoColour.white], + colorForeground: [CityCode.London, 'white', '#ffffff', MonoColour.black], + limitedService: false, +}; + +const londonRailAttrsComponent = (props: AttrsProps) => { + const { id, attrs, handleAttrsUpdate } = props; + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'switch', + label: t('panel.details.lines.londonRail.limitedService'), + oneLine: true, + isChecked: attrs.limitedService, + onChange: val => { + attrs.limitedService = val; + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + { + type: 'custom', + label: t('panel.details.lines.londonRail.colorBackground'), + component: ( + + ), + }, + { + type: 'custom', + label: t('panel.details.lines.londonRail.colorForeground'), + component: ( + + ), + }, + ]; + + return ; +}; + +const londonRail: LineStyle = { + component: LondonRail, + defaultAttrs: defaultLondonRailAttributes, + attrsComponent: londonRailAttrsComponent, + metadata: { + displayName: 'panel.details.lines.londonRail.displayName', + supportLinePathType: [LinePathType.Diagonal, LinePathType.Perpendicular, LinePathType.RotatePerpendicular], + }, +}; + +export default londonRail; diff --git a/src/components/svgs/lines/styles/london-sandwich.tsx b/src/components/svgs/lines/styles/london-sandwich.tsx new file mode 100644 index 00000000..d88eb221 --- /dev/null +++ b/src/components/svgs/lines/styles/london-sandwich.tsx @@ -0,0 +1,83 @@ +import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; +import { MonoColour } from '@railmapgen/rmg-palette-resources'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { AttrsProps, CityCode } from '../../../../constants/constants'; +import { + LinePathAttributes, + LinePathType, + LineStyle, + LineStyleComponentProps, + LineStyleType, +} from '../../../../constants/lines'; +import { AttributesWithColor, ColorField } from '../../../panels/details/color-field'; + +const LondonSandwichPre = (props: LineStyleComponentProps) => { + const { id, path, styleAttrs, handlePointerDown } = props; + const { color = defaultLondonSandwichAttributes.color } = styleAttrs ?? defaultLondonSandwichAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + + return ( + + + + ); +}; + +const LondonSandwich = (props: LineStyleComponentProps) => { + const { id, path, styleAttrs, handlePointerDown } = props; + const { color = defaultLondonSandwichAttributes.color } = styleAttrs ?? defaultLondonSandwichAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + + return ( + + + + ); +}; + +/** + * LondonSandwich specific props. + */ +export interface LondonSandwichAttributes extends LinePathAttributes, AttributesWithColor {} + +const defaultLondonSandwichAttributes: LondonSandwichAttributes = { + color: [CityCode.London, 'elizabeth', '#9364cc', MonoColour.white], +}; + +const LondonSandwichAttrsComponent = (props: AttrsProps) => { + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'custom', + label: t('color'), + component: ( + + ), + }, + ]; + + return ; +}; + +const londonSandwich: LineStyle = { + component: LondonSandwich, + preComponent: LondonSandwichPre, + defaultAttrs: defaultLondonSandwichAttributes, + attrsComponent: LondonSandwichAttrsComponent, + metadata: { + displayName: 'panel.details.lines.londonSandwich.displayName', + supportLinePathType: [LinePathType.Diagonal, LinePathType.Perpendicular, LinePathType.RotatePerpendicular], + }, +}; + +export default londonSandwich; diff --git a/src/components/svgs/lines/styles/london-tube-internal-int.tsx b/src/components/svgs/lines/styles/london-tube-internal-int.tsx index 37173c8a..1ff576ad 100644 --- a/src/components/svgs/lines/styles/london-tube-internal-int.tsx +++ b/src/components/svgs/lines/styles/london-tube-internal-int.tsx @@ -1,11 +1,7 @@ import React from 'react'; -import { NodeType } from '../../../../constants/constants'; import { LinePathAttributes, LinePathType, LineStyle, LineStyleComponentProps } from '../../../../constants/lines'; -import { ExternalStationAttributes, StationType } from '../../../../constants/stations'; -const X_HEIGHT = 5; - -const LondonTubeInternalInt = (props: LineStyleComponentProps) => { +const LondonTubeInternalIntPre = (props: LineStyleComponentProps) => { const { id, path, handlePointerDown } = props; const onPointerDown = React.useCallback( @@ -14,26 +10,13 @@ const LondonTubeInternalInt = (props: LineStyleComponentProps + ); }; -// Accessible stations have a large icon that the path should hide. -const getMaskR = (type: NodeType, attr: ExternalStationAttributes) => { - if (type === StationType.LondonTubeBasic) { - const { stepFreeAccess } = attr[StationType.LondonTubeBasic] ?? { stepFreeAccess: 'none' }; - if (stepFreeAccess !== 'none') return 1.5 * X_HEIGHT; - } - if (type === StationType.LondonTubeInt) { - const { stepFreeAccess } = attr[StationType.LondonTubeInt] ?? { stepFreeAccess: 'none' }; - if (stepFreeAccess !== 'none') return 1.5 * X_HEIGHT; - } - return X_HEIGHT; -}; - -const LondonTubeInternalIntPost = (props: LineStyleComponentProps) => { +const LondonTubeInternalInt = (props: LineStyleComponentProps) => { const { id, path, handlePointerDown } = props; const onPointerDown = React.useCallback( @@ -41,50 +24,9 @@ const LondonTubeInternalIntPost = (props: LineStyleComponentProps - {/* TODO: The masked part is still clickable with a pointer cursor. */} - - {/* Everything under a white pixel will be visible. */} - - {/* Everything under a black pixel will be invisible. */} - {/* `- 0.05` will hide the black edge between the icon and the path. */} - - - - + + ); }; @@ -100,7 +42,7 @@ const attrsComponent = () => undefined; const londonTubeInternalInt: LineStyle = { component: LondonTubeInternalInt, - postComponent: LondonTubeInternalIntPost, + preComponent: LondonTubeInternalIntPre, defaultAttrs: defaultLondonTubeInternalIntAttributes, attrsComponent, metadata: { diff --git a/src/components/svgs/lines/styles/single-color.tsx b/src/components/svgs/lines/styles/single-color.tsx index 71874dc1..066dafa7 100644 --- a/src/components/svgs/lines/styles/single-color.tsx +++ b/src/components/svgs/lines/styles/single-color.tsx @@ -1,6 +1,7 @@ import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; import { MonoColour } from '@railmapgen/rmg-palette-resources'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { AttrsProps, CityCode } from '../../../../constants/constants'; import { LinePathAttributes, @@ -45,10 +46,12 @@ const defaultSingleColorAttributes: SingleColorAttributes = { }; const singleColorAttrsComponent = (props: AttrsProps) => { + const { t } = useTranslation(); + const fields: RmgFieldsField[] = [ { type: 'custom', - label: 'color', + label: t('color'), component: ( ), diff --git a/src/components/svgs/nodes/facilities.tsx b/src/components/svgs/nodes/facilities.tsx index f4d75ba7..de561340 100644 --- a/src/components/svgs/nodes/facilities.tsx +++ b/src/components/svgs/nodes/facilities.tsx @@ -45,6 +45,9 @@ export enum FacilitiesType { AirportGuangzhou = 'airport_guangzhou', RailwayGuangzhou = 'railway_guangzhou', IntercityGuangzhou = 'intercity_guangzhou', + RiverCraftLondon = 'river_craft', + AirportLondon = 'airport_london', + CoachStationLondon = 'coach_station_london', } const Facilities = (props: NodeComponentProps) => { @@ -140,6 +143,9 @@ const attrsComponent = (props: AttrsProps) => { [FacilitiesType.AirportGuangzhou]: 'Airport Guangzhou', [FacilitiesType.RailwayGuangzhou]: 'Railway Guangzhou', [FacilitiesType.IntercityGuangzhou]: 'Intercity Guangzhou', + [FacilitiesType.RiverCraftLondon]: 'River services interchange', + [FacilitiesType.AirportLondon]: 'Airport London', + [FacilitiesType.CoachStationLondon]: 'Victoria Coach Station', }, onChange: val => { attrs.type = val as FacilitiesType; diff --git a/src/components/svgs/nodes/london-arrow.tsx b/src/components/svgs/nodes/london-arrow.tsx new file mode 100644 index 00000000..696eccde --- /dev/null +++ b/src/components/svgs/nodes/london-arrow.tsx @@ -0,0 +1,134 @@ +import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; +import { MonoColour } from '@railmapgen/rmg-palette-resources'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { AttrsProps, CityCode } from '../../../constants/constants'; +import { MiscNodeType, Node, NodeComponentProps } from '../../../constants/nodes'; +import { Rotate } from '../../../constants/stations'; +import { AttributesWithColor, ColorField } from '../../panels/details/color-field'; + +const X = 5; +const D = `M0,0 L${-X * 2},${-X * 2} L${Math.SQRT2 * X - 2 * X},${2 * -X} L${Math.SQRT2 * X},0 L${Math.SQRT2 * X - 2 * X},${2 * X} L${2 * -X},${2 * X} Z`; + +const LondonArrow = (props: NodeComponentProps) => { + const { id, x, y, attrs, handlePointerDown, handlePointerMove, handlePointerUp } = props; + const { + color = defaultLondonArrowAttributes.color, + rotate = defaultLondonArrowAttributes.rotate, + type = defaultLondonArrowAttributes.type, + } = attrs ?? defaultLondonArrowAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + const onPointerMove = React.useCallback( + (e: React.PointerEvent) => handlePointerMove(id, e), + [id, handlePointerMove] + ); + const onPointerUp = React.useCallback( + (e: React.PointerEvent) => handlePointerUp(id, e), + [id, handlePointerUp] + ); + + return ( + + {type === 'continuation' ? ( + + ) : type === 'sandwich' ? ( + + ) : ( + + )} + + ); +}; + +/** + * LondonArrow specific props. + */ +export interface LondonArrowAttributes extends AttributesWithColor { + rotate: Rotate; + type: 'continuation' | 'sandwich' | 'tube'; +} + +const defaultLondonArrowAttributes: LondonArrowAttributes = { + color: [CityCode.London, 'thameslink', '#d28db0', MonoColour.white], + rotate: 0, + type: 'continuation', +}; + +const londonArrowAttrsComponent = (props: AttrsProps) => { + const { id, attrs, handleAttrsUpdate } = props; + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'select', + label: t('panel.details.stations.common.rotate'), + value: attrs.rotate, + options: { 0: '0', 45: '45', 90: '90', 135: '135', 180: '180', 225: '225', 270: '270', 315: '315' }, + onChange: val => { + attrs.rotate = Number(val) as Rotate; + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + { + type: 'select', + label: t('panel.details.nodes.londonArrow.type'), + value: attrs.type, + options: { + continuation: t('panel.details.nodes.londonArrow.continuation'), + sandwich: t('panel.details.nodes.londonArrow.sandwich'), + tube: t('panel.details.nodes.londonArrow.tube'), + }, + onChange: val => { + attrs.type = val as 'continuation' | 'sandwich' | 'tube'; + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + { + type: 'custom', + label: t('color'), + component: , + minW: 'full', + }, + ]; + + return ; +}; + +const londonArrowIcon = ( + + + +); + +const londonArrow: Node = { + component: LondonArrow, + icon: londonArrowIcon, + defaultAttrs: defaultLondonArrowAttributes, + attrsComponent: londonArrowAttrsComponent, + metadata: { + displayName: 'panel.details.nodes.londonArrow.displayName', + tags: [], + }, +}; + +export default londonArrow; diff --git a/src/components/svgs/nodes/misc-nodes.ts b/src/components/svgs/nodes/misc-nodes.ts index ce8fdd6e..71040717 100644 --- a/src/components/svgs/nodes/misc-nodes.ts +++ b/src/components/svgs/nodes/misc-nodes.ts @@ -16,6 +16,7 @@ import mrtLineBadge from './mrt-line-badge'; import jrEastLineBadge from './jr-east-line-badge'; import qingdaoMetroNumLineBadge from './qingdao-metro-num-line-badge'; import guangdongIntercityRailwayLineBadge from './guangdong-intercity-railway-line-badge'; +import londonArrow from './london-arrow'; import facilities from './facilities'; import text from './text'; import i18nText from './i18n-text'; @@ -39,6 +40,7 @@ const miscNodes = { [MiscNodeType.JREastLineBadge]: jrEastLineBadge, [MiscNodeType.QingdaoMetroNumLineBadge]: qingdaoMetroNumLineBadge, [MiscNodeType.GuangdongIntercityRailwayLineBadge]: guangdongIntercityRailwayLineBadge, + [MiscNodeType.LondonArrow]: londonArrow, [MiscNodeType.Facilities]: facilities, [MiscNodeType.Text]: text, [MiscNodeType.I18nText]: i18nText, diff --git a/src/components/svgs/stations/london-river-services-interchange.tsx b/src/components/svgs/stations/london-river-services-interchange.tsx new file mode 100644 index 00000000..aeea02fd --- /dev/null +++ b/src/components/svgs/stations/london-river-services-interchange.tsx @@ -0,0 +1,183 @@ +import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { AttrsProps, CanvasType, CategoriesType, CityCode } from '../../../constants/constants'; +import { + NameOffsetX, + NameOffsetY, + Station, + StationAttributes, + StationComponentProps, + StationType, + defaultStationAttributes, +} from '../../../constants/stations'; +import { MultilineText } from '../common/multiline-text'; + +const X_HEIGHT = 5; +const FONT_SIZE = 2 * X_HEIGHT; +const LINE_HEIGHT = 0.85 * FONT_SIZE; + +const D1 = + 'M-18.2,12.6c2.4-0.6,5.8-1.6,11.5-0.4c2.9,0.6,5.6,1.3,8.3,1.3c3.5,0,5.4-0.6,8.1-1.2c2.4-0.6,5.2-1.2,7.4-1.1c3.8,0.1,6.6,0.7,8.2,1.4l-1.2-3.1C21,8.3,15.8,7.7,9.7,9.5c-2.6,0.7-5.2,1.3-7.9,1.2c-2.5,0-4.8-0.4-7.2-1C-13,8-15.9,9.3-19.8,10.3L-18.2,12.6z'; +const D2 = + 'M23.8-2h-4.1l-1.8-4.8c0,0-0.1-0.6-1-1.3c-0.6-0.5-1.6-0.5-1.6-0.5H4v-2h-6.9l-1.1-1.5l0.8-1.9h-1.9l-1.5,3.5h-2.6v2h-5.8c0,0-0.8,0.1-1.2,0.3c-0.4,0.3-0.6,0.5-0.6,0.5l-4.4,5.8h-7.3l7.3,10c1.6-0.7,6.6-2,9.7-1.9c4.1,0.1,9.5,1.9,13.1,1.9c6.6,0,8.8-2,14.6-2.3c7.1-0.4,11.6,2.3,11.6,2.3L23.8-2z M-11.1-2h-7.1l1.9-2.5c0,0,0.8-1.1,1.2-1.3c0.7-0.4,1.2-0.5,1.2-0.5h2.8V-2z M-9.2-2v-4.3h7.4v4.4L-9.2-2z M7.4-2H0v-4.3h7.4V-2z M9.3-2v-4.3h5.1c0,0,0.4,0,0.8,0.4c0.3,0.2,0.5,0.7,0.5,0.7l1.2,3.3L9.3-2z'; + +const LondonRiverServicesIntStation = (props: StationComponentProps) => { + const { id, x, y, attrs, handlePointerDown, handlePointerMove, handlePointerUp } = props; + const { + names = defaultStationAttributes.names, + nameOffsetX = defaultLondonRiverServicesIntStationAttributes.nameOffsetX, + nameOffsetY = defaultLondonRiverServicesIntStationAttributes.nameOffsetY, + } = attrs[StationType.LondonRiverServicesInt] ?? defaultLondonRiverServicesIntStationAttributes; + + const onPointerDown = React.useCallback( + (e: React.PointerEvent) => handlePointerDown(id, e), + [id, handlePointerDown] + ); + const onPointerMove = React.useCallback( + (e: React.PointerEvent) => handlePointerMove(id, e), + [id, handlePointerMove] + ); + const onPointerUp = React.useCallback( + (e: React.PointerEvent) => handlePointerUp(id, e), + [id, handlePointerUp] + ); + + const textDx = + nameOffsetX === 'left' + ? -(X_HEIGHT / 2 + X_HEIGHT * 1.33) + : nameOffsetX === 'right' + ? X_HEIGHT / 2 + X_HEIGHT * 1.33 + : 0; + const textDy = + nameOffsetY === 'top' + ? -(X_HEIGHT / 2 + X_HEIGHT * 1.33) + : nameOffsetY === 'bottom' + ? X_HEIGHT / 2 + X_HEIGHT * 1.33 + : 0; // fixed dy for each rotation + + const textAnchor = nameOffsetX === 'left' ? 'end' : nameOffsetX === 'right' ? 'start' : 'middle'; + const dominantBaseline = nameOffsetY === 'top' ? 'auto' : nameOffsetY === 'bottom' ? 'hanging' : 'middle'; + + return ( + + + + + + + + + + + + + + ); +}; + +/** + * LondonRiverServicesIntStation specific props. + */ +export interface LondonRiverServicesIntStationAttributes extends StationAttributes { + nameOffsetX: NameOffsetX; + nameOffsetY: NameOffsetY; +} + +const defaultLondonRiverServicesIntStationAttributes: LondonRiverServicesIntStationAttributes = { + names: ['Station'], + nameOffsetX: 'right', + nameOffsetY: 'top', +}; + +const londonRiverServicesIntAttrsComponent = (props: AttrsProps) => { + const { id, attrs, handleAttrsUpdate } = props; + const { t } = useTranslation(); + + const fields: RmgFieldsField[] = [ + { + type: 'textarea', + label: t('panel.details.stations.common.nameEn'), + value: attrs.names[0], + onChange: val => { + attrs.names[0] = val.toString(); + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + { + type: 'select', + label: t('panel.details.stations.common.nameOffsetX'), + value: attrs.nameOffsetX, + options: { + left: t('panel.details.stations.common.left'), + middle: t('panel.details.stations.common.middle'), + right: t('panel.details.stations.common.right'), + }, + disabledOptions: attrs.nameOffsetY === 'middle' ? ['middle'] : [], + onChange: val => { + attrs.nameOffsetX = val as NameOffsetX; + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + { + type: 'select', + label: t('panel.details.stations.common.nameOffsetY'), + value: attrs.nameOffsetY, + options: { + top: t('panel.details.stations.common.top'), + middle: t('panel.details.stations.common.middle'), + bottom: t('panel.details.stations.common.bottom'), + }, + disabledOptions: attrs.nameOffsetX === 'middle' ? ['middle'] : [], + onChange: val => { + attrs.nameOffsetY = val as NameOffsetY; + handleAttrsUpdate(id, attrs); + }, + minW: 'full', + }, + ]; + + return ; +}; + +const londonRiverServicesIntStationIcon = ( + + + + + + + +); + +const londonRiverServicesIntStation: Station = { + component: LondonRiverServicesIntStation, + icon: londonRiverServicesIntStationIcon, + defaultAttrs: defaultLondonRiverServicesIntStationAttributes, + attrsComponent: londonRiverServicesIntAttrsComponent, + metadata: { + displayName: 'panel.details.stations.londonRiverServicesInt.displayName', + cities: [CityCode.London], + canvas: [CanvasType.RailMap], + categories: [CategoriesType.Metro], + tags: [], + }, +}; + +export default londonRiverServicesIntStation; diff --git a/src/components/svgs/stations/london-tube-basic.tsx b/src/components/svgs/stations/london-tube-basic.tsx index 74546867..b76f440a 100644 --- a/src/components/svgs/stations/london-tube-basic.tsx +++ b/src/components/svgs/stations/london-tube-basic.tsx @@ -171,7 +171,8 @@ const LondonTubeBasicStation = (props: StationComponentProps) => { // rotate starts from top-middle while Math.sin/cos starts from middle-right const rad = ((rotate - 90) * Math.PI) / 180; - const height = (terminal ? 2 : 1) * (0.66 * X_HEIGHT + X_HEIGHT / 2); + // 0.5 cover the gap between the station icon and the line + const height = terminal ? 2 * (0.66 * X_HEIGHT + X_HEIGHT / 2) : 0.66 * X_HEIGHT + 0.5; const textDx = ROTATE_CONST[rotate].textDx + // fixed dx for each rotation Math.cos(rad) * Math.max(...transfer[0].map(_ => _[4])) * X_HEIGHT; // dynamic dx of n share tracks diff --git a/src/components/svgs/stations/london-tube-int.tsx b/src/components/svgs/stations/london-tube-int.tsx index bd36fd3b..14610204 100644 --- a/src/components/svgs/stations/london-tube-int.tsx +++ b/src/components/svgs/stations/london-tube-int.tsx @@ -181,7 +181,7 @@ const londonTubeIntAttrsComponent = (props: AttrsProps - + ); diff --git a/src/components/svgs/stations/stations.ts b/src/components/svgs/stations/stations.ts index b8efea0d..23359197 100644 --- a/src/components/svgs/stations/stations.ts +++ b/src/components/svgs/stations/stations.ts @@ -24,6 +24,7 @@ import tokyoMetroBasicStation from './tokyo-metro-basic'; import tokyoMetroIntStation from './tokyo-metro-int'; import londonTubeBasicStation from './london-tube-basic'; import londonTubeIntStation from './london-tube-int'; +import londonRiverServicesIntStation from './london-river-services-interchange'; import guangdongIntercityRailwayStation from './guangdong-intercity-railway'; const stations = { @@ -52,6 +53,7 @@ const stations = { [StationType.TokyoMetroInt]: tokyoMetroIntStation, [StationType.LondonTubeBasic]: londonTubeBasicStation, [StationType.LondonTubeInt]: londonTubeIntStation, + [StationType.LondonRiverServicesInt]: londonRiverServicesIntStation, [StationType.GuangdongIntercityRailway]: guangdongIntercityRailwayStation, }; diff --git a/src/constants/lines.ts b/src/constants/lines.ts index 545cbb57..6a319054 100644 --- a/src/constants/lines.ts +++ b/src/constants/lines.ts @@ -26,6 +26,10 @@ import { LRTSingleColorAttributes } from '../components/svgs/lines/styles/lrt-si import { LondonTubeTerminalAttributes } from '../components/svgs/lines/styles/london-tube-terminal'; import { LondonTubeInternalIntAttributes } from '../components/svgs/lines/styles/london-tube-internal-int'; import { LondonTube10MinWalkAttributes } from '../components/svgs/lines/styles/london-tube-10-min-walk'; +import { LondonRailAttributes } from '../components/svgs/lines/styles/london-rail'; +import { LondonSandwichAttributes } from '../components/svgs/lines/styles/london-sandwich'; +import { LondonLutonAirportDARTAttributes } from '../components/svgs/lines/styles/london-DART'; +import { LondonIFSCloudCableCarAttributes } from '../components/svgs/lines/styles/london-ifs-could-cable-car'; import { GuangdongIntercityRailwayAttributes } from '../components/svgs/lines/styles/guangdong-intercity-railway'; export enum LinePathType { @@ -65,6 +69,10 @@ export enum LineStyleType { LondonTubeTerminal = 'london-tube-terminal', LondonTubeInternalInt = 'london-tube-internal-int', LondonTube10MinWalk = 'london-tube-10-min-walk', + LondonRail = 'london-rail', + LondonSandwich = 'london-sandwich', + LondonLutonAirportDART = 'london-DART', + LondonIFSCloudCableCar = 'london-dangleway', GuangdongIntercityRailway = 'gd-intercity-rwy', } @@ -91,6 +99,10 @@ export interface ExternalLineStyleAttributes { [LineStyleType.LondonTubeTerminal]?: LondonTubeTerminalAttributes; [LineStyleType.LondonTubeInternalInt]?: LondonTubeInternalIntAttributes; [LineStyleType.LondonTube10MinWalk]?: LondonTube10MinWalkAttributes; + [LineStyleType.LondonRail]?: LondonRailAttributes; + [LineStyleType.LondonSandwich]?: LondonSandwichAttributes; + [LineStyleType.LondonLutonAirportDART]?: LondonLutonAirportDARTAttributes; + [LineStyleType.LondonIFSCloudCableCar]?: LondonIFSCloudCableCarAttributes; [LineStyleType.GuangdongIntercityRailway]?: GuangdongIntercityRailwayAttributes; } @@ -106,6 +118,10 @@ export const LineStylesWithColor = [ LineStyleType.JREastSingleColor, LineStyleType.JREastSingleColorPattern, LineStyleType.LRTSingleColor, + LineStyleType.GuangdongIntercityRailway, + LineStyleType.LondonRail, + LineStyleType.LondonSandwich, + LineStyleType.LondonLutonAirportDART, ]; /* ----- Below are core types for all lines, DO NOT TOUCH. ----- */ diff --git a/src/constants/nodes.ts b/src/constants/nodes.ts index f7ee4c29..240932a9 100644 --- a/src/constants/nodes.ts +++ b/src/constants/nodes.ts @@ -16,6 +16,7 @@ import { JREastLineBadgeAttributes } from '../components/svgs/nodes/jr-east-line import { QingdaoMetroNumLineBadgeAttributes } from '../components/svgs/nodes/qingdao-metro-num-line-badge'; import { MRTLineBadgeAttributes } from '../components/svgs/nodes/mrt-line-badge'; import { GuangdongIntercityRailwayLineBadgeAttributes } from '../components/svgs/nodes/guangdong-intercity-railway-line-badge'; +import { LondonArrowAttributes } from '../components/svgs/nodes/london-arrow'; import { FacilitiesAttributes } from '../components/svgs/nodes/facilities'; import { TextAttributes } from '../components/svgs/nodes/text'; import { I18nTextAttributes } from '../components/svgs/nodes/i18n-text'; @@ -39,6 +40,7 @@ export enum MiscNodeType { QingdaoMetroNumLineBadge = 'qingdao-metro-num-line-badge', MRTLineBadge = 'mrt-line-badge', GuangdongIntercityRailwayLineBadge = 'gd-intercity-rwy-line-badge', + LondonArrow = 'london-arrow', Facilities = 'facilities', Text = 'text', I18nText = 'i18n-text', @@ -63,6 +65,7 @@ export interface MiscNodeAttributes { [MiscNodeType.QingdaoMetroNumLineBadge]?: QingdaoMetroNumLineBadgeAttributes; [MiscNodeType.MRTLineBadge]?: MRTLineBadgeAttributes; [MiscNodeType.GuangdongIntercityRailwayLineBadge]?: GuangdongIntercityRailwayLineBadgeAttributes; + [MiscNodeType.LondonArrow]?: LondonArrowAttributes; [MiscNodeType.Facilities]?: FacilitiesAttributes; [MiscNodeType.Text]?: TextAttributes; [MiscNodeType.I18nText]?: I18nTextAttributes; diff --git a/src/constants/stations.ts b/src/constants/stations.ts index be3b4056..141feb46 100644 --- a/src/constants/stations.ts +++ b/src/constants/stations.ts @@ -24,6 +24,7 @@ import { TokyoMetroBasicStationAttributes } from '../components/svgs/stations/to import { TokyoMetroIntStationAttributes } from '../components/svgs/stations/tokyo-metro-int'; import { LondonTubeBasicStationAttributes } from '../components/svgs/stations/london-tube-basic'; import { LondonTubeIntStationAttributes } from '../components/svgs/stations/london-tube-int'; +import { LondonRiverServicesIntStationAttributes } from '../components/svgs/stations/london-river-services-interchange'; import { GuangdongIntercityRailwayStationAttributes } from '../components/svgs/stations/guangdong-intercity-railway'; export enum StationType { @@ -52,6 +53,7 @@ export enum StationType { TokyoMetroInt = 'tokyo-metro-int', LondonTubeBasic = 'london-tube-basic', LondonTubeInt = 'london-tube-int', + LondonRiverServicesInt = 'london-river-int', GuangdongIntercityRailway = 'gd-intercity-rwy', } @@ -81,6 +83,7 @@ export interface ExternalStationAttributes { [StationType.TokyoMetroInt]?: TokyoMetroIntStationAttributes; [StationType.LondonTubeBasic]?: LondonTubeBasicStationAttributes; [StationType.LondonTubeInt]?: LondonTubeIntStationAttributes; + [StationType.LondonRiverServicesInt]?: LondonRiverServicesIntStationAttributes; [StationType.GuangdongIntercityRailway]?: GuangdongIntercityRailwayStationAttributes; } diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json index f6fb0265..8352c3be 100644 --- a/src/i18n/translations/en.json +++ b/src/i18n/translations/en.json @@ -135,6 +135,13 @@ "guangdongIntercityRailwayLineBadge": { "displayName": "Guangdong Intercity Railway line badge" }, + "londonArrow": { + "displayName": "London arrow", + "type": "Type", + "continuation": "Continuation", + "sandwich": "Sandwich", + "tube": "Tube" + }, "master": { "displayName": "Master node", "type": "Master node type", @@ -339,6 +346,9 @@ "londonTubeInt": { "displayName": "London Tube interchange station" }, + "londonRiverServicesInt": { + "displayName": "London river services interchange station" + }, "guangdongIntercityRailway": { "displayName": "Guangdong Intercity Railway station" } @@ -439,6 +449,21 @@ "londonTubeTerminal": { "displayName": "London Tube terminal style" }, + "londonRail": { + "displayName": "London rail style", + "limitedService": "Limited service/Peak hours only", + "colorBackground": "Color background", + "colorForeground": "Color foreground" + }, + "londonSandwich": { + "displayName": "London sandwich style" + }, + "londonLutonAirportDART": { + "displayName": "London Luton Airport DART style" + }, + "londonIFSCloudCableCar": { + "displayName": "London IFS Cloud Cable Car style" + }, "guangdongIntercityRailway": { "displayName": "Guangdong Intercity Railway style" } @@ -552,7 +577,7 @@ "undo": "Undo.", "redo": "Redo." }, - "procedures":{ + "procedures": { "title": "Procedures", "translate": { "title": "Translate nodes' coordinates", diff --git a/src/i18n/translations/ja.json b/src/i18n/translations/ja.json index bec59ca3..9b436a86 100644 --- a/src/i18n/translations/ja.json +++ b/src/i18n/translations/ja.json @@ -126,8 +126,8 @@ "isTram": "LRT路線バッジです" }, "jrEastLineBadge": { - "displayName": "JR東日本路線番号徽章", - "crosshatchPatternFill": "網目模様で塗りつぶす" + "displayName": "JR東日本路線番号徽章", + "crosshatchPatternFill": "網目模様で塗りつぶす" }, "qingdaoMetroNumLineBadge": { "displayName": "青島地下鉄番号線徽章", @@ -137,6 +137,13 @@ "guangdongIntercityRailwayLineBadge": { "displayName": "広東省都市間鉄道線徽章" }, + "londonArrow": { + "displayName": "ロンドン矢印", + "type": "種類", + "continuation": "継続", + "sandwich": "サンドイッチ", + "tube": "地下鉄" + }, "master": { "displayName": "大師節点", "type": "大師節点種類", @@ -271,18 +278,18 @@ "displayName": "シンガポールMRT乗り換え駅" }, "jrEastBasic": { - "displayName": "JR東日本基本駅", - "nameOffset": "名前の補正値", - "textOneLine": "1行での名前", - "textVertical": "垂直の名前", - "important": "重要な駅", - "lines": "乗り換え線の補正値" + "displayName": "JR東日本基本駅", + "nameOffset": "名前の補正値", + "textOneLine": "1行での名前", + "textVertical": "垂直の名前", + "important": "重要な駅", + "lines": "乗り換え線の補正値" }, "jrEastImportant": { - "displayName": "JR東日本重要駅", - "textVertical": "垂直の名前", - "mostImportant": "最も重要な駅", - "minLength": "駅の最小長" + "displayName": "JR東日本重要駅", + "textVertical": "垂直の名前", + "mostImportant": "最も重要な駅", + "minLength": "駅の最小長" }, "foshanMetroBasic": { "displayName": "仏山地鐵基本車站", @@ -339,6 +346,9 @@ "londonTubeInt": { "displayName": "ロンドン地下鉄乗換駅" }, + "londonRiverServicesInt": { + "displayName": "ロンドン川サービス乗換駅" + }, "guangdongIntercityRailway": { "displayName": "広東省都市間鉄道駅" } @@ -439,6 +449,21 @@ "londonTubeTerminal": { "displayName": "ロンドン地下鉄終着風格" }, + "londonRail": { + "displayName": "ロンドン鉄道風格", + "limitedService": "限定サービス/ピーク時のみ", + "colorBackground": "背景色", + "colorForeground": "前景色" + }, + "londonSandwich": { + "displayName": "ロンドンサンドイッチ風格" + }, + "londonLutonAirportDART": { + "displayName": "ロンドンルートン空港DART風格" + }, + "londonIFSCloudCableCar": { + "displayName": "ロンドンIF雲索道風格" + }, "guangdongIntercityRailway": { "displayName": "広東省都市間鉄道風格" } diff --git a/src/i18n/translations/ko.json b/src/i18n/translations/ko.json index 8b07526c..932e2d0f 100644 --- a/src/i18n/translations/ko.json +++ b/src/i18n/translations/ko.json @@ -135,6 +135,13 @@ "guangdongIntercityRailwayLineBadge": { "displayName": "광동 시외 철도 노선 표지판" }, + "londonArrow": { + "displayName": "런던 화살표", + "type": "유형", + "continuation": "계속", + "sandwich": "샌드위치", + "tube": "튜브" + }, "master": { "displayName": "마스터 노드", "type": "마스터 노드 유형", @@ -338,6 +345,9 @@ "londonTubeInt": { "displayName": "런던 지하철 환승역" }, + "londonRiverServicesInt": { + "displayName": "런던 강 서비스 환승역" + }, "guangdongIntercityRailway": { "displayName": "광둥 시외 기차역" } @@ -438,6 +448,21 @@ "londonTubeTerminal": { "displayName": "런던 지하철 종착 스타일" }, + "londonRail": { + "displayName": "런던 철도 스타일", + "limitedService": "제한 서비스/혼잡 시간대만", + "colorBackground": "배경 색상", + "colorForeground": "전경 색상" + }, + "londonSandwich": { + "displayName": "런던 샌드위치 스타일" + }, + "londonLutonAirportDART": { + "displayName": "런던 루튼 공항 DART 스타일" + }, + "londonIFSCloudCableCar": { + "displayName": "런던 IFS 클라우드 케이블카 스타일" + }, "guangdongIntercityRailway": { "displayName": "광동성 도시간 철도 스타일" } diff --git a/src/i18n/translations/zh-Hans.json b/src/i18n/translations/zh-Hans.json index 89b726be..70269b2a 100644 --- a/src/i18n/translations/zh-Hans.json +++ b/src/i18n/translations/zh-Hans.json @@ -124,8 +124,8 @@ "isTram": "是LRT线路标识" }, "jrEastLineBadge": { - "displayName": "JR东日本线路标识", - "crosshatchPatternFill": "用网状图案填充" + "displayName": "JR东日本线路标识", + "crosshatchPatternFill": "用网状图案填充" }, "qingdaoMetroNumLineBadge": { "displayName": "青岛地铁数字线路标识", @@ -135,6 +135,13 @@ "guangdongIntercityRailwayLineBadge": { "displayName": "广东城际铁路线路标识" }, + "londonArrow": { + "displayName": "伦敦箭头", + "type": "类型", + "continuation": "延续", + "sandwich": "三明治", + "tube": "地铁" + }, "master": { "displayName": "大师节点", "type": "大师节点类型", @@ -338,6 +345,9 @@ "londonTubeInt": { "displayName": "伦敦地铁换乘车站" }, + "londonRiverServicesInt": { + "displayName": "伦敦河流服务换乘站" + }, "guangdongIntercityRailway": { "displayName": "广东城际铁路车站" } @@ -438,6 +448,21 @@ "londonTubeTerminal": { "displayName": "伦敦地铁终点站样式" }, + "londonRail": { + "displayName": "伦敦铁路样式", + "limitedService": "有限服务/仅限高峰时段", + "colorBackground": "背景颜色", + "colorForeground": "前景颜色" + }, + "londonSandwich": { + "displayName": "伦敦三明治样式" + }, + "londonLutonAirportDART": { + "displayName": "伦敦卢顿机场DART样式" + }, + "londonIFSCloudCableCar": { + "displayName": "伦敦IFS云缆车样式" + }, "guangdongIntercityRailway": { "displayName": "广东城际铁路样式" } diff --git a/src/i18n/translations/zh-Hant.json b/src/i18n/translations/zh-Hant.json index 3048e627..c4bedaf1 100644 --- a/src/i18n/translations/zh-Hant.json +++ b/src/i18n/translations/zh-Hant.json @@ -124,8 +124,8 @@ "isTram": "是LRT線路標識" }, "jrEastLineBadge": { - "displayName": "JR東日本線路標識", - "crosshatchPatternFill": "用網狀圖案填充" + "displayName": "JR東日本線路標識", + "crosshatchPatternFill": "用網狀圖案填充" }, "qingdaoMetroNumLineBadge": { "displayName": "青島地鐵數位線路標識", @@ -135,6 +135,13 @@ "guangdongIntercityRailwayLineBadge": { "displayName": "廣東城際鐵路線標識" }, + "londonArrow": { + "displayName": "倫敦箭頭", + "type": "類型", + "continuation": "延續", + "sandwich": "三明治", + "tube": "地鐵" + }, "master": { "displayName": "大師節點", "type": "大師節點類型", @@ -268,18 +275,18 @@ "displayName": "新加坡MRT換乘車站" }, "jrEastBasic": { - "displayName": "JR東日本基本車站", - "nameOffset": "名稱偏移", - "textOneLine": "名稱在一行中", - "textVertical": "垂直名稱", - "important": "重要車站", - "lines": "轉乘線偏移" + "displayName": "JR東日本基本車站", + "nameOffset": "名稱偏移", + "textOneLine": "名稱在一行中", + "textVertical": "垂直名稱", + "important": "重要車站", + "lines": "轉乘線偏移" }, "jrEastImportant": { - "displayName": "JR東日本重要車站", - "textVertical": "垂直名稱", - "mostImportant": "最重要車站", - "minLength": "車站的最小長度" + "displayName": "JR東日本重要車站", + "textVertical": "垂直名稱", + "mostImportant": "最重要車站", + "minLength": "車站的最小長度" }, "foshanMetroBasic": { "displayName": "佛山地鐵基本車站", @@ -338,6 +345,9 @@ "londonTubeInt": { "displayName": "倫敦地鐵換乘車站" }, + "londonRiverServicesInt": { + "displayName": "倫敦河流服務換乘站" + }, "guangdongIntercityRailway": { "displayName": "廣東城際鐵路車站" } @@ -438,6 +448,21 @@ "londonTubeTerminal": { "displayName": "倫敦地鐵終點站樣式" }, + "londonRail": { + "displayName": "倫敦鐵路樣式", + "limitedService": "有限服務/只限繁忙時段", + "colorBackground": "背景顏色", + "colorForeground": "前景顏色" + }, + "londonSandwich": { + "displayName": "倫敦三明治樣式" + }, + "londonLutonAirportDART": { + "displayName": "倫敦盧頓機場DART樣式" + }, + "londonIFSCloudCableCar": { + "displayName": "倫敦IFS雲纜車樣式" + }, "guangdongIntercityRailway": { "displayName": "廣東城際鐵路樣式" }