fix(website): accurate Iran border on homepage map + slow on/off marker blink
CI/CD / CI · API (dotnet build + test) (pull_request) Successful in 46s
CI/CD / CI · Admin API (dotnet build) (pull_request) Successful in 31s
CI/CD / CI · Dashboard (tsc) (pull_request) Successful in 1m5s
CI/CD / CI · Admin Web (tsc) (pull_request) Successful in 35s
CI/CD / CI · Website (tsc) (pull_request) Successful in 45s
CI/CD / CI · Koja (tsc) (pull_request) Successful in 51s
CI/CD / Deploy · all services (pull_request) Has been skipped
CI/CD / CI · API (dotnet build + test) (pull_request) Successful in 46s
CI/CD / CI · Admin API (dotnet build) (pull_request) Successful in 31s
CI/CD / CI · Dashboard (tsc) (pull_request) Successful in 1m5s
CI/CD / CI · Admin Web (tsc) (pull_request) Successful in 35s
CI/CD / CI · Website (tsc) (pull_request) Successful in 45s
CI/CD / CI · Koja (tsc) (pull_request) Successful in 51s
CI/CD / Deploy · all services (pull_request) Has been skipped
Replaced the rough 40-point hand-drawn polygon with the real national border (74 vertices, Natural Earth via world.geo.json) and fitted the projection bounding box to Iran's true extent, so the silhouette is recognisable and café markers stay aligned. Reworked the marker animation from a radar-style expanding ring into a slow 3.6s ease-in-out lamp fade (opacity 1->0.2->1) with a halo that glows on and off in sync. Verified via the SVG timeline: opacity 1.0 at 0s, 0.2 at 1.8s, 1.0 at 3.6s. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,11 +22,14 @@ type MarkersApiResponse = {
|
|||||||
|
|
||||||
// ── Coordinate transform ──────────────────────────────────────────────────────
|
// ── Coordinate transform ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
// Iran bounding box (degrees)
|
// Iran bounding box (degrees) — fitted to the real border extent
|
||||||
const MIN_LNG = 44;
|
// (lng 44.11–63.32, lat 25.08–39.71) with a small margin so the
|
||||||
const MAX_LNG = 64;
|
// silhouette fills the viewBox. Markers reproject with the same box,
|
||||||
const MIN_LAT = 24;
|
// so they stay aligned with the outline.
|
||||||
const MAX_LAT = 41;
|
const MIN_LNG = 43.6;
|
||||||
|
const MAX_LNG = 63.8;
|
||||||
|
const MIN_LAT = 24.6;
|
||||||
|
const MAX_LAT = 40.2;
|
||||||
const SVG_W = 600;
|
const SVG_W = 600;
|
||||||
const SVG_H = 500;
|
const SVG_H = 500;
|
||||||
|
|
||||||
@@ -41,34 +44,24 @@ function toPt([lng, lat]: [number, number]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Iran silhouette ────────────────────────────────────────────────────────────
|
// ── Iran silhouette ────────────────────────────────────────────────────────────
|
||||||
// Simplified 40-point polygon; approximate but recognisable.
|
// Real national border, simplified to 74 vertices (source: Natural Earth via
|
||||||
// Coordinates are [longitude, latitude] going clockwise from NW.
|
// world.geo.json). Coordinates are [longitude, latitude]; the ring starts on
|
||||||
|
// the Caspian (NE) and runs clockwise. Projected through toX/toY below, the
|
||||||
|
// same transform used for the café markers, so dots land in the right place.
|
||||||
const IRAN_OUTLINE: [number, number][] = [
|
const IRAN_OUTLINE: [number, number][] = [
|
||||||
// NW corner / Turkey-Armenia-Azerbaijan
|
[53.92, 37.20], [54.80, 37.39], [55.51, 37.96], [56.18, 37.94], [56.62, 38.12], [57.33, 38.03],
|
||||||
[44.8, 39.6], [45.5, 39.2], [46.2, 38.9],
|
[58.44, 37.52], [59.23, 37.41], [60.38, 36.53], [61.12, 36.49], [61.21, 35.65], [60.80, 34.40],
|
||||||
[46.8, 39.1], [47.6, 38.9],
|
[60.53, 33.68], [60.96, 33.53], [60.54, 32.98], [60.86, 32.18], [60.94, 31.55], [61.70, 31.38],
|
||||||
// Caspian coast (the concave notch heading south then north again)
|
[61.78, 30.74], [60.87, 29.83], [61.37, 29.30], [61.77, 28.70], [62.73, 28.26], [62.76, 27.38],
|
||||||
[48.3, 38.4], [49.0, 37.5], [49.9, 37.2],
|
[63.23, 27.22], [63.32, 26.76], [61.87, 26.24], [61.50, 25.08], [59.62, 25.38], [58.53, 25.61],
|
||||||
[51.0, 36.9], [52.2, 36.8], [53.0, 36.7],
|
[57.40, 25.74], [56.97, 26.97], [56.49, 27.14], [55.72, 26.96], [54.72, 26.48], [53.49, 26.81],
|
||||||
[54.0, 37.1], [54.7, 37.5],
|
[52.48, 27.58], [51.52, 27.87], [50.85, 28.81], [50.12, 30.15], [49.58, 29.99], [48.94, 30.32],
|
||||||
// NE / Turkmenistan
|
[48.57, 29.93], [48.01, 30.45], [48.00, 30.99], [47.69, 30.98], [47.85, 31.71], [47.33, 32.47],
|
||||||
[55.6, 37.4], [56.9, 37.1], [57.7, 36.8],
|
[46.11, 33.02], [45.42, 33.97], [45.65, 34.75], [46.15, 35.09], [46.08, 35.68], [45.42, 35.98],
|
||||||
[58.7, 37.5], [59.4, 36.8], [60.1, 36.7],
|
[44.77, 37.17], [44.23, 37.97], [44.42, 38.28], [44.11, 39.43], [44.79, 39.71], [44.95, 39.34],
|
||||||
// East / Afghanistan
|
[45.46, 38.87], [46.14, 38.74], [46.51, 38.77], [47.69, 39.51], [48.06, 39.58], [48.36, 39.29],
|
||||||
[61.2, 36.5], [61.3, 35.7], [62.0, 35.5],
|
[48.01, 38.79], [48.63, 38.27], [48.88, 38.32], [49.20, 37.58], [50.15, 37.37], [50.84, 36.87],
|
||||||
[62.5, 34.0], [63.0, 33.0], [63.2, 31.5],
|
[52.26, 36.70], [53.83, 36.97],
|
||||||
// SE / Pakistan – Oman Sea
|
|
||||||
[61.8, 29.8], [60.9, 29.5], [60.0, 27.5],
|
|
||||||
[59.0, 25.9], [58.5, 25.4],
|
|
||||||
// South coast (Persian Gulf, west-bound)
|
|
||||||
[57.5, 25.3], [56.4, 25.9], [55.6, 26.0],
|
|
||||||
[54.5, 27.0], [53.4, 27.3], [52.4, 28.0],
|
|
||||||
[51.1, 28.4], [50.4, 29.1], [49.0, 29.6],
|
|
||||||
[48.5, 30.2], [48.2, 30.8],
|
|
||||||
// West / Iraq border
|
|
||||||
[47.7, 31.0], [47.2, 32.0], [46.8, 33.2],
|
|
||||||
[46.2, 34.4], [45.5, 36.0], [45.0, 37.0],
|
|
||||||
[44.8, 38.1], [44.5, 38.9], [44.8, 39.6],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const IRAN_PATH =
|
const IRAN_PATH =
|
||||||
@@ -153,42 +146,50 @@ async function IranMapSvg() {
|
|||||||
</g>
|
</g>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Café blinking dots */}
|
{/* Café markers — each glows slowly on and off like a small lamp.
|
||||||
|
Halo and core brighten/dim together (ease-in-out), staggered so the
|
||||||
|
map twinkles organically rather than pulsing in unison. */}
|
||||||
{markers.map((m, idx) => {
|
{markers.map((m, idx) => {
|
||||||
const cx = toX(m.longitude);
|
const cx = toX(m.longitude);
|
||||||
const cy = toY(m.latitude);
|
const cy = toY(m.latitude);
|
||||||
// Stagger animation delay so dots don't all pulse in sync
|
const delay = `${((idx * 0.7) % 3.6).toFixed(2)}s`;
|
||||||
const delay = `${(idx * 0.4) % 2}s`;
|
const dur = "3.6s";
|
||||||
|
// ease-in-out for a smooth lamp-like fade
|
||||||
|
const ease = "0.4 0 0.6 1; 0.4 0 0.6 1";
|
||||||
return (
|
return (
|
||||||
<g key={m.id} filter="url(#glow)">
|
<g key={m.id} filter="url(#glow)">
|
||||||
{/* Outer pulse ring */}
|
{/* Soft halo */}
|
||||||
<circle cx={cx} cy={cy} r={10} fill="#0F6E56" opacity={0.2}>
|
<circle cx={cx} cy={cy} r={9} fill="#0F6E56">
|
||||||
<animate
|
|
||||||
attributeName="r"
|
|
||||||
values="8;16;8"
|
|
||||||
dur="2.4s"
|
|
||||||
begin={delay}
|
|
||||||
repeatCount="indefinite"
|
|
||||||
/>
|
|
||||||
<animate
|
<animate
|
||||||
attributeName="opacity"
|
attributeName="opacity"
|
||||||
values="0.25;0;0.25"
|
values="0.45;0.04;0.45"
|
||||||
dur="2.4s"
|
keyTimes="0;0.5;1"
|
||||||
|
calcMode="spline"
|
||||||
|
keySplines={ease}
|
||||||
|
dur={dur}
|
||||||
begin={delay}
|
begin={delay}
|
||||||
repeatCount="indefinite"
|
repeatCount="indefinite"
|
||||||
/>
|
/>
|
||||||
</circle>
|
</circle>
|
||||||
{/* Core dot */}
|
{/* Core dot — turns on (bright, slightly larger) and off (dim) */}
|
||||||
<circle
|
<circle cx={cx} cy={cy} r={4.5} fill="#0F6E56">
|
||||||
cx={cx}
|
|
||||||
cy={cy}
|
|
||||||
r={5}
|
|
||||||
fill="#0F6E56"
|
|
||||||
>
|
|
||||||
<animate
|
<animate
|
||||||
attributeName="opacity"
|
attributeName="opacity"
|
||||||
values="1;0.5;1"
|
values="1;0.2;1"
|
||||||
dur="2.4s"
|
keyTimes="0;0.5;1"
|
||||||
|
calcMode="spline"
|
||||||
|
keySplines={ease}
|
||||||
|
dur={dur}
|
||||||
|
begin={delay}
|
||||||
|
repeatCount="indefinite"
|
||||||
|
/>
|
||||||
|
<animate
|
||||||
|
attributeName="r"
|
||||||
|
values="4.5;5.6;4.5"
|
||||||
|
keyTimes="0;0.5;1"
|
||||||
|
calcMode="spline"
|
||||||
|
keySplines={ease}
|
||||||
|
dur={dur}
|
||||||
begin={delay}
|
begin={delay}
|
||||||
repeatCount="indefinite"
|
repeatCount="indefinite"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user