Skip to content

Commit d5dce5d

Browse files
authored
#665 Chongqing Rail Transit stations (#978)
1 parent 52ce499 commit d5dce5d

File tree

11 files changed

+563
-1
lines changed

11 files changed

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

0 commit comments

Comments
 (0)