Skip to content

Commit

Permalink
Merge pull request #1792 from owid/map-geo-paths-perf
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelgerber authored Jan 26, 2023
2 parents f5d6eeb + f31406d commit 57b8e6a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { GeoContext } from "d3-geo"

// Can be used as a d3 projection context to convert a geojson feature to a SVG path
// In contrast to what d3-geo does by default, it will round all coordinates to one decimal place
// Adapted from https://github.com/d3/d3-geo/blob/8d3f3a98c034b087e2c808f752d2381d51c30015/src/path/string.js

// FUTURE: Once we update to d3-geo@^3.10, d3-geo can do this by default: https://github.com/d3/d3-geo/pull/272

// Rounds to one decimal place
const round = (x: number): number => Math.round(x * 10) / 10

export class GeoPathRoundingContext implements GeoContext {
_string: string = ""

beginPath(): void {
this._string = ""
}

moveTo(x: number, y: number): void {
this._string += `M${round(x)},${round(y)}`
}

lineTo(x: number, y: number): void {
this._string += `L${round(x)},${round(y)}`
}

arc(_x: number, _y: number, _radius: number): void {
throw new Error("Method not implemented.")
}

closePath(): void {
this._string += "Z"
}

result(): string {
return this._string
}
}
27 changes: 10 additions & 17 deletions packages/@ourworldindata/grapher/src/mapCharts/MapChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
DEFAULT_BOUNDS,
flatten,
getRelativeMouse,
identity,
sortBy,
guid,
minBy,
Expand All @@ -24,6 +23,7 @@ import {
HorizontalNumericColorLegend,
} from "../horizontalColorLegend/HorizontalColorLegends"
import { MapProjectionName, MapProjectionGeos } from "./MapProjections"
import { GeoPathRoundingContext } from "./GeoPathRoundingContext"
import { select } from "d3-selection"
import { easeCubic } from "d3-ease"
import { MapTooltip } from "./MapTooltip"
Expand Down Expand Up @@ -96,25 +96,18 @@ const geoPathCache = new Map<MapProjectionName, string[]>()
const geoPathsFor = (projectionName: MapProjectionName): string[] => {
if (geoPathCache.has(projectionName))
return geoPathCache.get(projectionName)!
const projectionGeo = MapProjectionGeos[projectionName]
const strs = GeoFeatures.map((feature) => {
const s = projectionGeo(feature) as string
const paths = s.split(/Z/).filter(identity)

const newPaths = paths.map((path) => {
const points = path.split(/[MLZ]/).filter((f: any) => f)
const rounded = points.map((point) =>
point
.split(/,/)
.map((v) => parseFloat(v).toFixed(1))
.join(",")
)
return "M" + rounded.join("L")
})

return newPaths.join("Z") + "Z"
// Use this context to round the path coordinates to a set number of decimal places
const ctx = new GeoPathRoundingContext()
const projectionGeo = MapProjectionGeos[projectionName].context(ctx)
const strs = GeoFeatures.map((feature) => {
ctx.beginPath() // restart the path
projectionGeo(feature)
return ctx.result()
})

projectionGeo.context(null) // reset the context for future calls

geoPathCache.set(projectionName, strs)
return geoPathCache.get(projectionName)!
}
Expand Down

0 comments on commit 57b8e6a

Please sign in to comment.