# 十二.geom(综合)

# 1.MultiPoint

使用修改交互进行缩放和旋转

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <form class="form-inline">
      <label for="type">几何类型 &nbsp;</label>
      <select ref="type">
        <option value="Point"></option>
        <option value="LineString">直线</option>
        <option value="Polygon" selected>多边形</option>
        <option value="Circle"></option>
      </select>
    </form>
  </div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      geom: { MultiPoint, Point },
      interaction: { Draw, Modify, Translate },
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { OSM, Vector: VectorSource },
      style: { Circle: CircleStyle, Fill, Stroke, Style },
      extent: { getCenter, getHeight, getWidth },
      events: {
        condition: { never, platformModifierKeyOnly, primaryAction },
      },
    } = ol;
    const raster = new TileLayer({
      source: new OSM(),
    });
    const source = new VectorSource();
    const style = new Style({
      geometry: function (feature) {
        const modifyGeometry = feature.get("modifyGeometry");
        return modifyGeometry ? modifyGeometry.geometry : feature.getGeometry();
      },
      fill: new Fill({
        color: "rgba(255, 255, 255, 0.2)",
      }),
      stroke: new Stroke({
        color: "#ffcc33",
        width: 2,
      }),
      image: new CircleStyle({
        radius: 7,
        fill: new Fill({
          color: "#ffcc33",
        }),
      }),
    });
    function calculateCenter(geometry) {
      let center, coordinates, minRadius;
      const type = geometry.getType();
      if (type === "Polygon") {
        let x = 0;
        let y = 0;
        let i = 0;
        coordinates = geometry.getCoordinates()[0].slice(1);
        coordinates.forEach(function (coordinate) {
          x += coordinate[0];
          y += coordinate[1];
          i++;
        });
        center = [x / i, y / i];
      } else if (type === "LineString") {
        center = geometry.getCoordinateAt(0.5);
        coordinates = geometry.getCoordinates();
      } else {
        center = getCenter(geometry.getExtent());
      }
      let sqDistances;
      if (coordinates) {
        sqDistances = coordinates.map(function (coordinate) {
          const dx = coordinate[0] - center[0];
          const dy = coordinate[1] - center[1];
          return dx * dx + dy * dy;
        });
        minRadius = Math.sqrt(Math.max.apply(Math, sqDistances)) / 3;
      } else {
        minRadius =
          Math.max(
            getWidth(geometry.getExtent()),
            getHeight(geometry.getExtent())
          ) / 3;
      }
      return {
        center: center,
        coordinates: coordinates,
        minRadius: minRadius,
        sqDistances: sqDistances,
      };
    }
    const vector = new VectorLayer({
      source: source,
      style: function (feature) {
        const styles = [style];
        const modifyGeometry = feature.get("modifyGeometry");
        const geometry = modifyGeometry
          ? modifyGeometry.geometry
          : feature.getGeometry();
        const result = calculateCenter(geometry);
        const center = result.center;
        if (center) {
          styles.push(
            new Style({
              geometry: new Point(center),
              image: new CircleStyle({
                radius: 4,
                fill: new Fill({
                  color: "#ff3333",
                }),
              }),
            })
          );
          const coordinates = result.coordinates;
          if (coordinates) {
            const minRadius = result.minRadius;
            const sqDistances = result.sqDistances;
            const rsq = minRadius * minRadius;
            const points = coordinates.filter(function (coordinate, index) {
              return sqDistances[index] > rsq;
            });
            styles.push(
              new Style({
                geometry: new MultiPoint(points),
                image: new CircleStyle({
                  radius: 4,
                  fill: new Fill({
                    color: "#33cc33",
                  }),
                }),
              })
            );
          }
        }
        return styles;
      },
    });
    const map = new Map({
      layers: [raster, vector],
      target: this.$refs.map,
      view: new View({
        center: [-11000000, 4600000],
        zoom: 4,
      }),
    });
    const defaultStyle = new Modify({ source: source })
      .getOverlay()
      .getStyleFunction();
    const modify = new Modify({
      source: source,
      condition: function (event) {
        return primaryAction(event) && !platformModifierKeyOnly(event);
      },
      deleteCondition: never,
      insertVertexCondition: never,
      style: function (feature) {
        feature.get("features").forEach(function (modifyFeature) {
          const modifyGeometry = modifyFeature.get("modifyGeometry");
          if (modifyGeometry) {
            const point = feature.getGeometry().getCoordinates();
            let modifyPoint = modifyGeometry.point;
            if (!modifyPoint) {
              modifyPoint = point;
              modifyGeometry.point = modifyPoint;
              modifyGeometry.geometry0 = modifyGeometry.geometry;
              const result = calculateCenter(modifyGeometry.geometry0);
              modifyGeometry.center = result.center;
              modifyGeometry.minRadius = result.minRadius;
            }
            const center = modifyGeometry.center;
            const minRadius = modifyGeometry.minRadius;
            let dx, dy;
            dx = modifyPoint[0] - center[0];
            dy = modifyPoint[1] - center[1];
            const initialRadius = Math.sqrt(dx * dx + dy * dy);
            if (initialRadius > minRadius) {
              const initialAngle = Math.atan2(dy, dx);
              dx = point[0] - center[0];
              dy = point[1] - center[1];
              const currentRadius = Math.sqrt(dx * dx + dy * dy);
              if (currentRadius > 0) {
                const currentAngle = Math.atan2(dy, dx);
                const geometry = modifyGeometry.geometry0.clone();
                geometry.scale(
                  currentRadius / initialRadius,
                  undefined,
                  center
                );
                geometry.rotate(currentAngle - initialAngle, center);
                modifyGeometry.geometry = geometry;
              }
            }
          }
        });
        return defaultStyle(feature);
      },
    });
    modify.on("modifystart", function (event) {
      event.features.forEach(function (feature) {
        feature.set(
          "modifyGeometry",
          { geometry: feature.getGeometry().clone() },
          true
        );
      });
    });
    modify.on("modifyend", function (event) {
      event.features.forEach(function (feature) {
        const modifyGeometry = feature.get("modifyGeometry");
        if (modifyGeometry) {
          feature.setGeometry(modifyGeometry.geometry);
          feature.unset("modifyGeometry", true);
        }
      });
    });
    map.addInteraction(modify);
    map.addInteraction(
      new Translate({
        condition: function (event) {
          return primaryAction(event) && platformModifierKeyOnly(event);
        },
        layers: [vector],
      })
    );
    let draw;
    const typeSelect = this.$refs.type;
    function addInteractions() {
      draw = new Draw({
        source: source,
        type: typeSelect.value,
      });
      map.addInteraction(draw);
    }
    typeSelect.addEventListener("change", function () {
      map.removeInteraction(draw);
      addInteractions();
    });
    addInteractions();
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

# 2.自定义多边形样式

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      format: { GeoJSON },
      geom: { MultiPoint },
      Map,
      View,
      layer: { Vector: VectorLayer },
      source: { Vector: VectorSource },
      style: { Circle: CircleStyle, Fill, Stroke, Style },
    } = ol;
    const styles = [
      new Style({
        stroke: new Stroke({
          color: "blue",
          width: 3,
        }),
        fill: new Fill({
          color: "rgba(0, 0, 255, 0.1)",
        }),
      }),
      new Style({
        image: new CircleStyle({
          radius: 5,
          fill: new Fill({
            color: "orange",
          }),
        }),
        geometry: function (feature) {
          const coordinates = feature.getGeometry().getCoordinates()[0];
          return new MultiPoint(coordinates);
        },
      }),
    ];
    const geojsonObject = {
      type: "FeatureCollection",
      crs: {
        type: "name",
        properties: {
          name: "EPSG:3857",
        },
      },
      features: [
        {
          type: "Feature",
          geometry: {
            type: "Polygon",
            coordinates: [
              [
                [-5e6, 6e6],
                [-5e6, 8e6],
                [-3e6, 8e6],
                [-3e6, 6e6],
                [-5e6, 6e6],
              ],
            ],
          },
        },
        {
          type: "Feature",
          geometry: {
            type: "Polygon",
            coordinates: [
              [
                [-2e6, 6e6],
                [-2e6, 8e6],
                [0, 8e6],
                [0, 6e6],
                [-2e6, 6e6],
              ],
            ],
          },
        },
        {
          type: "Feature",
          geometry: {
            type: "Polygon",
            coordinates: [
              [
                [1e6, 6e6],
                [1e6, 8e6],
                [3e6, 8e6],
                [3e6, 6e6],
                [1e6, 6e6],
              ],
            ],
          },
        },
        {
          type: "Feature",
          geometry: {
            type: "Polygon",
            coordinates: [
              [
                [-2e6, -1e6],
                [-1e6, 1e6],
                [0, -1e6],
                [-2e6, -1e6],
              ],
            ],
          },
        },
      ],
    };
    const source = new VectorSource({
      features: new GeoJSON().readFeatures(geojsonObject),
    });
    const layer = new VectorLayer({
      source: source,
      style: styles,
    });
    const map = new Map({
      layers: [layer],
      target: this.$refs.map,
      view: new View({
        center: [0, 3000000],
        zoom: 2,
      }),
    });
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

# 3.分形渲染

如何有效地渲染具有许多顶点的特征

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <label for="depth">
      depth:&nbsp;
      <input id="depth" type="range" min="0" max="9" step="1" value="5" />
      &nbsp;(<span id="count">#</span> points)
    </label>
  </div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      Feature,
      geom: { LineString },
      Map,
      View,
      layer: { Vector: VectorLayer },
      source: { Vector: VectorSource },
      style: Style,
      proj: { fromLonLat },
    } = ol;
    const radius = 10e6;
    const cos30 = Math.cos(Math.PI / 6);
    const sin30 = Math.sin(Math.PI / 6);
    const rise = radius * sin30;
    const run = radius * cos30;

    const triangle = new LineString([
      [0, radius],
      [run, -rise],
      [-run, -rise],
      [0, radius],
    ]);

    const feature = new Feature(triangle);

    const layer = new VectorLayer({
      source: new VectorSource({
        features: [feature],
      }),
    });

    const map = new Map({
      layers: [layer],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 1,
      }),
    });

    function makeFractal(depth) {
      const geometry = triangle.clone();
      const graph = coordsToGraph(geometry.getCoordinates());
      for (let i = 0; i < depth; ++i) {
        let node = graph;
        while (node.next) {
          const next = node.next;
          injectNodes(node);
          node = next;
        }
      }
      const coordinates = graphToCoords(graph);
      document.getElementById("count").innerHTML = coordinates.length;
      geometry.setCoordinates(coordinates);
      feature.setGeometry(geometry);
    }

    function injectNodes(startNode) {
      const endNode = startNode.next;

      const start = startNode.point;
      const end = startNode.next.point;
      const dx = end[0] - start[0];
      const dy = end[1] - start[1];

      // first point at 1/3 along the segment
      const firstNode = {
        point: [start[0] + dx / 3, start[1] + dy / 3],
      };

      // second point at peak of _/\_
      const r = Math.sqrt(dx * dx + dy * dy) / (2 * cos30);
      const a = Math.atan2(dy, dx) + Math.PI / 6;
      const secondNode = {
        point: [start[0] + r * Math.cos(a), start[1] + r * Math.sin(a)],
      };

      // third point at 2/3 along the segment
      const thirdNode = {
        point: [end[0] - dx / 3, end[1] - dy / 3],
      };

      startNode.next = firstNode;
      firstNode.next = secondNode;
      secondNode.next = thirdNode;
      thirdNode.next = endNode;
    }

    function coordsToGraph(coordinates) {
      const graph = {
        point: coordinates[0],
      };
      const length = coordinates.length;
      for (let level = 0, node = graph; level < length - 1; ++level) {
        node.next = {
          point: coordinates[level + 1],
        };
        node = node.next;
      }
      return graph;
    }

    function graphToCoords(graph) {
      const coordinates = [graph.point];
      for (let node = graph, i = 1; node.next; node = node.next, ++i) {
        coordinates[i] = node.next.point;
      }
      return coordinates;
    }

    const depthInput = document.getElementById("depth");

    function update() {
      makeFractal(Number(depthInput.value));
    }

    let updateTimer;

    /**
     * Regenerate fractal on depth change.  Change events are debounced so updates
     * only occur every 200ms.
     */
    depthInput.onchange = function () {
      window.clearTimeout(updateTimer);
      updateTimer = window.setTimeout(update, 200);
    };

    update();
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

# 4.垄断一体化

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      Feature,
      control: { MousePosition },
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { OSM, Vector: VectorSource },
      style: { Circle: CircleStyle, Fill, Stroke, Style, Text },
      interaction: { Draw, Snap },
      geom: { LineString, Point, Polygon },
    } = ol;
    const raster = new TileLayer({
      source: new OSM(),
    });
    const nodes = new VectorSource({ wrapX: false });
    const nodesLayer = new VectorLayer({
      source: nodes,
      style: function (f) {
        const style = new Style({
          image: new CircleStyle({
            radius: 8,
            fill: new Fill({ color: "rgba(255, 0, 0, 0.2)" }),
            stroke: new Stroke({ color: "red", width: 1 }),
          }),
          text: new Text({
            text: f.get("node").id.toString(),
            fill: new Fill({ color: "red" }),
            stroke: new Stroke({
              color: "white",
              width: 3,
            }),
          }),
        });
        return [style];
      },
    });
    const edges = new VectorSource({ wrapX: false });
    const edgesLayer = new VectorLayer({
      source: edges,
      style: function (f) {
        const style = new Style({
          stroke: new Stroke({
            color: "blue",
            width: 1,
          }),
          text: new Text({
            text: f.get("edge").id.toString(),
            fill: new Fill({ color: "blue" }),
            stroke: new Stroke({
              color: "white",
              width: 2,
            }),
          }),
        });
        return [style];
      },
    });
    const faces = new VectorSource({ wrapX: false });
    const facesLayer = new VectorLayer({
      source: faces,
      style: function (f) {
        const style = new Style({
          stroke: new Stroke({
            color: "black",
            width: 1,
          }),
          fill: new Fill({
            color: "rgba(0, 255, 0, 0.2)",
          }),
          text: new Text({
            font: "bold 12px sans-serif",
            text: f.get("face").id.toString(),
            fill: new Fill({ color: "green" }),
            stroke: new Stroke({
              color: "white",
              width: 2,
            }),
          }),
        });
        return [style];
      },
    });
    const map = new Map({
      layers: [raster, facesLayer, edgesLayer, nodesLayer],
      target: this.$refs.map,
      view: new View({
        center: [-11000000, 4600000],
        zoom: 16,
      }),
    });
    const topo = topolis.createTopology();
    topo.on("addnode", nodeToFeature);
    topo.on("removenode", function (e) {
      removeElementFeature(nodes, e);
    });
    topo.on("addedge", edgeToFeature);
    topo.on("modedge", function (e) {
      const feature = edges.getFeatureById(e.id);
      feature.setGeometry(new LineString(e.coordinates));
    });
    topo.on("removeedge", function (e) {
      removeElementFeature(edges, e);
    });
    topo.on("addface", faceToFeature);
    topo.on("removeface", function (e) {
      removeElementFeature(faces, e);
    });
    function removeElementFeature(source, element) {
      const feature = source.getFeatureById(element.id);
      source.removeFeature(feature);
    }
    function nodeToFeature(node) {
      const feature = new Feature({
        geometry: new Point(node.coordinate),
        node: node,
      });
      feature.setId(node.id);
      nodes.addFeature(feature);
    }
    function edgeToFeature(edge) {
      const feature = new Feature({
        geometry: new LineString(edge.coordinates),
        edge: edge,
      });
      feature.setId(edge.id);
      edges.addFeature(feature);
    }
    function faceToFeature(face) {
      const coordinates = topo.getFaceGeometry(face);
      const feature = new Feature({
        geometry: new Polygon(coordinates),
        face: face,
      });
      feature.setId(face.id);
      faces.addFeature(feature);
    }
    function createNode(topo, coord) {
      let node;
      const existingEdge = topo.getEdgeByPoint(coord, 5)[0];
      if (existingEdge) {
        node = topo.modEdgeSplit(existingEdge, coord);
      } else {
        node = topo.addIsoNode(coord);
      }
      return node;
    }
    function onDrawend(e) {
      const edgeGeom = e.feature.getGeometry().getCoordinates();
      const startCoord = edgeGeom[0];
      const endCoord = edgeGeom[edgeGeom.length - 1];
      let start, end;
      try {
        start = topo.getNodeByPoint(startCoord);
        end = topo.getNodeByPoint(endCoord);
        const edgesAtStart = topo.getEdgeByPoint(startCoord, 5);
        const edgesAtEnd = topo.getEdgeByPoint(endCoord, 5);
        const crossing = topo.getEdgesByLine(edgeGeom);
        if (
          crossing.length === 1 &&
          !start &&
          !end &&
          edgesAtStart.length === 0 &&
          edgesAtEnd.length === 0
        ) {
          topo.remEdgeNewFace(crossing[0]);
          start = crossing[0].start;
          if (start.face) {
            topo.removeIsoNode(start);
          }
          end = crossing[0].end;
          if (end.face) {
            topo.removeIsoNode(end);
          }
          return;
        }
        if (!start) {
          start = createNode(topo, startCoord);
          edgeGeom[0] = start.coordinate;
        }
        if (!end) {
          end = createNode(topo, endCoord);
          edgeGeom[edgeGeom.length - 1] = end.coordinate;
        }
        topo.addEdgeNewFaces(start, end, edgeGeom);
      } catch (e) {
        toastr.warning(e.toString());
      }
    }
    const draw = new Draw({
      type: "LineString",
    });
    draw.on("drawend", onDrawend);
    map.addInteraction(draw);
    const snap = new Snap({
      source: edges,
    });
    map.addInteraction(snap);
    map.addControl(new MousePosition());
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

