const courtStructure = [
{ class: 'legend-rect', shape: 'rect', x: 0, y: TLP 38, width: 50, height: 8, fill: headerStyle.backgroundColor }, // rectangle behind legend
{ class: 'backboard', shape: 'line', x1: 22, x2: 28, y1: 3.75, y2: 3.75, stroke: hoopColor, opacity: hoopOpacity, strokeWidth: 0.5 }, // backboard
{ class: 'rim', shape: 'circle', r: 0.95, cx: 25, cy: 5.1, opacity: hoopOpacity, fill: hoopColor }, // the circle part of rim
{ class: 'back-iron', shape: 'rect', x: 24.625, y: 3.95, width: 0.75, height: 0.5, stroke: 0, opacity: hoopOpacity, fill: hoopColor } // back iron on rim
];
<rect
className='legend-rect'
x={0}
y={TLP 38}
width={50}
height={8}
fill={headerStyle.backgroundColor}
/>
...
We have the courtStructure
array of objects, and we would like to .map()
over the array and create the SVG elements described. Example for the first rect
is shown above. The keys in each object within courtStructure
should be created as a field on the SVG element. The shape
determines the element type.
The hardest part of achieving this seems to be:
- creating the correct element (rect, line, circle, etc.)
- handling the fact that different objects have different keys / parameters for the SVG
Is this possible to do?
CodePudding user response:
For each object extract the properties that need "name mapping", e.g. shape
, class
, etc. The remaining properties are kept in a single object and passed to React as spread attributes.
You can then create the component via dynamic tags or directly via React.createElement
:
const components = courtStructure.map(
({shape: Shape, class: className, ...props}) => {
return <Shape className={className} {...props} />
// or
return React.createElement(Shape, {className, ...props})
}
)
Also see
CodePudding user response:
I would probably change how the object structure is set up to separate the shape from the actual attributes, and make the keys of the attributes match the attributes you pass to the element like this:
const courtStructure = [
{
shape: 'rect',
attributes: {
className: 'legend-rect',
x: 0,
y: TLP 38,
width: 50,
height: 8,
fill: headerStyle.backgroundColor
}
}, // rectangle behind legend
...
];
This way you can map through the array and make a switch statement for the shape to decide what element to render, and destructure the attributes on the svg element. Something like this:
{courtStructure.map((element) => {
switch(element.shape) {
case 'rect':
return (
<rect {...element.attributes} />
);
case 'line':
return (
<line {...element.attributes} />
);
case 'circle':
return (
<circle {...element.attributes} />
);
}
})}
You could also obviously refactor this logic to its own Shape
component to make it cleaner!