• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geosolutions-it / MapStore2 / 20999865728

14 Jan 2026 03:33PM UTC coverage: 76.732% (-0.02%) from 76.751%
20999865728

push

github

web-flow
Fix #11814 Interactive legend is not showing the correct icons (#11823) (#11854)

(cherry picked from commit a3568c86d)

Co-authored-by: Sovas Tiwari <40485930+subashtiwari1010@users.noreply.github.com>

32202 of 50068 branches covered (64.32%)

77 of 108 new or added lines in 3 files covered. (71.3%)

2 existing lines in 2 files now uncovered.

40045 of 52188 relevant lines covered (76.73%)

38.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.0
/web/client/components/styleeditor/GraphicPattern/GraphicPattern.jsx
1
/*
2
 * Copyright 2025, GeoSolutions Sas.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under the BSD-style license found in the
6
 * LICENSE file in the root directory of this source tree.
7
 */
8

9
import React from 'react';
10

11
const MARKS_TYPES = {
1✔
12
    line: ({ mark }) => {
13
        return (
4✔
14
            <line
15
                x1={mark.x1}
16
                y1={mark.y1}
17
                x2={mark.x2}
18
                y2={mark.y2}
19
                stroke={mark.stroke}
20
                strokeWidth={mark["stroke-width"]}
21
                strokeOpacity={mark["stroke-opacity"]}
22
                strokeLinecap={mark["stroke-linecap"]}
23
                strokeLinejoin={mark["stroke-linejoin"]}
24
                opacity={mark.opacity}
25
            />
26
        );
27
    },
28
    polygon: ({ mark }) => {
NEW
29
        return (
×
30
            <polygon
31
                points={mark.points}
32
                stroke={mark.stroke}
33
                strokeWidth={mark["stroke-width"]}
34
                strokeOpacity={mark["stroke-opacity"]}
35
                fill={mark.fill}
36
                fillOpacity={mark["fill-opacity"]}
37
                opacity={mark.opacity}
38
            />
39
        );
40
    },
41
    circle: ({ mark }) => {
42
        return (
2✔
43
            <circle
44
                cx={mark.cx}
45
                cy={mark.cy}
46
                r={mark.r}
47
                fill={mark.fill}
48
                fillOpacity={mark["fill-opacity"]}
49
                stroke={mark.stroke}
50
                strokeWidth={mark["stroke-width"]}
51
                strokeOpacity={mark["stroke-opacity"]}
52
            />
53
        );
54
    },
55
    polyline: ({ mark }) => {
NEW
56
        return (
×
57
            <polyline
58
                points={mark.points}
59
                stroke={mark.stroke}
60
                strokeWidth={mark["stroke-width"]}
61
                strokeOpacity={mark["stroke-opacity"]}
62
                opacity={mark.opacity}
63
                fill={mark.fill}
64
                fillOpacity={mark["fill-opacity"]}
65
            />
66
        );
67
    }
68
};
69

