@mapcreator/sdk 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +29 -0
  2. package/dist/{esm/HighlightManager.d.ts → HighlightManager.d.ts} +2 -2
  3. package/dist/{esm/MCMap.d.ts → MCMap.d.ts} +1 -1
  4. package/dist/{esm/PopupManager.d.ts → PopupManager.d.ts} +4 -4
  5. package/dist/{esm/Registry.d.ts → Registry.d.ts} +3 -3
  6. package/dist/{esm/adornments → adornments}/categoricalLegend.d.ts +1 -1
  7. package/dist/{esm/adornments → adornments}/connectedLegend.d.ts +2 -2
  8. package/dist/{esm/adornments → adornments}/customAdornment.d.ts +1 -1
  9. package/dist/{esm/adornments → adornments}/heading.d.ts +1 -1
  10. package/dist/adornments/insetMap.d.ts +3 -0
  11. package/dist/{esm/adornments → adornments}/manualLegend.d.ts +1 -1
  12. package/dist/adornments/northArrow.d.ts +3 -0
  13. package/dist/adornments/scalebar.d.ts +3 -0
  14. package/dist/{esm/constants → constants}/index.d.ts +2 -2
  15. package/dist/{esm/controls → controls}/fullscreenControls.d.ts +1 -1
  16. package/dist/{esm/controls → controls}/geocoderControl.d.ts +1 -1
  17. package/dist/{esm/controls → controls}/geolocationControls.d.ts +1 -1
  18. package/dist/controls/refreshMapControls.d.ts +3 -0
  19. package/dist/controls/webControls.d.ts +4 -0
  20. package/dist/{esm/controls → controls}/zoomControls.d.ts +1 -1
  21. package/dist/index.d.ts +3 -0
  22. package/dist/locales/da_DK/strings.json.d.ts +10 -0
  23. package/dist/locales/de_DE/strings.json.d.ts +10 -0
  24. package/dist/locales/en_GB/strings.json.d.ts +10 -0
  25. package/dist/locales/es_ES/strings.json.d.ts +10 -0
  26. package/dist/locales/fr_FR/strings.json.d.ts +10 -0
  27. package/dist/locales/it_IT/strings.json.d.ts +10 -0
  28. package/dist/locales/nl_NL/strings.json.d.ts +10 -0
  29. package/dist/mapcreator-sdk.js +39590 -0
  30. package/dist/models/area.d.ts +5 -0
  31. package/dist/models/circle.d.ts +5 -0
  32. package/dist/models/dot.d.ts +3 -0
  33. package/dist/models/line.d.ts +4 -0
  34. package/dist/models/marker.d.ts +5 -0
  35. package/dist/models/polygon.d.ts +5 -0
  36. package/dist/{esm/renderAdornments.d.ts → renderAdornments.d.ts} +3 -3
  37. package/dist/{esm/types → types}/index.d.ts +1 -1
  38. package/dist/{esm/types → types}/mapstyle.d.ts +2 -6
  39. package/dist/{esm/utils → utils}/choropleth.d.ts +3 -3
  40. package/dist/{esm/utils → utils}/geolocation.d.ts +1 -1
  41. package/dist/{esm/utils → utils}/graphhopper.d.ts +1 -1
  42. package/dist/{esm/utils → utils}/helpers.d.ts +2 -2
  43. package/dist/{esm/utils → utils}/language.d.ts +1 -1
  44. package/dist/{esm/utils → utils}/models.d.ts +4 -4
  45. package/dist/{esm/utils → utils}/overlays.d.ts +1 -1
  46. package/dist/{esm/utils → utils}/svgHelpers.d.ts +3 -4
  47. package/dist/{esm/utils → utils}/template.d.ts +2 -2
  48. package/dist/{esm/utils → utils}/youtube.d.ts +1 -1
  49. package/package.json +8 -6
  50. package/dist/esm/HighlightManager.js +0 -203
  51. package/dist/esm/MCMap.js +0 -254
  52. package/dist/esm/PopupManager.js +0 -297
  53. package/dist/esm/Registry.js +0 -74
  54. package/dist/esm/adornments/categoricalLegend.js +0 -141
  55. package/dist/esm/adornments/connectedLegend.js +0 -393
  56. package/dist/esm/adornments/customAdornment.js +0 -29
  57. package/dist/esm/adornments/heading.js +0 -71
  58. package/dist/esm/adornments/insetMap.d.ts +0 -3
  59. package/dist/esm/adornments/insetMap.js +0 -351
  60. package/dist/esm/adornments/manualLegend.js +0 -15
  61. package/dist/esm/adornments/northArrow.d.ts +0 -3
  62. package/dist/esm/adornments/northArrow.js +0 -24
  63. package/dist/esm/adornments/scalebar.d.ts +0 -3
  64. package/dist/esm/adornments/scalebar.js +0 -176
  65. package/dist/esm/constants/index.js +0 -53
  66. package/dist/esm/controls/controls.js +0 -7
  67. package/dist/esm/controls/fullscreenControls.js +0 -29
  68. package/dist/esm/controls/geocoderControl.js +0 -202
  69. package/dist/esm/controls/geolocationControls.js +0 -65
  70. package/dist/esm/controls/refreshMapControls.d.ts +0 -3
  71. package/dist/esm/controls/refreshMapControls.js +0 -26
  72. package/dist/esm/controls/webControls.d.ts +0 -4
  73. package/dist/esm/controls/webControls.js +0 -40
  74. package/dist/esm/controls/zoomControls.js +0 -23
  75. package/dist/esm/i18n.js +0 -21
  76. package/dist/esm/index.d.ts +0 -5
  77. package/dist/esm/index.js +0 -5
  78. package/dist/esm/locales/da_DK/strings.json +0 -7
  79. package/dist/esm/locales/de_DE/strings.json +0 -7
  80. package/dist/esm/locales/en_GB/strings.json +0 -7
  81. package/dist/esm/locales/es_ES/strings.json +0 -7
  82. package/dist/esm/locales/fr_FR/strings.json +0 -7
  83. package/dist/esm/locales/it_IT/strings.json +0 -7
  84. package/dist/esm/locales/nl_NL/strings.json +0 -7
  85. package/dist/esm/models/area.d.ts +0 -5
  86. package/dist/esm/models/area.js +0 -165
  87. package/dist/esm/models/circle.d.ts +0 -5
  88. package/dist/esm/models/circle.js +0 -110
  89. package/dist/esm/models/dot.d.ts +0 -3
  90. package/dist/esm/models/dot.js +0 -42
  91. package/dist/esm/models/line.d.ts +0 -4
  92. package/dist/esm/models/line.js +0 -117
  93. package/dist/esm/models/marker.d.ts +0 -5
  94. package/dist/esm/models/marker.js +0 -179
  95. package/dist/esm/models/polygon.d.ts +0 -5
  96. package/dist/esm/models/polygon.js +0 -80
  97. package/dist/esm/renderAdornments.js +0 -129
  98. package/dist/esm/types/geometry.js +0 -1
  99. package/dist/esm/types/index.js +0 -1
  100. package/dist/esm/types/jobObject.js +0 -1
  101. package/dist/esm/types/mapstyle.js +0 -1
  102. package/dist/esm/utils/browser.js +0 -6
  103. package/dist/esm/utils/choropleth.js +0 -110
  104. package/dist/esm/utils/fullscreen.js +0 -40
  105. package/dist/esm/utils/geolocation.js +0 -93
  106. package/dist/esm/utils/graphhopper.js +0 -41
  107. package/dist/esm/utils/helpers.js +0 -116
  108. package/dist/esm/utils/language.js +0 -170
  109. package/dist/esm/utils/models.js +0 -103
  110. package/dist/esm/utils/overlays.js +0 -87
  111. package/dist/esm/utils/scalebar.js +0 -52
  112. package/dist/esm/utils/svgHelpers.js +0 -1512
  113. package/dist/esm/utils/template.js +0 -120
  114. package/dist/esm/utils/youtube.js +0 -64
  115. /package/dist/{esm/controls → controls}/controls.d.ts +0 -0
  116. /package/dist/{esm/i18n.d.ts → i18n.d.ts} +0 -0
  117. /package/dist/{esm/types → types}/geometry.d.ts +0 -0
  118. /package/dist/{esm/types → types}/jobObject.d.ts +0 -0
  119. /package/dist/{esm/utils → utils}/browser.d.ts +0 -0
  120. /package/dist/{esm/utils → utils}/fullscreen.d.ts +0 -0
  121. /package/dist/{esm/utils → utils}/scalebar.d.ts +0 -0
