You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Google Maps的Drawing Manager实现类似Esri工具的曲线及贝塞尔曲线绘制?

How to Add Curve & Bezier Curve Tools to Google Maps Drawing Manager

Got it, let's figure out how to replicate that Esri drawing toolbar's curve and Bezier curve functionality using Google Maps' Drawing Manager. The default Drawing Manager doesn't ship with these tools out of the box, but we can build them ourselves with some custom code—here's a step-by-step breakdown:

1. Set Up the Base Map & Drawing Manager

First, we'll initialize our map and the default Drawing Manager with standard tools (markers, polylines, etc.). We'll add our custom curve tools to this setup later.

// Initialize the map
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: -34.397, lng: 150.644 },
  zoom: 8,
});

// Initialize Drawing Manager with default tools
const drawingManager = new google.maps.drawing.DrawingManager({
  drawingMode: null,
  drawingControl: true,
  drawingControlOptions: {
    position: google.maps.ControlPosition.TOP_CENTER,
    drawingModes: [
      google.maps.drawing.OverlayType.MARKER,
      google.maps.drawing.OverlayType.POLYLINE,
      google.maps.drawing.OverlayType.POLYGON,
    ],
  },
});
drawingManager.setMap(map);

2. Add Custom UI Buttons for Curve Tools

The default Drawing Manager doesn't include curve/Bezier options, so we'll create custom buttons and add them to the existing drawing control container.

// Grab the existing drawing control container
const drawingControlContainer = document.querySelector(".gm-drawing-control");

// Create Freehand Curve button
const freehandBtn = document.createElement("button");
freehandBtn.textContent = "Freehand Curve";
freehandBtn.className = "gm-ui-hover-effect";
drawingControlContainer.appendChild(freehandBtn);

// Create Bezier Curve button
const bezierBtn = document.createElement("button");
bezierBtn.textContent = "Bezier Curve";
bezierBtn.className = "gm-ui-hover-effect";
drawingControlContainer.appendChild(bezierBtn);

3. Implement Freehand Curve Drawing

For freehand curves (like drawing a smooth line with your mouse), we'll listen to mouse events to collect points as the user drags, then connect those points with a polyline.

let isDrawingFreehand = false;
let freehandPath = [];
let freehandPolyline = null;

// Toggle freehand drawing mode on button click
freehandBtn.addEventListener("click", () => {
  isDrawingFreehand = !isDrawingFreehand;
  freehandBtn.style.backgroundColor = isDrawingFreehand ? "#4285F4" : "";
  freehandBtn.style.color = isDrawingFreehand ? "white" : "";

  if (isDrawingFreehand) {
    map.addListener("mousedown", startFreehandDraw);
  } else {
    google.maps.event.clearListeners(map, "mousedown");
  }
});

// Start collecting points on mouse down
function startFreehandDraw(e) {
  freehandPath = [e.latLng];
  freehandPolyline = new google.maps.Polyline({
    path: freehandPath,
    map: map,
    strokeColor: "#00FF00",
    strokeOpacity: 1.0,
    strokeWeight: 2,
  });

  map.addListener("mousemove", updateFreehandDraw);
  map.addListener("mouseup", endFreehandDraw);
}

// Update the curve as the user moves the mouse
function updateFreehandDraw(e) {
  freehandPath.push(e.latLng);
  freehandPolyline.setPath(freehandPath);
}

// Finalize the freehand curve when mouse is released
function endFreehandDraw() {
  isDrawingFreehand = false;
  freehandBtn.style.backgroundColor = "";
  freehandBtn.style.color = "";
  google.maps.event.clearListeners(map, "mousemove");
  google.maps.event.clearListeners(map, "mouseup");
}

4. Implement Bezier Curve Drawing

Google Maps doesn't support native Bezier curves, so we'll approximate them by calculating a dense set of points along the Bezier path and connecting them with a polyline. We'll use quadratic Bezier (needs 3 points: start, control, end) for simplicity.

let isDrawingBezier = false;
let bezierPoints = [];
let previewPolyline = null;

// Toggle Bezier drawing mode on button click
bezierBtn.addEventListener("click", () => {
  isDrawingBezier = !isDrawingBezier;
  bezierPoints = [];
  bezierBtn.style.backgroundColor = isDrawingBezier ? "#4285F4" : "";
  bezierBtn.style.color = isDrawingBezier ? "white" : "";

  if (isDrawingBezier) {
    map.addListener("mousedown", startBezierDraw);
  } else {
    google.maps.event.clearListeners(map, "mousedown");
    if (previewPolyline) previewPolyline.setMap(null);
  }
});

// Collect Bezier points on mouse click
function startBezierDraw(e) {
  const point = e.latLng;
  bezierPoints.push(point);

  // Add a marker to indicate the point
  new google.maps.Marker({
    position: point,
    map: map,
    icon: {
      url: bezierPoints.length === 1 
        ? "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ccircle%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%228%22%20fill%3D%22%234285F4%22%20stroke%3D%22white%22%20stroke-width%3D%222%22%2F%3E%3C%2Fsvg%3E"
        : "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ccircle%20cx%3D%228%22%20cy%3D%228%22%20r%3D%226%22%20fill%3D%22%23FBBC05%22%20stroke%3D%22white%22%20stroke-width%3D%222%22%2F%3E%3C%2Fsvg%3E",
      anchor: new google.maps.Point(bezierPoints.length === 1 ? 10 : 8, bezierPoints.length === 1 ? 10 : 8),
    },
  });

  // Handle different stages of Bezier drawing
  if (bezierPoints.length === 1) {
    // First point: listen for mouse move to preview the control line
    map.addListener("mousemove", previewBezierControl);
    map.addListener("mouseup", addBezierControlPoint);
  } else if (bezierPoints.length === 3) {
    // All 3 points collected: generate and draw the final Bezier curve
    const curvePoints = generateQuadraticBezier(bezierPoints[0], bezierPoints[1], bezierPoints[2]);
    new google.maps.Polyline({
      path: curvePoints,
      map: map,
      strokeColor: "#FF0000",
      strokeOpacity: 1.0,
      strokeWeight: 2,
    });
    // Reset drawing state
    endBezierDraw();
  }
}

// Preview the control line while moving the mouse
function previewBezierControl(e) {
  if (previewPolyline) previewPolyline.setMap(null);
  previewPolyline = new google.maps.Polyline({
    path: [bezierPoints[0], e.latLng],
    map: map,
    strokeColor: "#AAAAAA",
    strokeOpacity: 0.7,
    strokeWeight: 1,
    dashStyle: "dash",
  });
}

// Add the control point on mouse up
function addBezierControlPoint(e) {
  google.maps.event.clearListeners(map, "mousemove");
  google.maps.event.clearListeners(map, "mouseup");
  // Now listen for the end point
  map.addListener("mousemove", previewBezierCurve);
  map.addListener("mouseup", addBezierEndPoint);
}

// Preview the Bezier curve while moving to the end point
function previewBezierCurve(e) {
  const curvePoints = generateQuadraticBezier(bezierPoints[0], bezierPoints[1], e.latLng);
  if (previewPolyline) previewPolyline.setMap(null);
  previewPolyline = new google.maps.Polyline({
    path: curvePoints,
    map: map,
    strokeColor: "#FF0000",
    strokeOpacity: 0.7,
    strokeWeight: 2,
  });
}

// Add the end point and finalize the curve
function addBezierEndPoint(e) {
  bezierPoints.push(e.latLng);
  google.maps.event.clearListeners(map, "mousemove");
  google.maps.event.clearListeners(map, "mouseup");
}

// Calculate points for a quadratic Bezier curve
function generateQuadraticBezier(start, control, end) {
  const points = [];
  const steps = 50; // More steps = smoother curve (adjust as needed)
  for (let t = 0; t <= 1; t += 1/steps) {
    const lat = Math.pow(1-t, 2)*start.lat() + 2*(1-t)*t*control.lat() + Math.pow(t,2)*end.lat();
    const lng = Math.pow(1-t, 2)*start.lng() + 2*(1-t)*t*control.lng() + Math.pow(t,2)*end.lng();
    points.push(new google.maps.LatLng(lat, lng));
  }
  return points;
}

// Reset Bezier drawing state
function endBezierDraw() {
  isDrawingBezier = false;
  bezierBtn.style.backgroundColor = "";
  bezierBtn.style.color = "";
  google.maps.event.clearListeners(map, "mousedown");
  if (previewPolyline) previewPolyline.setMap(null);
}

Key Notes

  • Google Maps doesn't have native Bezier curve support, so we approximate it with a dense polyline of calculated points. Tweak the steps variable in generateQuadraticBezier to balance smoothness and performance.
  • You can customize the button styles, marker icons, and curve colors to match Esri's toolbar if needed.
  • For cubic Bezier curves (with two control points), just extend the logic to collect four points and update the generateQuadraticBezier function to use the cubic Bezier formula.

内容的提问来源于stack exchange,提问作者mustafa.salaheldin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:06:33