Skip to content

Commit a000b47

Browse files
authored
#771 Add Changsha Metro stations (#1248)
1 parent 0d0ba26 commit a000b47

File tree

13 files changed

+497
-1
lines changed

13 files changed

+497
-1
lines changed

src/components/panels/details/color-field.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const dynamicColorInjectionStationKeys = [
3434
StationType.ChongqingRTInt2021,
3535
StationType.ChengduRTBasic,
3636
StationType.WuhanRTBasic,
37+
StationType.CsmetroBasic,
3738
] as const;
3839
const dynamicColorInjectionMiscNodeKeys = [
3940
MiscNodeType.Text,
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import { RmgFields, RmgFieldsField } from '@railmapgen/rmg-components';
2+
import { MonoColour } from '@railmapgen/rmg-palette-resources';
3+
import React from 'react';
4+
import { useTranslation } from 'react-i18next';
5+
import { AttrsProps, CanvasType, CategoriesType, CityCode } from '../../../constants/constants';
6+
import {
7+
defaultStationAttributes,
8+
NameOffsetX,
9+
NameOffsetY,
10+
Station,
11+
StationAttributes,
12+
StationComponentProps,
13+
StationType,
14+
} from '../../../constants/stations';
15+
import { getLangStyle, TextLanguage } from '../../../util/fonts';
16+
import { MultilineText, NAME_DY } from '../common/multiline-text';
17+
import { ColorAttribute, ColorField } from '../../panels/details/color-field';
18+
19+
const NAME_DY_CS_BASIC = {
20+
top: { lineHeight: 6, offset: 14 },
21+
middle: { lineHeight: 0, offset: 0 },
22+
bottom: { lineHeight: 12.67, offset: 9 },
23+
};
24+
25+
const CsmetroBasicStation = (props: StationComponentProps) => {
26+
const { id, x, y, attrs, handlePointerDown, handlePointerMove, handlePointerUp } = props;
27+
const {
28+
names = defaultStationAttributes.names,
29+
nameOffsetX = defaultCsmetroBasicStationAttributes.nameOffsetX,
30+
nameOffsetY = defaultCsmetroBasicStationAttributes.nameOffsetY,
31+
color = defaultCsmetroBasicStationAttributes.color,
32+
} = attrs[StationType.CsmetroBasic] ?? defaultCsmetroBasicStationAttributes;
33+
34+
const onPointerDown = React.useCallback(
35+
(e: React.PointerEvent<SVGElement>) => handlePointerDown(id, e),
36+
[id, handlePointerDown]
37+
);
38+
const onPointerMove = React.useCallback(
39+
(e: React.PointerEvent<SVGElement>) => handlePointerMove(id, e),
40+
[id, handlePointerMove]
41+
);
42+
const onPointerUp = React.useCallback(
43+
(e: React.PointerEvent<SVGElement>) => handlePointerUp(id, e),
44+
[id, handlePointerUp]
45+
);
46+
47+
const textX = nameOffsetX === 'left' ? -10 : nameOffsetX === 'right' ? 10 : 0;
48+
const textY =
49+
(names[NAME_DY[nameOffsetY].namesPos].split('\n').length * NAME_DY_CS_BASIC[nameOffsetY].lineHeight +
50+
NAME_DY_CS_BASIC[nameOffsetY].offset) *
51+
NAME_DY[nameOffsetY].polarity +
52+
2;
53+
const textAnchor = nameOffsetX === 'left' ? 'end' : nameOffsetX === 'right' ? 'start' : 'middle';
54+
55+
return (
56+
<g id={id} transform={`translate(${x}, ${y})`}>
57+
<circle
58+
id={`stn_core_${id}`}
59+
r={7}
60+
stroke={color[2]}
61+
strokeWidth={2}
62+
fill="white"
63+
onPointerDown={onPointerDown}
64+
onPointerMove={onPointerMove}
65+
onPointerUp={onPointerUp}
66+
style={{ cursor: 'move' }}
67+
/>
68+
<g
69+
transform={`translate(${textX}, ${textY})`}
70+
textAnchor={textAnchor}
71+
className="rmp-name-outline"
72+
strokeWidth="1"
73+
>
74+
<MultilineText
75+
text={names[0].split('\n')}
76+
fontSize={12.67}
77+
lineHeight={12.67}
78+
grow="up"
79+
baseOffset={1}
80+
{...getLangStyle(TextLanguage.zh)}
81+
/>
82+
<MultilineText
83+
text={names[1].split('\n')}
84+
dx={nameOffsetX === 'right' ? 1.67 : 0}
85+
fontSize={6}
86+
lineHeight={6}
87+
grow="down"
88+
baseOffset={1.5}
89+
{...getLangStyle(TextLanguage.en)}
90+
/>
91+
</g>
92+
</g>
93+
);
94+
};
95+
96+
export interface CsmetroBasicStationAttributes extends StationAttributes, ColorAttribute {
97+
nameOffsetX: NameOffsetX;
98+
nameOffsetY: NameOffsetY;
99+
}
100+
101+
const defaultCsmetroBasicStationAttributes: CsmetroBasicStationAttributes = {
102+
...defaultStationAttributes,
103+
nameOffsetX: 'right',
104+
nameOffsetY: 'top',
105+
color: [CityCode.Changsha, 'cs1', '#DA291C', MonoColour.white],
106+
};
107+
108+
const csmetroBasicAttrsComponent = (props: AttrsProps<CsmetroBasicStationAttributes>) => {
109+
const { id, attrs, handleAttrsUpdate } = props;
110+
const { t } = useTranslation();
111+
112+
const fields: RmgFieldsField[] = [
113+
{
114+
type: 'textarea',
115+
label: t('panel.details.stations.common.nameZh'),
116+
value: attrs.names[0],
117+
onChange: val => {
118+
attrs.names[0] = val;
119+
handleAttrsUpdate(id, attrs);
120+
},
121+
minW: 'full',
122+
},
123+
{
124+
type: 'textarea',
125+
label: t('panel.details.stations.common.nameEn'),
126+
value: attrs.names.at(1) ?? defaultCsmetroBasicStationAttributes.names[1],
127+
onChange: val => {
128+
attrs.names[1] = val;
129+
handleAttrsUpdate(id, attrs);
130+
},
131+
minW: 'full',
132+
},
133+
{
134+
type: 'select',
135+
label: t('panel.details.stations.common.nameOffsetX'),
136+
value: attrs.nameOffsetX,
137+
options: {
138+
left: t('panel.details.stations.common.left'),
139+
middle: t('panel.details.stations.common.middle'),
140+
right: t('panel.details.stations.common.right'),
141+
},
142+
disabledOptions: attrs.nameOffsetY === 'middle' ? ['middle'] : [],
143+
onChange: val => {
144+
attrs.nameOffsetX = val as NameOffsetX;
145+
handleAttrsUpdate(id, attrs);
146+
},
147+
minW: 'full',
148+
},
149+
{
150+
type: 'select',
151+
label: t('panel.details.stations.common.nameOffsetY'),
152+
value: attrs.nameOffsetY,
153+
options: {
154+
top: t('panel.details.stations.common.top'),
155+
middle: t('panel.details.stations.common.middle'),
156+
bottom: t('panel.details.stations.common.bottom'),
157+
},
158+
disabledOptions: attrs.nameOffsetX === 'middle' ? ['middle'] : [],
159+
onChange: val => {
160+
attrs.nameOffsetY = val as NameOffsetY;
161+
handleAttrsUpdate(id, attrs);
162+
},
163+
minW: 'full',
164+
},
165+
{
166+
type: 'custom',
167+
label: t('color'),
168+
component: (
169+
<ColorField type={StationType.CsmetroBasic} defaultTheme={defaultCsmetroBasicStationAttributes.color} />
170+
),
171+
},
172+
];
173+
174+
return <RmgFields fields={fields} />;
175+
};
176+
177+
const csmetroBasicStationIcon = (
178+
<svg viewBox="0 0 24 24" height="40" width="40" focusable={false}>
179+
<circle cx="12" cy="12" r="7" stroke="currentColor" strokeWidth="2" fill="none" />
180+
</svg>
181+
);
182+
183+
const csmetroBasicStation: Station<CsmetroBasicStationAttributes> = {
184+
component: CsmetroBasicStation,
185+
icon: csmetroBasicStationIcon,
186+
defaultAttrs: defaultCsmetroBasicStationAttributes,
187+
attrsComponent: csmetroBasicAttrsComponent,
188+
metadata: {
189+
displayName: 'panel.details.stations.csmetroBasic.displayName',
190+
cities: [CityCode.Changsha],
191+
canvas: [CanvasType.RailMap],
192+
categories: [CategoriesType.Metro],
193+
tags: [],
194+
},
195+
};
196+
197+
export default csmetroBasicStation;

0 commit comments

Comments
 (0)