70
const GraphicPattern = ({ id, symbolizer, type }) => {
1✔
71
    const graphic = type === 'line' ? symbolizer["graphic-stroke"] : symbolizer["graphic-fill"];
7✔
72
    const mark = graphic?.graphics?.[0];
7✔
73

74
    if (!graphic || !mark) return null;
7✔
75

76
    const size = Number(graphic.size || 10);
6!
77
    const rotation = Number(graphic.rotation || 0);
6✔
78
    const opacity = Number(graphic.opacity ?? 1);
6!
79

80
    const margin =
81
        symbolizer["vendor-options"]?.["graphic-margin"]
6✔
82
            ?.split(" ")
83
            .map(Number) || [0, 0];
84

85
    const patternWidth = size + margin[0];
6✔
86
    const patternHeight = size + margin[1];
6✔
87

88
    const getMarkTypes = () => {
6✔
89
        switch (mark.mark) {
6!
90
        case "shape://horline":
91
            return MARKS_TYPES.line({
2✔
92
                mark: {
93
                    ...mark,
94
                    x1: 0,
95
                    y1: size / 2,
96
                    x2: size,
97
                    y2: size / 2,
98
                    opacity
99
                }
100
            });
101
        case "line":
102
        case "shape://vertline":
103
            return MARKS_TYPES.line({
1✔
104
                mark: {
105
                    ...mark,
106
                    x1: size / 2,
107
                    y1: 0,
108
                    x2: size / 2,
109
                    y2: size,
110
                    opacity
111
                }
112
            });
113
        case "shape://slash":
114
            return MARKS_TYPES.line({
1✔
115
                mark: {
116
                    ...mark,
117
                    x1: 0,
118
                    y1: size,
119
                    x2: size,
120
                    y2: 0,
121
                    opacity
122
                }
123
            });
124
        case "shape://backslash":
NEW
125
            return MARKS_TYPES.line({
×
126
                mark: {
127
                    ...mark,
128
                    x1: 0,
129
                    y1: 0,
130
                    x2: size,
131
                    y2: size,
132
                    opacity
133
                }
134
            });
135
        case "circle":
136
            return MARKS_TYPES.circle({
2✔
137
                mark: {
138
                    ...mark,
139
                    cx: size / 2,
140
                    cy: size / 2,
141
                    r: size / 4
142
                }
143
            });
144
        case "triangle":
NEW
145
            return MARKS_TYPES.polygon({ mark: { ...mark, points: `${size / 2},0 0,${size} ${size},${size}` } });
×
146
        case "star":
NEW
147
            const cx = size / 2;
×
NEW
148
            const cy = size / 2;
×
NEW
149
            const outerR = size / 2;
×
NEW
150
            const innerR = size / 2.5;
×
151

NEW
152
            const points = [];
×
NEW
153
            for (let i = 0; i < 10; i++) {
×
NEW
154
                const angle = (Math.PI / 5) * i - Math.PI / 2;
×
NEW
155
                const r = i % 2 === 0 ? outerR : innerR;
×
NEW
156
                points.push(
×
157
                    `${cx + r * Math.cos(angle)},${cy + r * Math.sin(angle)}`
158
                );
159
            }
NEW
160
            return MARKS_TYPES.polygon({ mark: { ...mark, points, fill: mark.fill ?? "#000" } });
×
161
        case "cross":
NEW
162
            return MARKS_TYPES.polygon({ mark: { ...mark, points: `${size / 2},0 ${size / 2},${size} ${size},${size / 2}` } });
×
163
        case "shape://dot":
NEW
164
            return MARKS_TYPES.circle({
×
165
                mark: {
166
                    ...mark,
167
                    cx: size / 2,
168
                    cy: size / 2,
169
                    r: size / 8,
170
                    opacity
171
                }
172
            });
173
        case "shape://plus":
NEW
174
            return <>
×
175
                {MARKS_TYPES.line({
176
                    mark: {
177
                        ...mark,
178
                        x1: 0,
179
                        y1: size / 2,
180
                        x2: size,
181
                        y2: size / 2,
182
                        opacity
183
                    }
184
                })}
185
                {MARKS_TYPES.line({
186
                    mark: {
187
                        ...mark,
188
                        x1: size / 2,
189
                        y1: 0,
190
                        x2: size / 2,
191
                        y2: size,
192
                        opacity
193
                    }
194
                })}
195
            </>;
196
        case "shape://times":
NEW
197
            return <>
×
198
                {MARKS_TYPES.line({
199
                    mark: {
200
                        ...mark,
201
                        x1: 0,
202
                        y1: size,
203
                        x2: size,
204
                        y2: 0,
205
                        opacity
206
                    }
207
                })}
208
                {MARKS_TYPES.line({
209
                    mark: {
210
                        ...mark,
211
                        x1: 0,
212
                        y1: size,
213
                        x2: size,
214
                        y2: 0,
215
                        opacity
216
                    }
217
                })}
218
            </>;
219
        case "shape://oarrow":
NEW
220
            return MARKS_TYPES.polyline({
×
221
                mark: {
222
                    ...mark,
223
                    points: `
224
                        0,0
225
                        ${size},${size / 2}
226
                        0,${size}
227
                    `,
228
                    fill: "none",
229
                    stroke: mark.stroke,
230
                    strokeWidth: mark["stroke-width"],
231
                    strokeOpacity: mark["stroke-opacity"],
232
                    opacity
233
                }
234
            });
235

236
        case "shape://carrow":
NEW
237
            return MARKS_TYPES.polygon({
×
238
                mark: {
239
                    ...mark,
240
                    points: `0,0 ${size},${size / 2} 0,${size}`,
241
                    opacity
242
                }
243
            });
244
        case "extshape://triangle":
NEW
245
            return MARKS_TYPES.polygon({ mark: { ...mark, points: `${size / 2},0 0,${size} ${size},${size}`, opacity, fill: mark.fill ?? "none" } });
×
246
        case "extshape://emicircle":
NEW
247
            const rx = size / 2;
×
NEW
248
            const ry = size / 4;
×
NEW
249
            return (
×
250
                <path
251
                    d={`M 0,${ry * 2} A ${rx} ${ry} 0 0 1 ${rx * 2},${ry * 2} L ${rx * 2},${ry * 2} Z`}
252
                    fill={mark.fill ?? "none"}
×
253
                    stroke={mark.stroke}
254
                    strokeWidth={mark["stroke-width"]}
255
                    opacity={mark.opacity}
256
                />
257
            );
258
        case "extshape://triangleemicircle": {
NEW
259
            const triangleHeight = size / 2;
×
NEW
260
            const semicircleRadius = size / 4;
×
NEW
261
            return (
×
262
                <>
263
                    {MARKS_TYPES.polygon({
264
                        mark: {
265
                            ...mark,
266
                            points: `
267
                                    ${size / 2},0
268
                                    0,${triangleHeight}
269
                                    ${size},${triangleHeight}
270
                                `,
271
                            fill: mark.fill ?? "none",
×
272
                            opacity
273
                        }
274
                    })}
275
                    <path
276
                        d={`
277
                                M ${size / 2 - semicircleRadius},${triangleHeight} 
278
                                A ${semicircleRadius} ${semicircleRadius} 0 0 0 ${size / 2 + semicircleRadius},${triangleHeight} 
279
                                L ${size / 2 + semicircleRadius},${triangleHeight + semicircleRadius} 
280
                                L ${size / 2 - semicircleRadius},${triangleHeight + semicircleRadius} 
281
                                Z
282
                            `}
283
                        fill={mark.fill ?? "none"}
×
284
                        stroke={mark.stroke}
285
                        strokeWidth={mark["stroke-width"] || 1}
×
286
                        strokeOpacity={mark["stroke-opacity"]}
287
                        opacity={opacity}
288
                    />
289
                </>
290
            );
291
        }
292
        case "extshape://narrow":
NEW
293
            return MARKS_TYPES.polygon({
×
294
                mark: {
295
                    ...mark,
296
                    points: `
297
                            ${size / 2},0
298
                            0,${size}
299
                            ${size},${size}
300
                        `,
301
                    fill: mark.fill ?? "none",
×
302
                    opacity
303
                }
304
            });
305
        case "extshape://sarrow":
NEW
306
            return MARKS_TYPES.polygon({
×
307
                mark: {
308
                    ...mark,
309
                    points: `
310
                                0,0
311
                                ${size},0
312
                                ${size / 2},${size}
313
                            `,
314
                    fill: mark.fill ?? "none",
×
315
                    opacity
316
                }
317
            });
318
        case "square":
319
        default:
NEW
320
            return MARKS_TYPES.polygon({
×
321
                mark: {
322
                    ...mark,
323
                    points: `0,0 ${size},0 ${size},${size} 0,${size}`,
324
                    fill: mark.fill ?? "none",
×
325
                    opacity
326
                }
327
            });
328
        }
329
    };
330

331
    return (
6✔
332
        <defs>
333
            <pattern
334
                id={id}
335
                patternUnits="userSpaceOnUse"
336
                width={patternWidth}
337
                height={patternHeight}
338
            >
339
                <g
340
                    transform={`
341
                        rotate(${rotation}
342
                        ${patternWidth / 2}
343
                        ${patternHeight / 2})
344
                    `}
345
                    opacity={opacity}
346
                >
347
                    {getMarkTypes()}
348
                </g>
349
            </pattern>
350
        </defs>
351
    );
352
};
353

354
export default GraphicPattern;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc