OpenLayers: 如何以最短距离移动以适应一个范围?

huangapple go评论45阅读模式
英文:

OpenLayers: How can I move the shortest distance to fit an extent?

问题

以下是您要翻译的内容:

点击蓝色圆圈,地图将移动很远,蓝色圆圈将从地图的右边出现。

这个移动很奇怪。蓝色圆圈只需要向右移动一小段距离。

发生这种情况的原因是蓝色圆圈在首次出现时位于世界之外(-180经度至180经度)。fit操作指定了坐标范围为-180至180。

我认为如果我能提供一个考虑地图当前位置的范围来进行适配操作,那么这个问题可能会得到解决。我尝试过查看各种函数,如获取视图的投影,但它包含预期的值[-180,-90,180,90],并没有指示我实际上正在查看超出这个范围的内容。

我该如何使其工作?

请注意,代码部分不进行翻译。

英文:

Click on the blue circle, the map will move a long distance and the blue circle will appear from the right edge of the map.

This movement is strange. The blue circle should only need to move a short distance to the right.

The reason why this is happening is because the blue circle, when it first appears, is outside of the world ( -180 longitude - 180 longitude ). The fit operation specifies coordinates with -180 - 180.

I figure I could get this to work if I could provide an extent to fit to that took into account the current position of the map. I have tried looking at various functions like getting the projection of then view, but it contains the expected values of [-180, -90, 180, 90] and doesn't indicate I am actually viewing outside of that.

How can I get this to work?

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function createPoints(points, groupName) {
  const features = [];

  for (const [i, point] of points.entries()) {
    const feature = {
      type: &quot;Feature&quot;,
      geometry: {
        type: &quot;Point&quot;,
        coordinates: point
      },
      properties: {
        id: `${groupName} index ${i}`,
        groupName
      }
    };

    features.push(feature);
  }

  const json = {
    type: &quot;FeatureCollection&quot;,
    features
  };

  return json;
}

const thePoints = createPoints(
  [
    [50, 33],
    [50, 33],
    [50, 33],
    [50, 33]
  ],
  &quot;thePoints&quot;
);

const styles = {
  Point: new ol.style.Style({
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({ color: &quot;red&quot; })
    }),
    stroke: new ol.style.Stroke({
      color: &quot;hsla(0, 50%, 100%, 1.0)&quot;,
      width: 5
    }),
    fill: new ol.style.Fill({
      color: &quot;hsla(0, 50%, 50%, 1.0)&quot;
    })
  })
};

const styleFunction = function (feature) {
  const featureType = feature.getGeometry().getType();
  return styles[featureType];
};

const vectorSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: &quot;EPSG:4326&quot; // 4326 3857
  }).readFeatures(thePoints)
});

const cluster = new ol.source.Cluster({
  distance: 30,
  minDistance: 10,
  source: vectorSource
});

const styleCache = {};
const vectorLayer = new ol.layer.Vector({
  source: cluster,
  style: function (feature) {
    const size = feature.get(&quot;features&quot;).length;
    let style = styleCache[size];
    if (!style) {
      style = new ol.style.Style({
        image: new ol.style.Circle({
          radius: 10,
          stroke: new ol.style.Stroke({
            color: &quot;#fff&quot;
          }),
          fill: new ol.style.Fill({
            color: &quot;#3399CC&quot;
          })
        }),
        text: new ol.style.Text({
          text: size.toString(),
          fill: new ol.style.Fill({
            color: &quot;#fff&quot;
          })
        })
      });
      styleCache[size] = style;
    }
    return style;
  },
  zIndex: 5,
  properties: {
    name: &quot;big&quot;
  }
});

const map = new ol.Map({
  target: &quot;map&quot;,
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ],
  view: new ol.View({
    projection: &quot;EPSG:4326&quot;,
    center: [-210, 0],
    zoom: 1
  })
});

 map.on(&quot;click&quot;, (e) =&gt; {
  vectorLayer.getFeatures(e.pixel).then((clickedFeatures) =&gt; {
	if (clickedFeatures.length) {
	  // Get clustered Coordinates
	  const features = clickedFeatures[0].get(&quot;features&quot;);
	  if (features.length &gt; 1) {
		const extent = ol.extent.boundingExtent(
		  features.map((r) =&gt; r.getGeometry().getCoordinates())
		);

		const currentZoom = map.getView().getZoom();

		map.getView().fit(extent, {
		  duration: 2000,
		  maxZoom: currentZoom,
		  padding: [50, 50, 50, 50]
		});
	  }
	}
  });
});

<!-- language: lang-css -->

#map {
  height: 512px;
  width: 1024px;
}

<!-- language: lang-html -->

&lt;link href=&quot;https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/ol.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/dist/ol.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;map&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

答案1

得分: 1

你需要计算你点击的包装世界的偏移量,然后将特性的范围按照这个世界宽度的数量进行偏移。

