简体   繁体   中英

How could I resize/scale a geojson polygon

I'm currently building different geojson polygon interactions. My blocker is building this algorithm that allows to scale the size of the polygon with onMouseDown method.

It was built with vanilla.js and use npm for dependencies.

import distance from "@turf/distance";
import centroid from "@turf/centroid";
import transformScale from "@turf/transform-scale";
import EventEmitter from "events";
const emitter = new EventEmitter();

const ScaleMode = {
  scalestart(selectedFeature, originalCenter) {},
  scaling(selectedFeature, originalCenter, lastMouseDown) {},
  scaleend(selectedFeature) {},

  onSetup: function(opts) {
    var state = {};

    emitter.addListener(
      "scalestart",
      function() {
        this.scalestart(state.selectedFeature, state.originalCenter);
      }.bind(this)
    );
    emitter.addListener(
      "scaling",
      function() {
        this.scaling(
          state.selectedFeature,
          state.originalCenter,
          state.lastMouseDownLngLat
        );
      }.bind(this)
    );
    emitter.addListener(
      "scaleend",
      function() {
        this.scaleend(state.selectedFeature, state.lastMouseDownLngLat);
      }.bind(this)
    );

    state.selectedFeature = opts.selectedFeature || false;
    state.lastMouseDownLngLat = false;
    state.originalCenter = false;
    state.mode = "scale" || false;
    return state;
  },
  toDisplayFeatures(state, geojson, display) {
    display(geojson);
  },
  onMouseDown: (state, e) => {
    if (e.featureTarget) {
      // calculate the polygon center
      state.polyCenter = turf.centroid(e.featureTarget);
      const polyCoordinates = state.polyCenter.geometry.coordinates;
      const poly = turf.polygon(PolyData);
      console.log(poly);
      const scaledPoly = turf.transformScale(poly, 3);
      console.log(poly);

      // scaling
      state.scaledPoly = transformScale(poly, 3);

      // disable on drag map over the polygon
      e.target["dragPan"].disable();
    }
  }
};

export default ScaleMode;

I want to be able to increase the coordinates of the polygon using onMouseDown/onMouseUp/onDrag methods.

Demo: https://codesandbox.io/s/54qv8x244n

Here's a clone of mapbox-gl-rotate-mode handling scaleTransform :

const distance = require("@turf/distance").default;
const centroid = require("@turf/centroid").default;
const transformScale = require("@turf/transform-scale").default;
const EventEmitter = require("events");
const emitter = new EventEmitter();

var ScaleMode = {
  scalestart: function() {},
  scaling: function() {},
  scaleend: function() {},

  onSetup: function(opts) {
    var state = {};

    emitter.addListener(
      "scalestart",
      function() {
        this.scalestart(state.selectedFeature, state.originalCenter);
      }.bind(this)
    );
    emitter.addListener(
      "scaling",
      function() {
        this.scaling(
          state.selectedFeature,
          state.originalCenter,
          state.scaleFactor
        );
      }.bind(this)
    );
    emitter.addListener(
      "scaleend",
      function() {
        this.scaleend(state.selectedFeature, state.scaleFactor);
      }.bind(this)
    );

    state.selectedFeature = opts.selectedFeature || undefined;
    state.scaleFactor = 1;
    state.originalCenter = undefined;
    state.mode = "scale";
    return state;
  },

  onMouseDown: function(state, e) {
    if (e.featureTarget) {
      if (this._ctx.api.get(e.featureTarget.properties.id)) {
        e.target["dragPan"].disable();
        state.selectedFeature = this._ctx.api.get(
          e.featureTarget.properties.id
        );
        state.originalCenter = centroid(e.featureTarget);
        state.originalFeature = e.featureTarget;
        state.originalDistance = Math.max(
          distance(state.originalCenter, [e.lngLat.lng, e.lngLat.lat]),
          0.1
        );
        emitter.emit("scalestart");
      }
    }
    return state;
  },

  toDisplayFeatures: function(state, geojson, display) {
    display(geojson);
  },

  onDrag: function(state, e) {
    if (state.selectedFeature && state.mode) {
      if (state.mode === "scale") {
        switch (state.originalFeature.properties["meta:type"]) {
          case "Point":
            break;
          case "LineString":
          case "Polygon":
          case "MultiLineString":
          case "MultiPolygon":
            state.scaleFactor =
              distance(state.originalCenter, [e.lngLat.lng, e.lngLat.lat]) /
                state.originalDistance || 1;
            break;
          default:
            return;
        }
        emitter.emit("scaling");
        state.selectedFeature.geometry = transformScale(
          state.originalFeature,
          state.scaleFactor
        ).geometry;
        this._ctx.api.add(state.selectedFeature);
      }
    }
  },

  onMouseUp: function(state, e) {
    e.target["dragPan"].enable();
    emitter.emit("scaleend");
    state.selectedFeature = undefined;
    state.scaleFactor = undefined;
    state.originalCenter = undefined;
    state.originalDistance = undefined;
    return state;
  }
};

module.exports = ScaleMode;

I wrapped it up as a npm package and you can now use it exactly like the rotate plugin:

npm i mapbox-gl-scale-mode

See it working here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM