mirror of
https://github.com/AnmolSaini16/mapcn
synced 2026-04-25 16:14:54 +02:00
Updates: Example update
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -9,6 +9,13 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function slugify(text: string): string {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/(^-|-$)/g, "");
|
||||
}
|
||||
|
||||
// DocsHeader - Page title and description
|
||||
interface DocsHeaderProps {
|
||||
title: string;
|
||||
@@ -89,8 +96,9 @@ interface DocsSectionProps {
|
||||
}
|
||||
|
||||
export function DocsSection({ title, children }: DocsSectionProps) {
|
||||
const id = title ? slugify(title) : undefined;
|
||||
return (
|
||||
<section className="space-y-5">
|
||||
<section className="space-y-5 scroll-mt-20" id={id}>
|
||||
{title && (
|
||||
<h2 className="text-xl font-semibold tracking-tight text-primary">
|
||||
{title}
|
||||
|
||||
155
src/app/docs/_components/examples/layer-markers-example.tsx
Normal file
155
src/app/docs/_components/examples/layer-markers-example.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useId } from "react";
|
||||
import { Map, MapPopup, useMap } from "@/registry/map";
|
||||
|
||||
// Generate random points around NYC
|
||||
function generateRandomPoints(count: number) {
|
||||
const center = { lng: -73.98, lat: 40.75 };
|
||||
const features = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const lng = center.lng + (Math.random() - 0.5) * 0.15;
|
||||
const lat = center.lat + (Math.random() - 0.5) * 0.1;
|
||||
features.push({
|
||||
type: "Feature" as const,
|
||||
properties: {
|
||||
id: i,
|
||||
name: `Location ${i + 1}`,
|
||||
category: ["Restaurant", "Cafe", "Bar", "Shop"][
|
||||
Math.floor(Math.random() * 4)
|
||||
],
|
||||
},
|
||||
geometry: {
|
||||
type: "Point" as const,
|
||||
coordinates: [lng, lat],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "FeatureCollection" as const,
|
||||
features,
|
||||
};
|
||||
}
|
||||
|
||||
// 200 markers - would be slow with DOM markers, but fast with layers
|
||||
const pointsData = generateRandomPoints(200);
|
||||
|
||||
interface SelectedPoint {
|
||||
id: number;
|
||||
name: string;
|
||||
category: string;
|
||||
coordinates: [number, number];
|
||||
}
|
||||
|
||||
function MarkersLayer() {
|
||||
const { map, isLoaded } = useMap();
|
||||
const id = useId();
|
||||
const sourceId = `markers-source-${id}`;
|
||||
const layerId = `markers-layer-${id}`;
|
||||
const [selectedPoint, setSelectedPoint] = useState<SelectedPoint | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map || !isLoaded) return;
|
||||
|
||||
map.addSource(sourceId, {
|
||||
type: "geojson",
|
||||
data: pointsData,
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: layerId,
|
||||
type: "circle",
|
||||
source: sourceId,
|
||||
paint: {
|
||||
"circle-radius": 6,
|
||||
"circle-color": "#3b82f6",
|
||||
"circle-stroke-width": 2,
|
||||
"circle-stroke-color": "#ffffff",
|
||||
// add more paint properties here to customize the appearance of the markers
|
||||
},
|
||||
});
|
||||
|
||||
const handleClick = (
|
||||
e: maplibregl.MapMouseEvent & {
|
||||
features?: maplibregl.MapGeoJSONFeature[];
|
||||
}
|
||||
) => {
|
||||
if (!e.features?.length) return;
|
||||
|
||||
const feature = e.features[0];
|
||||
const coords = (feature.geometry as GeoJSON.Point).coordinates as [
|
||||
number,
|
||||
number
|
||||
];
|
||||
|
||||
setSelectedPoint({
|
||||
id: feature.properties?.id,
|
||||
name: feature.properties?.name,
|
||||
category: feature.properties?.category,
|
||||
coordinates: coords,
|
||||
});
|
||||
};
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
map.getCanvas().style.cursor = "pointer";
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
map.getCanvas().style.cursor = "";
|
||||
};
|
||||
|
||||
map.on("click", layerId, handleClick);
|
||||
map.on("mouseenter", layerId, handleMouseEnter);
|
||||
map.on("mouseleave", layerId, handleMouseLeave);
|
||||
|
||||
return () => {
|
||||
map.off("click", layerId, handleClick);
|
||||
map.off("mouseenter", layerId, handleMouseEnter);
|
||||
map.off("mouseleave", layerId, handleMouseLeave);
|
||||
|
||||
try {
|
||||
if (map.getLayer(layerId)) map.removeLayer(layerId);
|
||||
if (map.getSource(sourceId)) map.removeSource(sourceId);
|
||||
} catch {
|
||||
// ignore cleanup errors
|
||||
}
|
||||
};
|
||||
}, [map, isLoaded, sourceId, layerId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedPoint && (
|
||||
<MapPopup
|
||||
longitude={selectedPoint.coordinates[0]}
|
||||
latitude={selectedPoint.coordinates[1]}
|
||||
onClose={() => setSelectedPoint(null)}
|
||||
closeOnClick={false}
|
||||
focusAfterOpen={false}
|
||||
offset={10}
|
||||
closeButton
|
||||
>
|
||||
<div className="min-w-[140px]">
|
||||
<p className="font-medium">{selectedPoint.name}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{selectedPoint.category}
|
||||
</p>
|
||||
</div>
|
||||
</MapPopup>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function LayerMarkersExample() {
|
||||
return (
|
||||
<div className="h-[400px] w-full">
|
||||
<Map center={[-73.98, 40.75]} zoom={11}>
|
||||
<MarkersLayer />
|
||||
</Map>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { ComponentPreview } from "../_components/component-preview";
|
||||
import { AdvancedUsageExample } from "../_components/examples/advanced-usage-example";
|
||||
import { CustomLayerExample } from "../_components/examples/custom-layer-example";
|
||||
import { LayerMarkersExample } from "../_components/examples/layer-markers-example";
|
||||
import { CodeBlock } from "../_components/code-block";
|
||||
import { getExampleSource } from "@/lib/get-example-source";
|
||||
import { Metadata } from "next";
|
||||
@@ -16,12 +17,11 @@ export const metadata: Metadata = {
|
||||
title: "Advanced Usage",
|
||||
};
|
||||
|
||||
const refCode = `import { Map } from "@/components/ui/map";
|
||||
const refCode = `import { Map, type MapRef } from "@/components/ui/map";
|
||||
import { useRef } from "react";
|
||||
import type MapLibreGL from "maplibre-gl";
|
||||
|
||||
function MyMapComponent() {
|
||||
const mapRef = useRef<MapLibreGL.Map>(null);
|
||||
const mapRef = useRef<MapRef>(null);
|
||||
|
||||
const handleFlyTo = () => {
|
||||
// Access the MapLibre GL map instance via ref
|
||||
@@ -65,6 +65,7 @@ function MapEventListener() {
|
||||
export default function AdvancedPage() {
|
||||
const advancedSource = getExampleSource("advanced-usage-example.tsx");
|
||||
const customLayerSource = getExampleSource("custom-layer-example.tsx");
|
||||
const layerMarkersSource = getExampleSource("layer-markers-example.tsx");
|
||||
|
||||
return (
|
||||
<DocsLayout
|
||||
@@ -132,6 +133,19 @@ export default function AdvancedPage() {
|
||||
<CustomLayerExample />
|
||||
</ComponentPreview>
|
||||
|
||||
<DocsSection title="Example: Markers via Layers">
|
||||
<p>
|
||||
When displaying hundreds or thousands of markers, use GeoJSON layers
|
||||
instead of DOM-based <DocsCode>MapMarker</DocsCode> components. This
|
||||
approach renders markers on the WebGL canvas, providing significantly
|
||||
better performance.
|
||||
</p>
|
||||
</DocsSection>
|
||||
|
||||
<ComponentPreview code={layerMarkersSource}>
|
||||
<LayerMarkersExample />
|
||||
</ComponentPreview>
|
||||
|
||||
<DocsSection title="Extend to Build">
|
||||
<p>You can extend this to build custom features like:</p>
|
||||
<ul>
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { DocsLayout, DocsSection, DocsCode } from "../_components/docs";
|
||||
import {
|
||||
DocsLayout,
|
||||
DocsSection,
|
||||
DocsCode,
|
||||
DocsNote,
|
||||
DocsLink,
|
||||
} from "../_components/docs";
|
||||
import { ComponentPreview } from "../_components/component-preview";
|
||||
import { MarkersExample } from "../_components/examples/markers-example";
|
||||
import { PopupExample } from "../_components/examples/popup-example";
|
||||
@@ -13,7 +19,9 @@ export const metadata: Metadata = {
|
||||
export default function MarkersPage() {
|
||||
const markersSource = getExampleSource("markers-example.tsx");
|
||||
const popupSource = getExampleSource("popup-example.tsx");
|
||||
const draggableMarkerSource = getExampleSource("draggable-marker-example.tsx");
|
||||
const draggableMarkerSource = getExampleSource(
|
||||
"draggable-marker-example.tsx"
|
||||
);
|
||||
|
||||
return (
|
||||
<DocsLayout
|
||||
@@ -30,6 +38,16 @@ export default function MarkersPage() {
|
||||
</p>
|
||||
</DocsSection>
|
||||
|
||||
<DocsNote>
|
||||
<strong>Performance tip:</strong> <DocsCode>MapMarker</DocsCode> is
|
||||
DOM-based and works best for a few dozen of markers. For larger
|
||||
datasets, see the{" "}
|
||||
<DocsLink href="/docs/advanced-usage#example-markers-via-layers">
|
||||
GeoJSON layers example
|
||||
</DocsLink>{" "}
|
||||
instead. Rendering many DOM markers can make the browser sluggish.
|
||||
</DocsNote>
|
||||
|
||||
<DocsSection title="Basic Example">
|
||||
<p>
|
||||
Simple markers with tooltips and popups showing location information.
|
||||
|
||||
@@ -857,7 +857,7 @@ type MapRouteProps = {
|
||||
};
|
||||
|
||||
function MapRoute({
|
||||
id,
|
||||
id: propId,
|
||||
coordinates,
|
||||
color = "#4285F4",
|
||||
width = 3,
|
||||
@@ -870,8 +870,9 @@ function MapRoute({
|
||||
}: MapRouteProps) {
|
||||
const { map, isLoaded } = useMap();
|
||||
const autoId = useId();
|
||||
const sourceId = id ?? `route-source-${autoId}`;
|
||||
const layerId = id ?? `route-layer-${autoId}`;
|
||||
const id = propId ?? autoId;
|
||||
const sourceId = `route-source-${id}`;
|
||||
const layerId = `route-layer-${id}`;
|
||||
|
||||
// Add source and layer on mount
|
||||
useEffect(() => {
|
||||
@@ -1283,3 +1284,5 @@ export {
|
||||
MapRoute,
|
||||
MapClusterLayer,
|
||||
};
|
||||
|
||||
export type { MapRef };
|
||||
|
||||
Reference in New Issue
Block a user