Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/svg-canvas-graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ const SvgCanvas = () => {
<>
<SvgLayer
elements={elements}
selected={selected}
handlePointerDown={handlePointerDown}
handlePointerMove={handlePointerMove}
handlePointerUp={handlePointerUp}
Expand Down
83 changes: 71 additions & 12 deletions src/components/svg-layer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { LineId, MiscNodeId, StnId } from '../constants/constants';
import { Id, LineId, MiscNodeId, StnId } from '../constants/constants';
import { ExternalLineStyleAttributes, LineStyleComponentProps } from '../constants/lines';
import { MiscNodeType } from '../constants/nodes';
import { StationType } from '../constants/stations';
Expand All @@ -11,6 +11,7 @@ import { default as allStations } from './svgs/stations/stations';

interface SvgLayerProps {
elements: Element[];
selected: Set<Id>;
handlePointerDown: (node: StnId | MiscNodeId, e: React.PointerEvent<SVGElement>) => void;
handlePointerMove: (node: StnId | MiscNodeId, e: React.PointerEvent<SVGElement>) => void;
handlePointerUp: (node: StnId | MiscNodeId, e: React.PointerEvent<SVGElement>) => void;
Expand All @@ -24,7 +25,8 @@ type StyleComponent = React.FC<

const SvgLayer = React.memo(
(props: SvgLayerProps) => {
const { elements, handlePointerDown, handlePointerMove, handlePointerUp, handleEdgePointerDown } = props;
const { elements, selected, handlePointerDown, handlePointerMove, handlePointerUp, handleEdgePointerDown } =
props;

const layers = Object.fromEntries(
Array.from({ length: 21 }, (_, i) => [
Expand All @@ -42,7 +44,8 @@ const SvgLayer = React.memo(

const PreStyleComponent = lineStyles[style]?.preComponent as StyleComponent | undefined;
if (PreStyleComponent) {
layers[element.line!.attr.zIndex].pre.push(
const isSelected = selected.has(element.id);
const preComponent = (
<PreStyleComponent
key={`${element.id}.pre`}
id={element.id as LineId}
Expand All @@ -53,10 +56,16 @@ const SvgLayer = React.memo(
handlePointerDown={handleEdgePointerDown}
/>
);
layers[element.line!.attr.zIndex].pre.push(
<g key={`${element.id}.pre-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{preComponent}
</g>
);
}

const StyleComponent = (lineStyles[style]?.component ?? UnknownLineStyle) as StyleComponent;
layers[element.line!.attr.zIndex].main.push(
const isSelected = selected.has(element.id);
const component = (
<StyleComponent
key={element.id}
id={element.id as LineId}
Expand All @@ -68,9 +77,16 @@ const SvgLayer = React.memo(
/>
);

layers[element.line!.attr.zIndex].main.push(
<g key={`${element.id}-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{component}
</g>
);

const PostStyleComponent = lineStyles[style]?.postComponent as StyleComponent | undefined;
if (PostStyleComponent) {
layers[element.line!.attr.zIndex].post.push(
const isSelected = selected.has(element.id);
const postComponent = (
<PostStyleComponent
key={`${element.id}.post`}
id={element.id as LineId}
Expand All @@ -81,14 +97,20 @@ const SvgLayer = React.memo(
handlePointerDown={handleEdgePointerDown}
/>
);
layers[element.line!.attr.zIndex].post.push(
<g key={`${element.id}.post-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{postComponent}
</g>
);
}
} else if (element.type === 'station') {
const attr = element.station!;
const type = attr.type as StationType;

const PreStationComponent = allStations[type]?.preComponent;
if (PreStationComponent) {
layers[element.station!.zIndex].pre.push(
const isSelected = selected.has(element.id);
const preComponent = (
<PreStationComponent
key={`${element.id}.pre`}
id={element.id as StnId}
Expand All @@ -100,10 +122,16 @@ const SvgLayer = React.memo(
handlePointerUp={handlePointerUp}
/>
);
layers[element.station!.zIndex].pre.push(
<g key={`${element.id}.pre-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{preComponent}
</g>
);
}

const StationComponent = allStations[type]?.component ?? UnknownNode;
layers[element.station!.zIndex].main.push(
const isSelected = selected.has(element.id);
const component = (
<StationComponent
key={element.id}
id={element.id as StnId}
Expand All @@ -116,9 +144,16 @@ const SvgLayer = React.memo(
/>
);

layers[element.station!.zIndex].main.push(
<g key={`${element.id}-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{component}
</g>
);

const PostStationComponent = allStations[type]?.postComponent;
if (PostStationComponent) {
layers[element.station!.zIndex].post.push(
const isSelected = selected.has(element.id);
const postComponent = (
<PostStationComponent
key={`${element.id}.post`}
id={element.id as StnId}
Expand All @@ -130,14 +165,20 @@ const SvgLayer = React.memo(
handlePointerUp={handlePointerUp}
/>
);
layers[element.station!.zIndex].post.push(
<g key={`${element.id}.post-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{postComponent}
</g>
);
}
} else if (element.type === 'misc-node') {
const attr = element.miscNode!;
const type = attr.type as MiscNodeType;

const PreMiscNodeComponent = miscNodes[type]?.preComponent;
if (PreMiscNodeComponent) {
layers[element.miscNode!.zIndex].pre.push(
const isSelected = selected.has(element.id);
const preComponent = (
<PreMiscNodeComponent
key={`${element.id}.pre`}
id={element.id as MiscNodeId}
Expand All @@ -150,10 +191,16 @@ const SvgLayer = React.memo(
handlePointerUp={handlePointerUp}
/>
);
layers[element.miscNode!.zIndex].pre.push(
<g key={`${element.id}.pre-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{preComponent}
</g>
);
}

const MiscNodeComponent = miscNodes[type]?.component ?? UnknownNode;
layers[element.miscNode!.zIndex].main.push(
const isSelected = selected.has(element.id);
const component = (
<MiscNodeComponent
key={element.id}
id={element.id as MiscNodeId}
Expand All @@ -167,9 +214,16 @@ const SvgLayer = React.memo(
/>
);

layers[element.miscNode!.zIndex].main.push(
<g key={`${element.id}-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{component}
</g>
);

const PostMiscNodeComponent = miscNodes[type]?.postComponent;
if (PostMiscNodeComponent) {
layers[element.miscNode!.zIndex].post.push(
const isSelected = selected.has(element.id);
const postComponent = (
<PostMiscNodeComponent
key={`${element.id}.post`}
id={element.id as MiscNodeId}
Expand All @@ -182,6 +236,11 @@ const SvgLayer = React.memo(
handlePointerUp={handlePointerUp}
/>
);
layers[element.miscNode!.zIndex].post.push(
<g key={`${element.id}.post-glow`} filter={isSelected ? 'url(#selected-glow)' : undefined}>
{postComponent}
</g>
);
}
}
}
Expand All @@ -192,7 +251,7 @@ const SvgLayer = React.memo(

return jsxElements;
},
(prevProps, nextProps) => prevProps.elements === nextProps.elements
(prevProps, nextProps) => prevProps.elements === nextProps.elements && prevProps.selected === nextProps.selected
);

export default SvgLayer;
12 changes: 12 additions & 0 deletions src/components/svg-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,18 @@ const SvgWrapper = () => {
<rect x="0" y="0" width="2.5" height="2.5" fill="black" fillOpacity="50%" />
<rect x="2.5" y="2.5" width="2.5" height="2.5" fill="black" fillOpacity="50%" />
</pattern>
<filter id="selected-glow" x="-50%" y="-50%" width="200%" height="200%">
<feColorMatrix values="1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="yellowGlow" />
<feGaussianBlur in="yellowGlow" stdDeviation="1" result="blur1" />
<feGaussianBlur in="yellowGlow" stdDeviation="2" result="blur2">
<animate attributeName="stdDeviation" values="1;3;1" dur="1s" repeatCount="indefinite" />
</feGaussianBlur>
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
{gridLines && (
<GridLines
Expand Down