@@ -1,141 +0,0 @@
1
- import { escapeXML, measureTextBlock } from '@/utils/svgHelpers';
2
- export function getCategoricalLegendSvg(legend, defaultFont) {
3
- const padding = 15;
4
- const swatchSize = 15;
5
- const entryMargin = 20;
6
- const swatchMargin = 10;
7
- const { title = '', titleFontColor = '#000000', titleFont = defaultFont, titleFontSize = 24, entries, entryFontColor = '#000000', entryFont = defaultFont, entryFontSize = 13, entryShape = 'rectangle', layout = 'vertical', background = '#ffffff', showBackground = false, } = legend;
8
- const titleBox = measureTextBlock([title], titleFont, titleFontSize);
9
- const entryBoxes = entries.map(entry => measureTextBlock([entry.label], entryFont, entryFontSize));
10
- const hasTitle = title.trim().length > 0;
11
- let width;
12
- let height;
13
- if (layout === 'vertical') {
14
- width =
15
- Math.max(titleBox.width, ...entryBoxes.map(b => b.width + swatchSize + swatchMargin)) +
16
- padding * 2;
17
- height =
18
- padding * 2 +
19
- (hasTitle ? titleBox.height + entryMargin : 0) +
20
- entryBoxes.reduce((sum, box) => sum + box.height, 0) +
21
- Math.max(entryBoxes.length - 1, 0) * entryMargin;
22
- }
23
- else {
24
- width = Math.max(titleBox.width + padding * 2, padding * 2 +
25
- entryBoxes.reduce((sum, box) => sum + box.width + swatchSize + swatchMargin, 0) +
26
- Math.max(entryBoxes.length - 1, 0) * entryMargin);
27
- height =
28
- padding * 2 +
29
- (hasTitle ? titleBox.height + entryMargin : 0) +
30
- Math.max(0, ...entryBoxes.map(b => b.height));
31
- }
32
- const children = [];
33
- if (showBackground) {
34
- children.push(`
35
- <rect
36
- x="0"
37
- y="0"
38
- rx="10"
39
- ry="10"
40
- width="${width}"
41
- height="${height}"
42
- fill="${background}"
43
- />
44
- `);
45
- }
46
- let x = padding;
47
- let y = padding;
48
- if (hasTitle) {
49
- children.push(`
50
- <text
51
- x="${x}"
52
- y="${y + titleBox.ascent}"
53
- font-family="${titleFont}"
54
- font-size="${titleFontSize}"
55
- fill="${titleFontColor}"
56
- >
57
- ${escapeXML(title)}
58
- </text>
59
- `);
60
- y += titleBox.height + entryMargin;
61
- }
62
- for (let i = 0; i < entries.length; i++) {
63
- const entry = entries[i];
64
- const entryBox = entryBoxes[i];
65
- if (entryShape === 'rectangle') {
66
- children.push(`
67
- <rect
68
- x="${x}"
69
- y="${y + entryBox.height / 2 - swatchSize / 2}"
70
- rx="2"
71
- ry="2"
72
- width="${swatchSize}"
73
- height="${swatchSize}"
74
- fill="${entry.color}"
75
- />
76
- `);
77
- }
78
- else if (entryShape === 'circle') {
79
- children.push(`
80
- <circle
81
- cx="${x + swatchSize / 2}"
82
- cy="${y + entryBox.height / 2}"
83
- r="${swatchSize / 2}"
84
- fill="${entry.color}"
85
- />
86
- `);
87
- }
88
- else if (entryShape === 'line') {
89
- children.push(`
90
- <line
91
- x1="${x}"
92
- y1="${y + entryBox.height / 2}"
93
- x2="${x + swatchSize}"
94
- y2="${y + entryBox.height / 2}"
95
- stroke="${entry.color}"
96
- stroke-width="2"
97
- stroke-linecap="round"
98
- />
99
- `);
100
- }
101
- else if (entryShape === 'icon' && entry.svg.length > 0) {
102
- const svgEl = new DOMParser()
103
- .parseFromString(entry.svg, 'image/svg+xml')
104
- .querySelector('svg');
105
- if (svgEl) {
106
- svgEl.setAttribute('width', String(swatchSize));
107
- svgEl.setAttribute('height', String(swatchSize));
108
- svgEl.setAttribute('transform', `translate(${x}, ${y + entryBox.height / 2 - swatchSize / 2})`);
109
- children.push(svgEl.outerHTML);
110
- }
111
- }
112
- children.push(`
113
- <text
114
- x="${x + swatchSize + swatchMargin}"
115
- y="${y + entryBox.ascent}"
116
- font-family="${entryFont}"
117
- font-size="${entryFontSize}"
118
- fill="${entryFontColor}"
119
- >
120
- ${escapeXML(entry.label)}
121
- </text>
122
- `);
123
- if (layout === 'vertical') {
124
- y += entryBox.height + entryMargin;
125
- }
126
- else {
127
- x += entryBox.width + swatchSize + swatchMargin + entryMargin;
128
- }
129
- }
130
- return `
131
- <svg
132
- xmlns="http://www.w3.org/2000/svg"
133
- width="${width}"
134
- height="${height}"
135
- viewBox="0 0 ${width} ${height}"
136
- style="display: block;"
137
- >
138
- ${children.join('')}
139
- </svg>
140
- `;
141
- }
@@ -1,393 +0,0 @@
1
- import { groupByColor, getColumnName, legendTickCount, getColorGenerator, isChoroplethColumn, } from '@/utils/choropleth';
2
- import { formatLocale } from 'd3-format';
3
- import { extent, ticks as calcTicks } from 'd3-array';
4
- import { lerp, unlerp, clamp } from '@/utils/helpers';
5
- import { escapeXML, loadFonts, measureTextBlock } from '@/utils/svgHelpers';
6
- import { getCategoricalLegendSvg } from '@/adornments/categoricalLegend';
7
- const defaultFont = 'ArialMT';
8
- const padding = 15;
9
- export function useConnectedLegend(legend, jobObject, map, vapiUrl, accessToken) {
10
- const container = document.createElement('div');
11
- container.className = 'adornment';
12
- if (legend.showBackground) {
13
- container.style.boxShadow = '0 0 7px 0 rgba(33, 37, 41, 0.25)';
14
- container.style.borderRadius = '10px';
15
- }
16
- const fonts = [legend.titleFont ?? defaultFont, legend.labelFont ?? defaultFont];
17
- const fontsToLoad = Array.from(new Set(fonts));
18
- loadFonts(fontsToLoad, vapiUrl, accessToken).then(() => (container.innerHTML = getSvg(legend, jobObject, map)));
19
- return container;
20
- }
21
- function getSvg(legend, jobObject, map) {
22
- const { target } = legend;
23
- const group = jobObject.registry?.models?.[target.modelType]?.find(g => g.id === target.groupId);
24
- const bindings = group?.models ?? [];
25
- const choropleth = group?.choropleth;
26
- const dataColumn = getColumnName(group?.fillColor);
27
- return !choropleth ||
28
- !dataColumn ||
29
- group.models.every(area => !(area.visible ?? true)) ||
30
- !isChoroplethColumn(bindings, dataColumn)
31
- ? renderBlankLegend()
32
- : choropleth.colorMode === 'categorical'
33
- ? renderCategoricalLegend(legend, choropleth, dataColumn)
34
- : choropleth.colorMode === 'linear'
35
- ? renderContinuousLegend(legend, group, map)
36
- : choropleth.colorMode === 'quantile' || choropleth.colorMode === 'quantize'
37
- ? renderDiscreteLegend(legend, group, map)
38
- : renderBlankLegend();
39
- }
40
- function renderBlankLegend() {
41
- return `
42
- <svg
43
- xmlns="http://www.w3.org/2000/svg"
44
- width="0"
45
- height="0"
46
- viewBox="0 0 0 0"
47
- style="display: block;"
48
- >
49
- </svg>
50
- `;
51
- }
52
- function renderContinuousLegend(legend, group, map) {
53
- const barThickness = 15;
54
- const stopCount = 32;
55
- const barEndRadius = barThickness / 2;
56
- const titleMargin = 10;
57
- const tickLength = 20;
58
- const tickLabelMargin = 5;
59
- const { id, layout = 'vertical', labelFont = defaultFont, labelFontSize = 13, labelFontColor = '#000000', numberFormat = '.2~s', title = '', titleFont = defaultFont, titleFontSize = 14, titleFontColor = '#000000', showBackground = false, background = '#ffffff', } = legend;
60
- const gradientId = `gradient-${id}`;
61
- const isHorizontal = layout === 'horizontal';
62
- const colorGenerator = getColorGenerator(group);
63
- if (colorGenerator === undefined) {
64
- return renderBlankLegend();
65
- }
66
- const children = [];
67
- const [min, max] = extent(colorGenerator.domain());
68
- const ticks = calcTicks(min, max, legendTickCount);
69
- const formatLabel = getFormatter(numberFormat);
70
- const tickLabels = ticks.map(tick => formatLabel(tick));
71
- const tickLabelBoxes = tickLabels.map(label => measureTextBlock([label], labelFont, labelFontSize));
72
- const stops = [];
73
- for (let i = 0; i < stopCount; i++) {
74
- const t = i / (stopCount - 1);
75
- stops.push(`<stop offset="${t * 100}%" stop-color="${colorGenerator(min + t * (max - min))}" />`);
76
- }
77
- const transform = !isHorizontal ? 'rotate(90)' : '';
78
- children.push(`
79
- <defs>
80
- <linearGradient id="${gradientId}" gradientTransform="${transform}">
81
- ${stops.join('')}
82
- </linearGradient>
83
- </defs>
84
- `);
85
- const titleBox = measureTextBlock([title], titleFont, titleFontSize);
86
- const hasTitle = title.trim().length > 0;
87
- const labelBox = {
88
- width: Math.max(0, ...tickLabelBoxes.map(b => b.width)),
89
- height: Math.max(0, ...tickLabelBoxes.map(b => b.height)),
90
- ascent: Math.max(0, ...tickLabelBoxes.map(b => b.ascent)),
91
- };
92
- const titleBoxHeight = hasTitle ? titleBox.height + titleMargin : 0;
93
- const titleBoxWidth = hasTitle ? titleBox.width : 0;
94
- const count = ticks.length - 1;
95
- const barLength = clamp(45 * count, isHorizontal
96
- ? Math.ceil((labelBox.width + 10) * count)
97
- : Math.ceil((labelBox.height + 10) * count), isHorizontal
98
- ? Math.floor(map.getContainer().clientWidth - 10 - padding * 2)
99
- : Math.floor(map.getContainer().clientHeight - 10 - padding * 2 - titleBoxHeight));
100
- const width = isHorizontal
101
- ? Math.ceil(padding * 2 + Math.max(titleBoxWidth, barLength))
102
- : Math.ceil(padding * 2 + Math.max(titleBoxWidth, tickLength + tickLabelMargin + labelBox.width));
103
- const height = isHorizontal
104
- ? Math.ceil(padding * 2 + titleBoxHeight + tickLength + tickLabelMargin + labelBox.ascent)
105
- : Math.ceil(padding * 2 + titleBoxHeight + barLength);
106
- if (showBackground) {
107
- children.push(`
108
- <rect
109
- x="0"
110
- y="0"
111
- rx="10"
112
- ry="10"
113
- width="${width}"
114
- height="${height}"
115
- fill="${background}"
116
- />
117
- `);
118
- }
119
- const x = padding;
120
- let y = padding;
121
- if (hasTitle) {
122
- children.push(`
123
- <text
124
- x="${x}"
125
- y="${y + titleBox.ascent}"
126
- font-family="${titleFont}"
127
- font-size="${titleFontSize}"
128
- fill="${titleFontColor}"
129
- >
130
- ${escapeXML(title)}
131
- </text>
132
- `);
133
- y += titleBox.height + titleMargin;
134
- }
135
- children.push(`
136
- <rect
137
- x="${x}"
138
- y="${y}"
139
- rx="${barEndRadius}"
140
- ry="${barEndRadius}"
141
- width="${isHorizontal ? barLength : barThickness}"
142
- height="${isHorizontal ? barThickness : barLength}"
143
- fill="url(#${gradientId})"
144
- />
145
- `);
146
- for (let i = 1; i < ticks.length - 1; i++) {
147
- const tick = ticks[i];
148
- const label = tickLabels[i];
149
- const box = tickLabelBoxes[i];
150
- const offset = lerp(0, barLength, unlerp(min, max, tick));
151
- if (offset > barEndRadius && offset < barLength - barEndRadius) {
152
- children.push(`
153
- <line
154
- x1="${isHorizontal ? Math.floor(x + offset) + 0.5 : x}"
155
- y1="${isHorizontal ? y : Math.floor(y + offset) + 0.5}"
156
- x2="${isHorizontal ? Math.floor(x + offset) + 0.5 : x + tickLength}"
157
- y2="${isHorizontal ? y + tickLength : Math.floor(y + offset) + 0.5}"
158
- stroke="#ffffff"
159
- />
160
- `);
161
- }
162
- children.push(`
163
- <text
164
- x="${isHorizontal ? x + offset : x + tickLength + tickLabelMargin}"
165
- y="${isHorizontal
166
- ? y + tickLength + tickLabelMargin + box.ascent
167
- : y + offset - box.descent + box.height / 2}"
168
- font-family="${labelFont}"
169
- font-size="${labelFontSize}"
170
- fill="${labelFontColor}"
171
- text-anchor="${isHorizontal ? 'middle' : 'start'}"
172
- >
173
- ${escapeXML(label)}
174
- </text>
175
- `);
176
- }
177
- return `
178
- <svg
179
- xmlns="http://www.w3.org/2000/svg"
180
- width="${width}"
181
- height="${height}"
182
- viewBox="0 0 ${width} ${height}"
183
- style="display: block;"
184
- >
185
- ${children.join('')}
186
- </svg>
187
- `;
188
- }
189
- function renderDiscreteLegend(legend, group, map) {
190
- const gap = 10;
191
- const colorGenerator = getColorGenerator(group);
192
- const colors = colorGenerator?.range();
193
- const children = [];
194
- let height = 0;
195
- let width = 0;
196
- if (colorGenerator && colors && colors.length > 1) {
197
- const { layout = 'vertical', labelFont = defaultFont, labelFontSize = 13, labelFontColor = '#000000', labelStyle = 'range', numberFormat = '.2~s', title = '', titleFont = defaultFont, titleFontSize = 14, titleFontColor = '#000000', showBackground = false, background = '#ffffff', } = legend;
198
- const isVertical = layout === 'vertical';
199
- const isRange = labelStyle === 'range';
200
- const formatLabel = getFormatter(numberFormat);
201
- const labels = isRange
202
- ? colors
203
- .map(color => colorGenerator.invertExtent(color))
204
- .map((range, index, array) => index === 0
205
- ? `< ${formatLabel(range[1])}`
206
- : index === array.length - 1
207
- ? `> ${formatLabel(range[0])}`
208
- : `${formatLabel(range[0])} – ${formatLabel(range[1])}`)
209
- : colors
210
- .map(color => colorGenerator.invertExtent(color))
211
- .reduce((g, range, index) => (index && g.push(formatLabel(range[0])), g), []);
212
- const lBoxes = labels.map(label => measureTextBlock([label], labelFont, labelFontSize));
213
- const titleBox = measureTextBlock([title], titleFont, titleFontSize);
214
- const hasTitle = title.trim().length > 0;
215
- const labelBox = {
216
- width: Math.max(0, ...lBoxes.map(b => b.width)),
217
- height: Math.max(0, ...lBoxes.map(b => b.height)),
218
- ascent: Math.max(0, ...lBoxes.map(b => b.ascent)),
219
- };
220
- const titleBoxHeight = hasTitle ? titleBox.height + gap : 0;
221
- const titleBoxWidth = hasTitle ? titleBox.width : 0;
222
- const count = colors.length;
223
- let m = 45; // default segment length
224
- const c = 15; // segment width
225
- const r = c / 2; // radius
226
- if (isVertical) {
227
- m = clamp(m, Math.ceil(labelBox.height) + 10, Math.floor((map.getContainer().clientHeight - 10 - padding * 2 - titleBoxHeight) / count));
228
- height = Math.ceil(padding * 2 + titleBoxHeight + count * m);
229
- width = Math.ceil(padding * 2 + Math.max(titleBoxWidth, c + gap + labelBox.width));
230
- }
231
- else {
232
- m = clamp(m, Math.ceil(labelBox.width) + 10, Math.floor((map.getContainer().clientWidth - 10 - padding * 2) / count));
233
- width = Math.ceil(padding * 2 + Math.max(titleBoxWidth, count * m));
234
- height = Math.ceil(padding * 2 + titleBoxHeight + c + gap + labelBox.ascent);
235
- }
236
- if (showBackground) {
237
- children.push(`
238
- <rect
239
- x="0"
240
- y="0"
241
- rx="10"
242
- ry="10"
243
- width="${width}"
244
- height="${height}"
245
- fill="${background}"
246
- />
247
- `);
248
- }
249
- let x = padding;
250
- let y = padding;
251
- if (hasTitle) {
252
- children.push(`
253
- <text
254
- x="${x}"
255
- y="${y + titleBox.ascent}"
256
- font-family="${titleFont}"
257
- font-size="${titleFontSize}"
258
- fill="${titleFontColor}"
259
- >
260
- ${escapeXML(title)}
261
- </text>
262
- `);
263
- y += titleBoxHeight;
264
- }
265
- const w = isVertical ? c : m;
266
- const h = isVertical ? m : c;
267
- const dx = isVertical ? 0 : m;
268
- const dy = isVertical ? m : 0;
269
- const tickLength = isRange ? c : c + 5;
270
- const d1 = isVertical
271
- ? `M ${x} ${y + r} v ${m - r} h ${c} v ${-(m - r)} a ${r} ${r} 0 0 0 ${-c} 0 z`
272
- : `M ${x + r} ${y} h ${m - r} v ${c} h ${-(m - r)} a ${r} ${r} 0 0 1 0 ${-c} z`;
273
- children.push(`<path d="${d1}" fill="${colors[0]}" />`);
274
- x += dx;
275
- y += dy;
276
- for (let i = 1; i < count - 1; i++, x += dx, y += dy) {
277
- children.push(`
278
- <rect
279
- x="${x}"
280
- y="${y}"
281
- width="${w}"
282
- height="${h}"
283
- fill="${colors[i]}"
284
- />
285
- `);
286
- children.push(`
287
- <line
288
- x1="${isVertical ? x : x + 0.5}"
289
- y1="${isVertical ? y + 0.5 : y}"
290
- x2="${isVertical ? x + tickLength : x + 0.5}"
291
- y2="${isVertical ? y + 0.5 : y + tickLength}"
292
- stroke="#ffffff"
293
- />
294
- `);
295
- }
296
- const d2 = isVertical
297
- ? `M ${x} ${y} v ${m - r} a ${r} ${r} 0 0 0 ${c} 0 v ${-(m - r)} z`
298
- : `M ${x} ${y} h ${m - r} a ${r} ${r} 0 0 1 0 ${c} h ${-(m - r)} z`;
299
- children.push(`<path d="${d2}" fill="${colors[count - 1]}" />`);
300
- children.push(`
301
- <line
302
- x1="${isVertical ? x : x + 0.5}"
303
- y1="${isVertical ? y + 0.5 : y}"
304
- x2="${isVertical ? x + tickLength : x + 0.5}"
305
- y2="${isVertical ? y + 0.5 : y + tickLength}"
306
- stroke="#ffffff"
307
- />
308
- `);
309
- x = padding;
310
- y = padding + titleBoxHeight;
311
- for (let i = 0; i < labels.length; i++, x += dx, y += dy) {
312
- children.push(`
313
- <text
314
- x="${isVertical ? x + c + gap : x + (isRange ? m / 2 : m)}"
315
- y="${isVertical
316
- ? y + (isRange ? m / 2 : m) - labelBox.height / 2 + labelBox.ascent
317
- : y + c + gap + labelBox.ascent}"
318
- text-anchor="${isVertical ? 'start' : 'middle'}"
319
- font-family="${labelFont}"
320
- font-size="${labelFontSize}"
321
- fill="${labelFontColor}"
322
- >
323
- ${escapeXML(labels[i])}
324
- </text>
325
- `);
326
- }
327
- }
328
- return `
329
- <svg
330
- xmlns="http://www.w3.org/2000/svg"
331
- width="${width}"
332
- height="${height}"
333
- viewBox="0 0 ${width} ${height}"
334
- style="display: block;"
335
- >
336
- ${children.join('')}
337
- </svg>
338
- `;
339
- }
340
- function renderCategoricalLegend(legend, choropleth, dataColumn) {
341
- const categoricalGroup = choropleth.categoricalColors[dataColumn];
342
- if (categoricalGroup === undefined) {
343
- return renderBlankLegend();
344
- }
345
- const colorGroup = groupByColor(categoricalGroup.values);
346
- const entries = Object.entries(categoricalGroup.colors)
347
- .map(([color, meta]) => ({
348
- color,
349
- label: meta.title ?? colorGroup[color] ?? choropleth.defaultGroupName,
350
- order: meta.order,
351
- hidden: meta.hidden,
352
- svg: '',
353
- }))
354
- .filter(entry => !entry.hidden)
355
- .sort((a, b) => a.order - b.order);
356
- return getCategoricalLegendSvg({
357
- type: 'manualLegend',
358
- id: legend.id,
359
- name: legend.name,
360
- position: legend.position,
361
- stacking: legend.stacking ?? 'vertical',
362
- layout: legend.layout ?? 'vertical',
363
- title: legend.title ?? '',
364
- titleFont: legend.titleFont ?? defaultFont,
365
- titleFontColor: legend.titleFontColor ?? '#000000',
366
- titleFontSize: legend.titleFontSize ?? 14,
367
- entryFont: legend.labelFont ?? defaultFont,
368
- entryFontColor: legend.labelFontColor ?? '#000000',
369
- entryFontSize: legend.labelFontSize ?? 13,
370
- entryShape: 'rectangle',
371
- entries,
372
- background: legend.background ?? '#ffffff',
373
- showBackground: legend.showBackground ?? false,
374
- }, defaultFont);
375
- }
376
- function getFormatter(format) {
377
- const { decimal, group } = getSeparators();
378
- const locale = formatLocale({
379
- decimal,
380
- thousands: group,
381
- grouping: [3],
382
- currency: ['', ''],
383
- });
384
- return locale.format(format);
385
- }
386
- function getSeparators() {
387
- const parts = new Intl.NumberFormat(navigator.languages).formatToParts(1000.1);
388
- const decimal = parts.find(part => part.type === 'decimal')?.value;
389
- const group = parts.find(part => part.type === 'group')?.value;
390
- return decimal !== undefined && group !== undefined
391
- ? { decimal, group }
392
- : { decimal: '.', group: ',' };
393
- }
@@ -1,29 +0,0 @@
1
- import { numberRe } from '@/utils/helpers';
2
- export function useCustomAdornment(adornment) {
3
- const container = document.createElement('div');
4
- container.className = 'adornment';
5
- const { svg, scale = 1 } = adornment;
6
- const doc = new DOMParser().parseFromString(svg, 'image/svg+xml');
7
- const svgEl = doc.querySelector('svg');
8
- if (svgEl) {
9
- const viewBoxRe = new RegExp(numberRe
10
- .toString()
11
- .replace(/^\/\^|\$\/$/g, '')
12
- .replace(/.*/, '^($&)[, ]($&)[, ]($&)[, ]($&)$$'));
13
- const width = svgEl.getAttribute('width');
14
- const height = svgEl.getAttribute('height');
15
- if (width && height && numberRe.test(width) && numberRe.test(height)) {
16
- svgEl.setAttribute('width', String(Number(width) * scale));
17
- svgEl.setAttribute('height', String(Number(height) * scale));
18
- }
19
- else {
20
- const match = viewBoxRe.exec(svgEl.getAttribute('viewBox'));
21
- const w = match ? Number(match[3]) : 300;
22
- const h = match ? Number(match[4]) : 150;
23
- svgEl.setAttribute('width', String(w * scale));
24
- svgEl.setAttribute('height', String(h * scale));
25
- }
26
- container.appendChild(svgEl);
27
- }
28
- return container;
29
- }
@@ -1,71 +0,0 @@
1
- import { escapeXML, loadFonts, measureTextBlock } from '@/utils/svgHelpers';
2
- export function useHeading(heading, vapiUrl, accessToken) {
3
- const container = document.createElement('div');
4
- container.className = 'adornment';
5
- const defaultFont = 'ArialMT';
6
- const fonts = [heading.titleFont ?? defaultFont, heading.subtitleFont ?? defaultFont];
7
- const fontsToLoad = Array.from(new Set(fonts));
8
- loadFonts(fontsToLoad, vapiUrl, accessToken).then(() => (container.innerHTML = getSvg(heading, defaultFont)));
9
- return container;
10
- }
11
- function getSvg(heading, defaultFont) {
12
- const padding = 8;
13
- const radius = 6;
14
- const { title, titleColor = '#000000', titleFont = defaultFont, titleFontSize = 20, titleJustify = 'center', subtitle, subtitleColor = '#000000', subtitleFont = defaultFont, subtitleFontSize = 12, subtitleJustify = 'center', background = '#ffffff', showBackground = false, } = heading;
15
- let measuredWidth = 0;
16
- let titleHeight = 0;
17
- let subtitleHeight = 0;
18
- let titleY = 0;
19
- let subtitleY = 0;
20
- const titleBox = title.trim().length > 0 ? measureTextBlock([title], titleFont, titleFontSize) : null;
21
- const subtitleBox = subtitle.trim().length > 0
22
- ? measureTextBlock([subtitle], subtitleFont, subtitleFontSize)
23
- : null;
24
- measuredWidth = Math.max(titleBox?.width ?? 0, subtitleBox?.width ?? 0);
25
- if (titleBox) {
26
- const { ascent: ta, descent: td } = titleBox;
27
- titleHeight = ta + td;
28
- titleY = padding + ta;
29
- }
30
- if (subtitleBox) {
31
- const { ascent: sa, descent: sd } = subtitleBox;
32
- subtitleHeight = sa + sd;
33
- if (titleBox) {
34
- subtitleY = titleY + titleBox.descent + sa + 6;
35
- }
36
- else {
37
- subtitleY = padding + sa;
38
- }
39
- }
40
- const containerWidth = measuredWidth + padding * 2;
41
- const containerHeight = titleHeight + subtitleHeight + padding * 2;
42
- const titleX = titleJustify === 'center'
43
- ? containerWidth / 2
44
- : titleJustify === 'right'
45
- ? containerWidth - padding
46
- : padding;
47
- const subtitleX = subtitleJustify === 'center'
48
- ? containerWidth / 2
49
- : subtitleJustify === 'right'
50
- ? containerWidth - padding
51
- : padding;
52
- let svg = '';
53
- svg += `<svg xmlns="http://www.w3.org/2000/svg" width="${containerWidth}" height="${containerHeight}" viewBox="0 0 ${containerWidth} ${containerHeight}">`;
54
- svg += `<rect x="0" y="0" width="${containerWidth}" height="${containerHeight}" fill="${background}" rx="${radius}" style="visibility:${showBackground ? 'visible' : 'hidden'}" />`;
55
- if (titleBox || subtitleBox) {
56
- const titleAnchor = titleJustify === 'center' ? 'middle' : titleJustify === 'right' ? 'end' : 'start';
57
- const subtitleAnchor = subtitleJustify === 'center' ? 'middle' : subtitleJustify === 'right' ? 'end' : 'start';
58
- svg += `<text x="${titleX}" y="${titleY}" fill="${titleColor}" font-family="${titleFont}" font-size="${titleFontSize}" text-anchor="${titleAnchor}">`;
59
- if (titleBox) {
60
- svg += `${escapeXML(title)}`;
61
- }
62
- if (subtitleBox) {
63
- svg += `<tspan x="${subtitleX}" y="${subtitleY}" fill="${subtitleColor}" font-family="${subtitleFont}" font-size="${subtitleFontSize}" text-anchor="${subtitleAnchor}">`;
64
- svg += `${escapeXML(subtitle)}`;
65
- svg += `</tspan>`;
66
- }
67
- svg += `</text>`;
68
- }
69
- svg += `</svg>`;
70
- return svg;
71
- }
@@ -1,3 +0,0 @@
1
- import type { Map } from '@mapcreator/maplibre-gl';
2
- import type { JobObjectInsetMap } from '@/types/jobObject';
3
- export declare function useInsetMap(insetMap: JobObjectInsetMap, map: Map, cdnUrl: string): HTMLElement;