mapbox-gl-draw-snap-mode
Version:
Snapping mode for mapbox-gl-draw
294 lines (267 loc) • 14.2 kB
HTML
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mapbox Gl Draw Snap Mode (Demo)</title>
<style>
@import "https://unpkg.com/modern-normalize@1.0.0/modern-normalize.css";
@import url("https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css");
@import url("https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.0/mapbox-gl-draw.css");
@import url("https://unpkg.com/nprogress@0.2.0/nprogress.css");
h1,
p {
font-family: Lato;
}
.map-wrapper {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
border-radius: inherit;
}
#map {
width: 100%;
height: 100%;
}
.mapboxgl-ctrl-group input[type="checkbox"] {
width: 29px;
height: 29px;
overflow: hidden;
display: block;
padding: 0;
outline: none;
border: 0;
box-sizing: border-box;
background-color: transparent;
cursor: pointer;
margin: 0;
border-bottom: 1px solid #ccc;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.mapboxgl-ctrl-group input[type="checkbox"]:last-of-type {
border-bottom: none;
}
.mapboxgl-ctrl-group input[type="checkbox"]:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.mapboxgl-ctrl-group input[type="checkbox"]:checked {
background-color: rgba(0, 0, 0, 0.15);
}
.mapboxgl-ctrl-group input[type="checkbox"]:after {
content: "";
background-repeat: no-repeat;
background-position: center;
background-size: 18px;
border-radius: 4px;
width: 100%;
height: 100%;
display: inline-block;
}
.mapboxgl-ctrl-group input[type="checkbox"].snap_mode.snap:after {
background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Icons' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 32 32' style='enable-background:new 0 0 32 32;' xml:space='preserve'%3E%3Cpath d='M26.5,10l-4.8-4.8c0,0,0,0,0,0s0,0,0,0l-3-3c-0.4-0.4-1-0.4-1.4,0l-4.6,4.6c-0.4,0.4-0.4,1,0,1.4l7.8,7.8 c1.3,1.3,1.3,3.3,0.1,4.5c-0.6,0.6-1.4,0.9-2.2,0.9c-0.8,0-1.7-0.4-2.3-1l-4.8-4.8c0,0,0,0,0,0s0,0,0,0l-3-3c-0.4-0.4-1-0.4-1.4,0 l-4.6,4.6c-0.4,0.4-0.4,1,0,1.4l7.8,7.8c2.3,2.3,5.2,3.5,8.4,3.6c0.1,0,0.1,0,0.2,0c3.1,0,5.9-1.2,8.1-3.3 C31.2,22.2,31.1,14.7,26.5,10z M18,4.4L19.6,6l-3.2,3.2l-1.6-1.6L18,4.4z M7.6,14.8l1.6,1.6L6,19.6L4.4,18L7.6,14.8z'/%3E%3C/svg%3E%0A");
}
.mapboxgl-ctrl-group input[type="checkbox"].snap_mode.grid:after {
background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' width='16px' height='16px' viewBox='0 0 16 16' id='svg2' version='1.1' inkscape:version='1.0.1 (3bc2e813f5, 2020-09-07)' sodipodi:docname='grid.svg'%3E%3Cdefs id='defs4' /%3E%3Csodipodi:namedview id='base' pagecolor='%23ffffff' bordercolor='%23666666' borderopacity='1.0' inkscape:pageopacity='0.0' inkscape:pageshadow='2' inkscape:zoom='22.627417' inkscape:cx='16.97478' inkscape:cy='4.108315' inkscape:document-units='px' inkscape:current-layer='g6148-2' showgrid='true' units='px' inkscape:window-width='1920' inkscape:window-height='1021' inkscape:window-x='0' inkscape:window-y='0' inkscape:window-maximized='1' inkscape:snap-bbox='false' inkscape:bbox-paths='false' inkscape:bbox-nodes='false' inkscape:snap-bbox-edge-midpoints='true' inkscape:snap-bbox-midpoints='true' inkscape:document-rotation='0'%3E%3Cinkscape:grid type='xygrid' id='grid3336' /%3E%3C/sodipodi:namedview%3E%3Cg inkscape:label='Layer 1' inkscape:groupmode='layer' id='layer1' transform='translate(0,-1036.3622)'%3E%3Cg transform='translate(78,-251.00067)' id='g6148-2'%3E%3Cpath style='color:%23000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:%23000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:%23000000;solid-opacity:1;fill:%23000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate' d='m -76.5,1287.8629 v 1 h -1 v 1 h 1 v 3 h -1 v 1 h 1 v 3 h -1 v 1 h 1 v 3 h -1 v 1 h 1 v 1 h 1 v -1 h 3 v 1 h 1 v -1 h 3 v 1 h 1 v -1 h 3 v 1 h 1 v -1 h 1 v -1 h -1 v -3 h 1 v -1 h -1 v -3 h 1 v -1 h -1 v -3 h 1 v -1 h -1 v -1 h -1 v 1 h -3 v -1 h -1 v 1 h -3 v -1 h -1 v 1 h -3 v -1 z m 1,2 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z m -8,4 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z m -8,4 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z m 4,0 h 3 v 3 h -3 z' id='path7088-6-0' /%3E%3C/g%3E%3C/g%3E%3Cmetadata id='metadata8'%3E%3Crdf:RDF%3E%3Crdf:Description about='https://iconscout.com/legal%23licenses' dc:title='Grid, Line, Streamline, Layout, Outline' dc:description='Grid, Line, Streamline, Layout, Outline' dc:publisher='Iconscout' dc:date='2016-12-14' dc:format='image/svg+xml' dc:language='en'%3E%3Cdc:creator%3E%3Crdf:Bag%3E%3Crdf:li%3EMohit Gandhi%3C/rdf:li%3E%3C/rdf:Bag%3E%3C/dc:creator%3E%3C/rdf:Description%3E%3Ccc:Work rdf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3C/svg%3E%0A");
}
</style>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.js"></script>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<script src="https://unpkg.com/mapbox-gl-draw-snap-mode"></script>
<!-- <script src="index.js"></script> -->
<script type="module">
import nprogress from "https://cdn.skypack.dev/nprogress";
window.nprogress = nprogress;
nprogress.start();
</script>
<script type="text/babel" data-type="module">
import React, {
useRef,
useState,
useEffect,
} from "https://cdn.skypack.dev/react";
import ReactDOM from "https://cdn.skypack.dev/react-dom";
const {
SnapPolygonMode,
SnapPointMode,
SnapLineMode,
SnapModeDrawStyles,
SnapDirectSelect,
} = mapboxGlDrawSnapMode;
console.log({
mapboxGlDrawSnapMode,
SnapPolygonMode,
SnapPointMode,
SnapLineMode,
SnapModeDrawStyles,
SnapDirectSelect,
});
class extendDrawBarCheckboxes {
constructor(opt) {
let ctrl = this;
ctrl.checkboxes = opt.checkboxes || [];
ctrl.onRemoveOrig = opt.draw.onRemove;
}
onAdd(map) {
let ctrl = this;
ctrl.map = map;
ctrl._container = document.createElement("div");
ctrl._container.className = "mapboxgl-ctrl-group mapboxgl-ctrl";
ctrl.elContainer = ctrl._container;
ctrl.checkboxes.forEach((b) => {
ctrl.addCheckbox(b);
});
return ctrl._container;
}
onRemove(map) {
ctrl.checkboxes.forEach((b) => {
ctrl.removeButton(b);
});
ctrl.onRemoveOrig(map);
}
addCheckbox(opt) {
let ctrl = this;
const elCheckbox = document.createElement("input");
elCheckbox.setAttribute("type", "checkbox");
elCheckbox.setAttribute("title", opt.title);
elCheckbox.checked = opt.initialState === "checked";
elCheckbox.className = "mapbox-gl-draw_ctrl-draw-btn";
if (opt.classes instanceof Array) {
opt.classes.forEach((c) => {
elCheckbox.classList.add(c);
});
}
elCheckbox.addEventListener(opt.on, opt.action);
ctrl.elContainer.appendChild(elCheckbox);
opt.elCheckbox = elCheckbox;
}
removeButton(opt) {
opt.elCheckbox.removeEventListener(opt.on, opt.action);
opt.elCheckbox.remove();
}
}
export default function App() {
if (mapboxgl.getRTLTextPluginStatus() === "unavailable")
mapboxgl.setRTLTextPlugin(
"https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-rtl-text/v0.2.3/mapbox-gl-rtl-text.js",
(err) => {
err && console.error(err);
},
true
);
let mapRef = useRef(null);
useEffect(() => {
const map = new mapboxgl.Map({
container: mapRef.current || "",
style: `https://map.ir/vector/styles/main/mapir-xyz-light-style.json`,
center: [51.3857, 35.6102],
zoom: 10,
pitch: 0,
interactive: true,
hash: true,
attributionControl: true,
transformRequest: (url) => {
return {
url: url,
headers: {
"x-api-key":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRiZWU0YWU4OTk4OTA3MmQ3OTFmMjQ4ZDE5N2VhZTgwZWU2NTUyYjhlYjczOWI2NDdlY2YyYzIzNWRiYThiMzIzOTM5MDkzZDM0NTY2MmU3In0.eyJhdWQiOiI5NDMyIiwianRpIjoiZGJlZTRhZTg5OTg5MDcyZDc5MWYyNDhkMTk3ZWFlODBlZTY1NTJiOGViNzM5YjY0N2VjZjJjMjM1ZGJhOGIzMjM5MzkwOTNkMzQ1NjYyZTciLCJpYXQiOjE1OTA4MjU0NzIsIm5iZiI6MTU5MDgyNTQ3MiwiZXhwIjoxNTkzNDE3NDcyLCJzdWIiOiIiLCJzY29wZXMiOlsiYmFzaWMiXX0.M_z4xJlJRuYrh8RFe9UrW89Y_XBzpPth4yk3hlT-goBm8o3x8DGCrSqgskFfmJTUD2wC2qSoVZzQKB67sm-swtD5fkxZO7C0lBCMAU92IYZwCdYehIOtZbP5L1Lfg3C6pxd0r7gQOdzcAZj9TStnKBQPK3jSvzkiHIQhb6I0sViOS_8JceSNs9ZlVelQ3gs77xM2ksWDM6vmqIndzsS-5hUd-9qdRDTLHnhdbS4_UBwNDza47Iqd5vZkBgmQ_oDZ7dVyBuMHiQFg28V6zhtsf3fijP0UhePCj4GM89g3tzYBOmuapVBobbX395FWpnNC3bYg7zDaVHcllSUYDjGc1A",
"Mapir-SDK": "reactjs",
},
};
},
});
const draw = new MapboxDraw({
modes: {
...MapboxDraw.modes,
draw_point: SnapPointMode,
draw_polygon: SnapPolygonMode,
draw_line_string: SnapLineMode,
direct_select: SnapDirectSelect,
},
styles: SnapModeDrawStyles,
userProperties: true,
snap: true,
// overlap: false,
// snapOptions: {
// snapPx: 15,
// snapToMidPoints: true,
// snapVertexPriorityDistance: 0.0025,
// snapGetFeatures: (map, draw) => [
// ...map.queryRenderedFeatures({
// layers: ["not-editable-layer-name"],
// }),
// ...draw.getAll().features,
// ],
// },
guides: false,
});
map.once("load", () => {
nprogress.done();
map.resize();
const SnapOptionsBar = new extendDrawBarCheckboxes({
draw: draw,
checkboxes: [
{
on: "change",
action: (e) => {
draw.options.snap = e.target.checked;
},
classes: ["snap_mode", "snap"],
title: "Snap when Draw",
initialState: "checked",
},
{
on: "change",
action: (e) => {
draw.options.guides = e.target.checked;
},
classes: ["snap_mode", "grid"],
title: "Show Guides",
},
],
});
map.addControl(draw, "top-right");
map.addControl(SnapOptionsBar, "top-right");
draw.set({
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
id: "example-id",
geometry: {
type: "Polygon",
coordinates: [
[
[51.41742415918904, 35.73019558439101],
[51.31319413385742, 35.702773908694724],
[51.378997493472525, 35.665562843119986],
[51.45008537540798, 35.67776544979942],
[51.46619566741822, 35.70822028156377],
[51.41742415918904, 35.73019558439101],
],
],
},
},
],
});
});
}, []);
return (
<div className="map-wrapper">
<div id="map" ref={mapRef} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>