# 5.合成线

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Feature,
        geom: { LineString },
        Map,
        View,
        layer: { Vector: VectorLayer },
        source: { Vector: VectorSource },
        style: { Stroke, Style },
      } = ol
      const count = 10000
      const features = new Array(count)
  
      let startPoint = [0, 0]
      let endPoint
  
      let delta, deltaX, deltaY
      let signX = 1
      let signY = -1
  
      let i
      for (i = 0; i < count; ++i) {
        delta = (i + 1) * 2500
        if (i % 2 === 0) {
          signY *= -1
        } else {
          signX *= -1
        }
        deltaX = delta * signX
        deltaY = delta * signY
        endPoint = [startPoint[0] + deltaX, startPoint[1] + deltaY]
        features[i] = new Feature({
          geometry: new LineString([startPoint, endPoint]),
        })
        startPoint = endPoint
      }
  
      const vector = new VectorLayer({
        source: new VectorSource({
          features: features,
          wrapX: false,
        }),
        style: new Style({
          stroke: new Stroke({
            color: "#666666",
            width: 1,
          }),
        }),
      })
  
      const view = new View({
        center: [12579156, 3274244],
        zoom: 0,
      })
  
      const map = new Map({
        layers: [vector],
        target: this.$refs.map,
        view: view,
      })
    },
  }
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# 6.合成点

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Feature,
        Map,
        View,
        layer: { Vector: VectorLayer },
        source: { Vector: VectorSource },
        style: { Circle: CircleStyle, Fill, Stroke, Style },
        geom: { LineString, Point },
        render: { getVectorContext },
      } = ol
  
      const count = 20000
      const features = new Array(count)
      const e = 18000000
      for (let i = 0; i < count; ++i) {
        features[i] = new Feature({
          geometry: new Point([
            2 * e * Math.random() - e,
            2 * e * Math.random() - e,
          ]),
          i: i,
          size: i % 2 ? 10 : 20,
        })
      }
  
      const styles = {
        10: new Style({
          image: new CircleStyle({
            radius: 5,
            fill: new Fill({ color: "#666666" }),
            stroke: new Stroke({ color: "#bada55", width: 1 }),
          }),
        }),
        20: new Style({
          image: new CircleStyle({
            radius: 10,
            fill: new Fill({ color: "#666666" }),
            stroke: new Stroke({ color: "#bada55", width: 1 }),
          }),
        }),
      }
  
      const vectorSource = new VectorSource({
        features: features,
        wrapX: false,
      })
      const vector = new VectorLayer({
        source: vectorSource,
        style: function (feature) {
          return styles[feature.get("size")]
        },
      })
  
      const map = new Map({
        layers: [vector],
        target: document.getElementById("map"),
        view: new View({
          center: [12579156, 3274244],
          zoom: 2,
        }),
      })
  
      let point = null
      let line = null
      const displaySnap = function (coordinate) {
        const closestFeature =
          vectorSource.getClosestFeatureToCoordinate(coordinate)
        if (closestFeature === null) {
          point = null
          line = null
        } else {
          const geometry = closestFeature.getGeometry()
          const closestPoint = geometry.getClosestPoint(coordinate)
          if (point === null) {
            point = new Point(closestPoint)
          } else {
            point.setCoordinates(closestPoint)
          }
          if (line === null) {
            line = new LineString([coordinate, closestPoint])
          } else {
            line.setCoordinates([coordinate, closestPoint])
          }
        }
        map.render()
      }
  
      map.on("pointermove", function (evt) {
        if (evt.dragging) {
          return
        }
        const coordinate = map.getEventCoordinate(evt.originalEvent)
        displaySnap(coordinate)
      })
  
      map.on("click", function (evt) {
        displaySnap(evt.coordinate)
      })
  
      const stroke = new Stroke({
        color: "rgba(255,255,0,0.9)",
        width: 3,
      })
      const style = new Style({
        stroke: stroke,
        image: new CircleStyle({
          radius: 10,
          stroke: stroke,
        }),
      })
  
      vector.on("postrender", function (evt) {
        const vectorContext = getVectorContext(evt)
        vectorContext.setStyle(style)
        if (point !== null) {
          vectorContext.drawGeometry(point)
        }
        if (line !== null) {
          vectorContext.drawGeometry(line)
        }
      })
  
      map.on("pointermove", function (evt) {
        if (evt.dragging) {
          return
        }
        const pixel = map.getEventPixel(evt.originalEvent)
        const hit = map.hasFeatureAtPixel(pixel)
        if (hit) {
          map.getTarget().style.cursor = "pointer"
        } else {
          map.getTarget().style.cursor = ""
        }
      })
    },
  }
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

# 7.渲染几何形状到画布

查看代码详情
<template>
    <div ref="map" class="map" id="canvas"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        geom: { LineString, Point, Polygon },
        style: { Circle: CircleStyle, Fill, Stroke, Style },
        render: { toContext },
      } = ol
  
      const canvas = document.getElementById("canvas")
      const vectorContext = toContext(canvas.getContext("2d"), {
        size: [100, 100],
      })
  
      const fill = new Fill({ color: "blue" })
      const stroke = new Stroke({ color: "black" })
      const style = new Style({
        fill: fill,
        stroke: stroke,
        image: new CircleStyle({
          radius: 10,
          fill: fill,
          stroke: stroke,
        }),
      })
      vectorContext.setStyle(style)
  
      vectorContext.drawGeometry(
        new LineString([
          [10, 10],
          [90, 90],
        ])
      )
      vectorContext.drawGeometry(
        new Polygon([
          [
            [2, 2],
            [98, 2],
            [2, 98],
            [2, 2],
          ],
        ])
      )
      vectorContext.drawGeometry(new Point([88, 88]))
    },
  }
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50