UNPKG

geojson-map-fit-mercator

Version:

Finds the optimal bearing, zoom and center point for fitting a set of GeoJSON features in a Mapbox GL or LibreMap Mercator map.

1 lines 16.3 kB
{"version":3,"file":"index.cjs","sources":["../src/screen.ts","../src/index.ts"],"sourcesContent":["import type { Feature, Polygon, Position } from 'geojson';\nimport { SphericalMercator } from '@mapbox/sphericalmercator';\nimport { XY, LngLat, mapFitPadding, rectangleOrientation } from './types';\nimport { getCoords } from '@turf/invariant';\n\nexport function findScreenZoom(\n paddedScreenDimensions: XY,\n paddedScreenRatio: number,\n boundingRectangleOrientation: rectangleOrientation,\n maxZoom: number,\n floatZoom: boolean,\n merc: SphericalMercator,\n): number {\n const { shortSide, longSide } = boundingRectangleOrientation;\n const longSideCoords = getCoords(longSide!);\n const shortSideCoords = getCoords(shortSide!);\n\n // We need to determine the ratio required for the zoom level. To do this we are going to approximate the length\n // of the longest and shortest sides of the polygon in pixels (This doesn't account for projection distortion but is\n // a good estimation)\n const longPx: [XY, XY] = [merc.px(longSideCoords[0], maxZoom), merc.px(longSideCoords[1], maxZoom)];\n const shortPx: [XY, XY] = [merc.px(shortSideCoords[0], maxZoom), merc.px(shortSideCoords[1], maxZoom)];\n\n // Because these points aren't aligned to the axis, we use the Pythagorean theorem to calculate the distance\n const longPxX = longPx[0][0] - longPx[1][0];\n const longPxY = longPx[0][1] - longPx[1][1];\n const shortPxX = shortPx[0][0] - shortPx[1][0];\n const shortPxY = shortPx[0][1] - shortPx[1][1];\n const longPxDistance = Math.sqrt(Math.pow(longPxX, 2) + Math.pow(longPxY, 2));\n const shortPxDistance = Math.sqrt(Math.pow(shortPxX, 2) + Math.pow(shortPxY, 2));\n\n let xPx = longPxDistance;\n let yPx = shortPxDistance;\n\n // If the screen is taller than it is wide, swap the x and y values\n if (paddedScreenRatio < 1) {\n xPx = shortPxDistance;\n yPx = longPxDistance;\n }\n\n const ratios: XY = [Math.abs(xPx / paddedScreenDimensions[0]), Math.abs(yPx / paddedScreenDimensions[1])];\n const zoom = Math.min(maxZoom - Math.log(ratios[0]) / Math.log(2), maxZoom - Math.log(ratios[1]) / Math.log(2));\n return floatZoom ? zoom : Math.floor(zoom);\n}\n\nexport function findScreenBearing(\n boundingRectangleBearing: number,\n preferredBearing: number,\n screenRatio: number,\n): number {\n let bearing = boundingRectangleBearing;\n // Rotate the bearing by 90 degrees if the screen is wider than it is tall\n if (screenRatio > 1) {\n bearing = bearing + (90 % 360);\n }\n\n // Rotate the bearing 180 degrees if the preferred bearing is on the opposite side of the screen\n if (bearing < (preferredBearing - 90) % 360 || bearing > (preferredBearing + 90) % 360) {\n bearing = (bearing + 180) % 360;\n }\n\n return bearing;\n}\n\nexport function findScreenCenter(\n boundingRectangle: Feature<Polygon>,\n bearing: number,\n zoom: number,\n padding: mapFitPadding,\n merc: SphericalMercator,\n): LngLat {\n const { left = 0, right = 0, top = 0, bottom = 0 } = padding;\n\n // Use the bounding rectangle's pixel location to calculate the centre of the\n // map. This allows us to account for mercator projection distortion.\n const coords = getCoords(boundingRectangle);\n const uniqCoords = coords[0].reduce((uniq: Position[], coord: [number, number]) => {\n if (!uniq.find((c) => c[0] === coord[0] && c[1] === coord[1])) {\n uniq.push(coord);\n }\n return uniq;\n }, []);\n\n const sumCoords = uniqCoords.reduce(\n (acc: [number, number], coord: [number, number]) => {\n const [x, y] = merc.px(coord as LngLat, zoom);\n acc[0] = acc[0] + x;\n acc[1] = acc[1] + y;\n return acc;\n },\n [0, 0],\n );\n\n const midX = sumCoords[0] / uniqCoords.length;\n const midY = sumCoords[1] / uniqCoords.length;\n\n const xPaddingOffset = right - left;\n const yPaddingOffset = bottom - top;\n\n const bearingRadians = bearing * (Math.PI / 180);\n\n const centerXOffset = xPaddingOffset * Math.cos(bearingRadians) - yPaddingOffset * Math.sin(bearingRadians);\n const centerYOffset = xPaddingOffset * Math.sin(bearingRadians) + yPaddingOffset * Math.cos(bearingRadians);\n\n return merc.ll([midX + centerXOffset, midY + centerYOffset], zoom);\n}\n","import { SphericalMercator } from '@mapbox/sphericalmercator';\nimport { bearing } from '@turf/bearing';\nimport { convex } from '@turf/convex';\nimport { getCoords } from '@turf/invariant';\nimport type { Polygon, Feature, FeatureCollection, LineString } from 'geojson';\nimport { findScreenCenter, findScreenBearing, findScreenZoom } from './screen';\nimport { XY, mapFitPadding, mapFitOptions, mapFitResult, rectangleOrientation, boundingOrientation } from './types';\nimport transformRotate from '@turf/transform-rotate';\nimport centroid from '@turf/centroid';\nimport { segmentReduce } from '@turf/meta';\nimport polygonToLine from '@turf/polygon-to-line';\nimport envelope from '@turf/envelope';\nimport { length } from '@turf/length';\nimport type { AllGeoJSON } from '@turf/helpers';\n\nfunction mapFitFeatures(\n features: FeatureCollection,\n screenDimensions: XY,\n options: mapFitOptions = {} as mapFitOptions,\n): mapFitResult {\n // Set default options\n const {\n tileSize = 512,\n preferredBearing = 0,\n padding = {} as mapFitPadding,\n maxZoom = 23,\n floatZoom = true,\n } = options;\n\n // Create a mercator projection. SphericalMercator caches its calculations so it's safe to create a new instance each run\n const merc: SphericalMercator = new SphericalMercator({ size: tileSize, antimeridian: true });\n const [screenWidth, screenHeight] = screenDimensions;\n const { left = 0, right = 0, top = 0, bottom = 0 } = padding;\n const paddedScreenWidth = screenWidth - left - right;\n const paddedScreenHeight = screenHeight - top - bottom;\n const paddedScreenRatio = paddedScreenWidth / paddedScreenHeight;\n\n // Calculate the bounding rectangle of the features\n const {\n boundsOrientation: { orientation, bearing: baseBearing },\n boundingRectangle,\n } = minimumBoundingRectangle(features);\n\n if (!boundingRectangle) {\n throw new Error('Unable to calculate bounding rectangle');\n }\n\n // Determine how to fit the bounding rectangle to the screen\n const zoom = findScreenZoom(\n [paddedScreenWidth, paddedScreenHeight],\n paddedScreenRatio,\n orientation,\n maxZoom,\n floatZoom,\n merc,\n );\n const bearing = findScreenBearing(baseBearing!, preferredBearing, paddedScreenRatio);\n const center = findScreenCenter(boundingRectangle, bearing, zoom, padding, merc);\n\n return { bearing, zoom, center };\n}\n\nexport function minimumBoundingRectangle(geoJsonInput: AllGeoJSON): {\n boundsOrientation: boundingOrientation;\n boundingRectangle: Feature<Polygon>;\n} {\n // Create a convex hull around the input geometry\n const convexHull = convex(geoJsonInput);\n if (!convexHull) throw new Error(\"Can't determine minimumBoundingRectangle for given geometry\");\n\n // Break the hull into its constituent edges and find the smallest\n const hullLines = polygonToLine(convexHull);\n const smallestHullBoundsOrientation = segmentReduce(\n hullLines,\n (smallestEnvelope: boundingOrientation | undefined, segment) => {\n return smallestHullEnvelopeReducer(smallestEnvelope, segment!, convexHull);\n },\n { bearing: undefined, orientation: { shortSide: undefined, longSide: undefined }, envelope: undefined },\n );\n\n const boundingRectangle = transformRotate(\n envelope(smallestHullBoundsOrientation.envelope!),\n smallestHullBoundsOrientation.bearing!,\n {\n pivot: centroid(convexHull),\n },\n );\n\n return {\n boundsOrientation: smallestHullBoundsOrientation,\n boundingRectangle,\n };\n}\n\nfunction smallestHullEnvelopeReducer(\n smallestEnvelope: boundingOrientation | undefined,\n segment: Feature<LineString>,\n hull: Feature<Polygon>,\n): boundingOrientation {\n const segmentCoords = getCoords(segment);\n const segmentBearing = bearing(segmentCoords[0], segmentCoords[1]);\n\n const rotatedHull = transformRotate(hull, -1.0 * segmentBearing, {\n pivot: centroid(hull),\n });\n const envelopeOfHull = envelope(rotatedHull);\n\n const rectangleOrientation = findRectangleOrientation(envelopeOfHull);\n const shortSideLength = length(rectangleOrientation.shortSide!);\n\n if (\n smallestEnvelope!.orientation.shortSide == undefined ||\n shortSideLength < length(smallestEnvelope!.orientation.shortSide)\n ) {\n return { bearing: segmentBearing, orientation: rectangleOrientation, envelope: envelopeOfHull };\n }\n\n return smallestEnvelope!;\n}\n\nfunction findRectangleOrientation(rectangle: Feature<Polygon>): rectangleOrientation {\n const rectangleSides = polygonToLine(rectangle);\n return segmentReduce(\n rectangleSides,\n (sideOrientation: rectangleOrientation | undefined, segment): rectangleOrientation => {\n const segmentLength = length(segment!);\n\n if (sideOrientation!.shortSide == undefined || length(sideOrientation!.shortSide) > segmentLength) {\n sideOrientation!.shortSide = segment!;\n }\n\n if (sideOrientation!.longSide == undefined || length(sideOrientation!.longSide) < segmentLength) {\n sideOrientation!.longSide = segment!;\n }\n\n return sideOrientation!;\n },\n { shortSide: undefined, longSide: undefined },\n );\n}\n\nexport { mapFitFeatures };\n"],"names":["getCoords","SphericalMercator","convex","segmentReduce","bearing","length"],"mappings":"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"}