Skip to content

Commit f0d541d

Browse files
better
1 parent 52f5d9a commit f0d541d

1 file changed

Lines changed: 111 additions & 31 deletions

File tree

src/map/MapManager.ts

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class MapManager {
1010
private layerMap: Map<string, L.Layer> = new Map();
1111
private svgOverlay: SVGSVGElement | null = null;
1212
private flagPatterns: Map<string, string> = new Map();
13+
private flagImages: Map<string, HTMLImageElement> = new Map();
1314

1415
constructor(containerId: string, state: AppState) {
1516
this.state = state;
@@ -111,7 +112,10 @@ export class MapManager {
111112
resolve();
112113
};
113114

114-
// Also patch the _drawPath method to handle multiple parts
115+
// Store reference to MapManager for accessing flag images
116+
const mapManager = this;
117+
118+
// Also patch the _drawPath method to handle multiple parts and flag patterns
115119
const originalDrawPath = bigImageControl._drawPath.bind(bigImageControl);
116120
bigImageControl._drawPath = function(value: any) {
117121
if (value.multiParts) {
@@ -123,6 +127,46 @@ export class MapManager {
123127
this.ctx[count++ ? 'lineTo' : 'moveTo'](point.x, point.y);
124128
});
125129
if (partData.closed) this.ctx.closePath();
130+
131+
// Check if this is a flag pattern (URL reference)
132+
if (value.options.fillColor && typeof value.options.fillColor === 'string' && value.options.fillColor.startsWith('url(#flag-pattern-')) {
133+
// Extract flag code from pattern ID
134+
const match = value.options.fillColor.match(/flag-pattern-([a-z]{2})/);
135+
if (match) {
136+
const flagCode = match[1].toUpperCase();
137+
const img = mapManager.flagImages.get(flagCode);
138+
139+
if (img && img.complete && img.naturalWidth > 0) {
140+
// Image is loaded, create pattern
141+
try {
142+
const pattern = this.ctx.createPattern(img, 'repeat');
143+
if (pattern) {
144+
this.ctx.fillStyle = pattern;
145+
this.ctx.globalAlpha = value.options.fillOpacity || 0.9;
146+
this.ctx.fill();
147+
this.ctx.globalAlpha = 1;
148+
149+
if (value.options.stroke) {
150+
this.ctx.strokeStyle = value.options.color || '#ffffff';
151+
this.ctx.lineWidth = value.options.weight || 1;
152+
this.ctx.stroke();
153+
}
154+
return; // Don't call _feelPath since we handled it
155+
}
156+
} catch (e) {
157+
console.warn('Failed to create flag pattern for export:', e);
158+
}
159+
}
160+
161+
// Fallback to gray if image not loaded or failed
162+
this.ctx.fillStyle = '#d3d3d3';
163+
this.ctx.globalAlpha = 0.7;
164+
this.ctx.fill();
165+
this.ctx.globalAlpha = 1;
166+
return;
167+
}
168+
}
169+
126170
this._feelPath(value.options);
127171
});
128172
} else {
@@ -190,6 +234,14 @@ export class MapManager {
190234
return this.flagPatterns.get(flagCode)!;
191235
}
192236

237+
// Pre-load flag image for export (if not already loaded)
238+
if (!this.flagImages.has(flagCode)) {
239+
const img = new Image();
240+
img.crossOrigin = 'anonymous';
241+
img.src = `https://flagcdn.com/w160/${flagCode.toLowerCase()}.png`;
242+
this.flagImages.set(flagCode, img);
243+
}
244+
193245
// Find or create SVG element with defs
194246
const mapContainer = this.map.getContainer();
195247
const panes = (this.map as any)._panes;
@@ -437,42 +489,70 @@ export class MapManager {
437489
});
438490
}
439491

492+
private async waitForFlagImagesToLoad(): Promise<void> {
493+
const promises: Promise<void>[] = [];
494+
495+
this.flagImages.forEach((img, flagCode) => {
496+
if (!img.complete) {
497+
promises.push(
498+
new Promise((resolve) => {
499+
if (img.complete) {
500+
resolve();
501+
} else {
502+
img.onload = () => resolve();
503+
img.onerror = () => resolve(); // Resolve even on error to not block export
504+
}
505+
})
506+
);
507+
}
508+
});
509+
510+
if (promises.length > 0) {
511+
await Promise.all(promises);
512+
// Small additional delay to ensure everything is ready
513+
await new Promise(resolve => setTimeout(resolve, 100));
514+
}
515+
}
516+
440517
prepareForExport(): void {
441518
// Close all tooltips
442519
this.closeAllTooltips();
443520

444-
// Refresh all layer styles to ensure they're captured correctly
445-
this.layerMap.forEach((layer, countryId) => {
446-
if (layer instanceof L.Path) {
447-
const country = this.state.getCountry(countryId);
448-
if (country) {
449-
const color = this.state.getCountryColor(countryId);
450-
const flag = this.state.getCountryFlag(countryId);
451-
452-
let fillColor = color || '#d3d3d3';
453-
let fillOpacity = 0.7;
454-
455-
// Use flag pattern if flag is set
456-
if (flag) {
457-
const patternId = this.createFlagPattern(flag);
458-
fillColor = `url(#${patternId})`;
459-
fillOpacity = 0.9;
460-
}
521+
// Wait for flag images to load before proceeding
522+
this.waitForFlagImagesToLoad().then(() => {
523+
// Refresh all layer styles to ensure they're captured correctly
524+
this.layerMap.forEach((layer, countryId) => {
525+
if (layer instanceof L.Path) {
526+
const country = this.state.getCountry(countryId);
527+
if (country) {
528+
const color = this.state.getCountryColor(countryId);
529+
const flag = this.state.getCountryFlag(countryId);
530+
531+
let fillColor = color || '#d3d3d3';
532+
let fillOpacity = 0.7;
533+
534+
// Use flag pattern if flag is set
535+
if (flag) {
536+
const patternId = this.createFlagPattern(flag);
537+
fillColor = `url(#${patternId})`;
538+
fillOpacity = 0.9;
539+
}
461540

462-
const style = {
463-
fill: true,
464-
fillColor: fillColor,
465-
fillOpacity: fillOpacity,
466-
stroke: true,
467-
color: '#ffffff',
468-
weight: 1,
469-
opacity: 1,
470-
};
471-
layer.setStyle(style);
472-
// Ensure the options are also set
473-
layer.options = { ...layer.options, ...style };
541+
const style = {
542+
fill: true,
543+
fillColor: fillColor,
544+
fillOpacity: fillOpacity,
545+
stroke: true,
546+
color: '#ffffff',
547+
weight: 1,
548+
opacity: 1,
549+
};
550+
layer.setStyle(style);
551+
// Ensure the options are also set
552+
layer.options = { ...layer.options, ...style };
553+
}
474554
}
475-
}
555+
});
476556
});
477557
}
478558

0 commit comments

Comments
 (0)