UNPKG

rs-react-native-map-clustering

Version:

React Native Map Clustering both for Android and iOS with TypeScript support

153 lines (152 loc) 5.67 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.returnMarkerStyle = exports.generateSpiral = exports.markerToGeoJSONFeature = exports.returnMapZoom = exports.calculateBBox = exports.isMarker = void 0; const geo_viewport_1 = __importDefault(require("@mapbox/geo-viewport")); const react_native_1 = require("react-native"); const { width, height } = react_native_1.Dimensions.get('window'); const isMarkerElement = (child) => { if (!child || typeof child !== 'object' || !('props' in child)) return false; const props = child.props; return !!props.coordinate && props.cluster !== false; }; exports.isMarker = isMarkerElement; const calculateBBox = (region) => { const lngD = region.longitudeDelta < 0 ? region.longitudeDelta + 360 : region.longitudeDelta; return [ region.longitude - lngD, region.latitude - region.latitudeDelta, region.longitude + lngD, region.latitude + region.latitudeDelta ]; }; exports.calculateBBox = calculateBBox; const returnMapZoom = (region, bBox, minZoom) => { const viewport = region.longitudeDelta >= 40 ? { zoom: minZoom } : geo_viewport_1.default.viewport(bBox, [width, height]); return viewport.zoom; }; exports.returnMapZoom = returnMapZoom; const markerToGeoJSONFeature = (marker, index) => { const { children: _, ...props } = marker.props; return { type: 'Feature', geometry: { coordinates: [props.coordinate.longitude, props.coordinate.latitude], type: 'Point' }, properties: { point_count: 0, index, ...props } }; }; exports.markerToGeoJSONFeature = markerToGeoJSONFeature; const ANGLE_CACHE = (() => { const map = new Map(); for (let i = 0; i < 200; i += 0.25) { const angle = 0.25 * (i * 0.5); map.set(angle.toFixed(2), { cos: Math.cos(angle), sin: Math.sin(angle) }); } return map; })(); const getCachedTrig = (angle) => { return ANGLE_CACHE.get(angle.toFixed(2)) ?? { cos: Math.cos(angle), sin: Math.sin(angle) }; }; const generateSpiral = (marker, clusterChildren, markers, index) => { const { properties, geometry } = marker; const count = properties.point_count; const centerLocation = geometry.coordinates; const centerPoint = { latitude: centerLocation[1], longitude: centerLocation[0] }; if (count > 500) { const sampleSize = 75; const sampleStep = Math.floor(count / sampleSize); const spiralDensity = 0.0006; const result = []; for (let i = 0; i < sampleSize; i++) { const child = clusterChildren[i * sampleStep]; if (!child?.properties || typeof child.properties.index !== 'number') continue; const angle = 0.25 * (i * 0.5); const { cos: cosAngle, sin: sinAngle } = getCachedTrig(angle); result.push({ index: child.properties.index, longitude: centerLocation[0] + spiralDensity * angle * sinAngle, latitude: centerLocation[1] + spiralDensity * angle * cosAngle, centerPoint }); } return result; } const maxSpiderPoints = count > 200 ? 75 : count > 100 ? 50 : count; const res = []; let start = 0; if (index > 0) { for (let i = 0; i < index; i++) { start += markers[i].properties.point_count || 0; } } const spiralDensity = count > 100 ? 0.0004 : count > 50 ? 0.0003 : 0.00025; const step = count > maxSpiderPoints ? Math.floor(count / maxSpiderPoints) : 1; const positions = Math.min(count, maxSpiderPoints); for (let i = 0; i < positions; i++) { const actualIndex = i * step; const angle = 0.25 * (actualIndex * 0.5); const { cos: cosAngle, sin: sinAngle } = getCachedTrig(angle); const child = clusterChildren[actualIndex + start]; if (!child?.properties || typeof child.properties.index !== 'number') continue; res.push({ index: child.properties.index, longitude: centerLocation[0] + spiralDensity * angle * sinAngle, latitude: centerLocation[1] + spiralDensity * angle * cosAngle, centerPoint }); } return res; }; exports.generateSpiral = generateSpiral; const MARKER_STYLES = { 4: { width: 54, height: 54, size: 40, fontSize: 16 }, 8: { width: 60, height: 60, size: 46, fontSize: 17 }, 10: { width: 66, height: 66, size: 50, fontSize: 17 }, 15: { width: 72, height: 72, size: 54, fontSize: 18 }, 25: { width: 78, height: 78, size: 58, fontSize: 19 }, 50: { width: 84, height: 84, size: 64, fontSize: 20 }, 100: { width: 90, height: 90, size: 70, fontSize: 22 } }; const DEFAULT_STYLE = { width: 48, height: 48, size: 36, fontSize: 15 }; const returnMarkerStyle = (points) => { if (MARKER_STYLES[points]) return MARKER_STYLES[points]; if (points > 100) return MARKER_STYLES[100]; if (points > 50) return MARKER_STYLES[50]; if (points > 25) return MARKER_STYLES[25]; if (points > 15) return MARKER_STYLES[15]; if (points > 10) return MARKER_STYLES[10]; if (points > 8) return MARKER_STYLES[8]; if (points > 4) return MARKER_STYLES[4]; return DEFAULT_STYLE; }; exports.returnMarkerStyle = returnMarkerStyle;