map.on("click", (e) => {
  vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
    if (clickedFeatures.length) {
      // 获取集群坐标
      const features = clickedFeatures[0].get("features");
      if (features.length > 1) {
        const extent = ol.extent.boundingExtent(
          features.map((r) => r.getGeometry().getCoordinates())
        );

        const currentZoom = map.getView().getZoom();

        const projectionExtent = map.getView().getProjection().getExtent();
        const projectionWidth = ol.extent.getWidth(projectionExtent);
        const clickedWorld = Math.floor(
          (e.coordinate[0] - projectionExtent[0]) / projectionWidth
        );
        extent[0] += clickedWorld * projectionWidth;
        extent[2] += clickedWorld * projectionWidth;

        map.getView().fit(extent, {
          duration: 2000,
          maxZoom: currentZoom,
          padding: [50, 50, 50, 50]
        });
      }
    }
  });
});

这段代码描述了如何在地图上点击某个位置后,计算包含点击的特性集群范围,并将地图视图调整到该范围,以便它完全可见。

英文:

You would need to calculate the offset of the wrapped world you clicked on, then offset the features extent by that number of world widths

<!-- begin snippet: js hide: false console: true babel: null -->

<!-- language: lang-js -->

function createPoints(points, groupName) {
  const features = [];

  for (const [i, point] of points.entries()) {
    const feature = {
      type: &quot;Feature&quot;,
      geometry: {
        type: &quot;Point&quot;,
        coordinates: point
      },
      properties: {
        id: `${groupName} index ${i}`,
        groupName
      }
    };

    features.push(feature);
  }

  const json = {
    type: &quot;FeatureCollection&quot;,
    features
  };

  return json;
}

const thePoints = createPoints(
  [
    [50, 33],
    [50, 33],
    [50, 33],
    [50, 33]
  ],
  &quot;thePoints&quot;
);

const styles = {
  Point: new ol.style.Style({
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({ color: &quot;red&quot; })
    }),
    stroke: new ol.style.Stroke({
      color: &quot;hsla(0, 50%, 100%, 1.0)&quot;,
      width: 5
    }),
    fill: new ol.style.Fill({
      color: &quot;hsla(0, 50%, 50%, 1.0)&quot;
    })
  })
};

const styleFunction = function (feature) {
  const featureType = feature.getGeometry().getType();
  return styles[featureType];
};

const vectorSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: &quot;EPSG:4326&quot; // 4326 3857
  }).readFeatures(thePoints)
});

const cluster = new ol.source.Cluster({
  distance: 30,
  minDistance: 10,
  source: vectorSource
});

const styleCache = {};
const vectorLayer = new ol.layer.Vector({
  source: cluster,
  style: function (feature) {
    const size = feature.get(&quot;features&quot;).length;
    let style = styleCache[size];
    if (!style) {
      style = new ol.style.Style({
        image: new ol.style.Circle({
          radius: 10,
          stroke: new ol.style.Stroke({
            color: &quot;#fff&quot;
          }),
          fill: new ol.style.Fill({
            color: &quot;#3399CC&quot;
          })
        }),
        text: new ol.style.Text({
          text: size.toString(),
          fill: new ol.style.Fill({
            color: &quot;#fff&quot;
          })
        })
      });
      styleCache[size] = style;
    }
    return style;
  },
  zIndex: 5,
  properties: {
    name: &quot;big&quot;
  }
});

const map = new ol.Map({
  target: &quot;map&quot;,
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ],
  view: new ol.View({
    projection: &quot;EPSG:4326&quot;,
    center: [-210, 0],
    zoom: 1
  })
});

 map.on(&quot;click&quot;, (e) =&gt; {
  vectorLayer.getFeatures(e.pixel).then((clickedFeatures) =&gt; {
    if (clickedFeatures.length) {
      // Get clustered Coordinates
      const features = clickedFeatures[0].get(&quot;features&quot;);
      if (features.length &gt; 1) {
        const extent = ol.extent.boundingExtent(
          features.map((r) =&gt; r.getGeometry().getCoordinates())
        );

        const currentZoom = map.getView().getZoom();

        const projectionExtent = map.getView().getProjection().getExtent();
        const projectionWidth = ol.extent.getWidth(projectionExtent);
        const clickedWorld = Math.floor(
          (e.coordinate[0] - projectionExtent[0]) / projectionWidth
        );
        extent[0] += clickedWorld * projectionWidth;
        extent[2] += clickedWorld * projectionWidth;

        map.getView().fit(extent, {
          duration: 2000,
          maxZoom: currentZoom,
          padding: [50, 50, 50, 50]
        });
      }
    }
  });
});

<!-- language: lang-css -->

#map {
  height: 512px;
  width: 1024px;
}

<!-- language: lang-html -->

&lt;link href=&quot;https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/ol.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/dist/ol.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;map&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年4月11日 00:16:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75978764.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定