OpenLayers-如果从文件系统或Web服务器上查看,地图比例会有所不同

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenLayers-如果从文件系统或Web服务器上查看,地图比例会有所不同相关的知识,希望对你有一定的参考价值。

我正在尝试将VectorLayer添加到现有的TileLayer,所以我可以将ol.geom.Point标记为感兴趣的地方。

最初这是我想要的工作方式-兴趣点准确地在TileLayer上绘制了它们的位置。

从那时起,我已经生成了更多的图块,但是我没有更改OpenLayers代码。在地图上应该只有更少的黑色空间,但是现在地图看起来似乎要加载缩小的地图,而我的点仍然绘制在同一位置。

OpenLayers缩放级别不成问题-它仍然始终加载缩小,并且在两种情况下,我都可以放大8倍。每种场景的缩放级别都使用相同的图块图像,但是由于我的地图总体上变大了,所以这些图块显得更小。

您能帮我弄清楚如何解决刻度差异吗?

这里是正确绘制时的外观。您可以看到Player ####标记在地图的范围内-黑色区域都没有。

OpenLayers map with markers

[here是我的托管副本

OpenLayers map with markers

点的坐标是相同的,您可以在屏幕上看到这些点彼此之间的绝对距离相同,但是它们是从地图上的黑色区域绘制的,这与图块的比例有所不同或

[Here's OpenLayers代码

<script>
  var layers = 
    dim0: 
      name: "Overworld",
      attribution:
        '<a href="https://github.com/mjungnickel18/papyruscs">PapyrusCS</a>',
      minNativeZoom: 15,
      minZoom: 15,
      maxNativeZoom: 20,
      maxZoom: 22,
      noWrap: true,
      tileSize: 512,
      folder: "dim0",
      fileExtension: "png"
    
  ;

  var config = 
    factor: 1
  ;

  layers = "dim0":"name":"Overworld","attribution":"Generated by <a href=\"https://github.com/mjungnickel18/papyruscs\">PapyrusCS</a>","minNativeZoom":12,"maxNativeZoom":20,"noWrap":true,"tileSize":512,"folder":"dim0","fileExtension":"png"; 
  config = "factor":65536.0,"globalMinZoom":12,"globalMaxZoom":20,"tileSize":512,"blocksPerTile":32;

  // ======

  // For the extent sizes specified below, OpenLayers tries to fit
  // the whole extents given in a space [0, 0] -> [2^8, 2^8] visually
  // on screen at zoom level 0.
  //
  // This constant represents that internal tile size that OpenLayers
  // will aim for, so that we can calculate zoom levels correctly later.
  const openLayersInternalTileSize = Math.pow(2, 8); // 256

  // The actual size of the tiles that we're using in Papyrus.
  const tileSize = config.tileSize;

  // The maximum positive extents of the whole map. The units for this
  // value are "number of tiles at the most zoomed out level generated
  // by Papyrus". That is, if Papyrus generates a minimum zoom level
  // of 15, then the units for this extent size are the number of (Papyrus)
  // zoom level 15 tiles to display at (OpenLayers) zoom level 0.
  //
  // The minimum zoom level that Papyrus is using is in config.globalMinZoom.
  const maximumExtentSize = 10000;

  // The minimum negative extents of the whole map. Uses the same units
  // as maximumExtentSize.
  const minimumExtentSize = -10000;

  // Computes the resolutions array to use for OpenLayers. For each OpenLayers
  // zoom level (0 through 42), this computes the ratio such that a single tile
  // at OpenLayers zoom level 0 is a single tile at the minimum Papyrus zoom level.
  const papyrusMinimumZoomScale = Math.pow(2, config.globalMinZoom);
  const convertedFromTilesToPixelsUsingTileSize = papyrusMinimumZoomScale / tileSize;
  const resolutions = new Array(43);
  for (let z = 0; z < 43; ++z) 
    resolutions[z] = convertedFromTilesToPixelsUsingTileSize / Math.pow(2, z);
  

  // When we calculate resolutions above, we've effectively saying that zoom level 0 is
  // zoom level N, where N is the lowest zoom level. This zoom level N also becomes
  // the range of [0, 0] -> [1, 1] in the coordinate system. We need to be able to translate
  // coordinates in that "zoomed out" coordinate system, back down to the maximum zoom level
  // where each tile represents 32x32 (depending on tilesize) Minecraft tiles.
  const zoomRatioForMaximumZoom = 1 / Math.pow(2, config.globalMaxZoom - config.globalMinZoom);
  const minecraftTilesAtMostZoomedInLevel = config.blocksPerTile;

  // Use a projection where pixels have a 1:1 ratio with the screen at zoom level 0.
  const projection = new ol.proj.Projection(
    code: "ZOOMIFY",
    units: "pixels",
    extent: [
      0,
      0,
      openLayersInternalTileSize / tileSize,
      openLayersInternalTileSize / tileSize
    ]
  );

  // Construct the tile grid using the desired maximum and minimum extents listed above,
  // set the origin to [0, 0] (the center of the map), and the calculated resolutions array.
  const tilegrid = new ol.tilegrid.TileGrid(
    extent: [
      minimumExtentSize,
      minimumExtentSize,
      maximumExtentSize,
      maximumExtentSize
    ],
    origin: [0, 0],
    resolutions: resolutions,
    tileSize: [tileSize, tileSize]
  );

  let map;
  let locationElement;

  const tileLayers = Object.keys(layers)
    .sort()
    .map(function(layerKey, idx) 
      const layer = layers[layerKey];
      const tileLayer = new ol.layer.Tile(
        source: new ol.source.XYZ(
          tileUrlFunction: function(tileCoord, pixelRatio, projection) 
            const z = tileCoord[0];
            const x = tileCoord[1];
            const y = tileCoord[2];
            return (
              "./" +
              layer.folder +
              "/" +
              z +
              "/" +
              x +
              "/" +
              y +
              "." +
              layer.fileExtension
            );
          ,
          projection: projection,
          tileGrid: tilegrid,
          attributions: layer.attribution
        ),
        visible: idx == 0
      );
      tileLayer.metaLayerKey = layerKey;
      return tileLayer;
    );

  const initialLayer = layers[Object.keys(layers).sort()[0]];

  if (Object.keys(layers).sort()[0] == "dim0_stronghold") 
    document.getElementById("map").style.background = "#fff";
   else 
    document.getElementById("map").style.background = "#202020";
  

  const view = new ol.View(
    projection: projection,
    center: [0, 0],
    zoom: 0,
    minZoom: 0,
    maxZoom: config.globalMaxZoom - config.globalMinZoom
  );

  const PapyrusControls = (function(Control) 
    function PapyrusControls(opt_options) 
      const options = opt_options || ;

      const element = document.createElement("div");
      element.className = "layer-select ol-unselectable";

      const card = document.createElement("div");
      card.className = "card";
      element.appendChild(card);

      const cardBody = document.createElement("div");
      cardBody.className = "card-body p-3 px-3";
      card.appendChild(cardBody);

      const form = document.createElement("form");
      cardBody.appendChild(form);

      let currentSelectedLayer = Object.keys(layers).sort()[0];
      let rememberedCenters = ;
      let rememberedZoom = ;

      Object.keys(layers)
        .sort()
        .forEach(function(layerKey, idx) 
          const layer = layers[layerKey];

          const radioContainer = document.createElement("div");
          radioContainer.className = "custom-control custom-radio";

          const radioInput = document.createElement("input");
          radioInput.type = "radio";
          radioInput.id = layerKey;
          radioInput.name = "layers";
          radioInput.className = "custom-control-input";
          radioInput.checked = idx == 0;
          radioInput.value = layerKey;
          radioContainer.appendChild(radioInput);

          const radioLabel = document.createElement("label");
          radioLabel.htmlFor = layerKey;
          radioLabel.className = "custom-control-label";
          radioLabel.innerText = layer.name;
          radioContainer.appendChild(radioLabel);

          const selectLayer = function(e) 
            if (layerKey == "dim0_stronghold") 
              document.getElementById("map").style.background = "#fff";
             else 
              document.getElementById("map").style.background = "#202020";
            

            if (currentSelectedLayer != layerKey) 
              const runtimeLayers = map.getLayers();
              runtimeLayers.forEach(function(runtimeLayer) 
                runtimeLayer.setVisible(
                  runtimeLayer.metaLayerKey == layerKey
                );
              );

              const oldFocusGroup = currentSelectedLayer.substr(0, 4);
              const newFocusGroup = layerKey.substr(0, 4);

              rememberedCenters[oldFocusGroup] = view.getCenter();
              if (rememberedCenters[newFocusGroup] === undefined) 
                // refocus the map to 0, 0
                view.setCenter([0, 0]);
               else 
                // set back to where we were
                view.setCenter(rememberedCenters[newFocusGroup]);
              

              rememberedZoom[oldFocusGroup] = view.getZoom();
              view.setMinZoom(layer.minNativeZoom - config.globalMinZoom);
              view.setMaxZoom(layer.maxNativeZoom - config.globalMinZoom);
              if (rememberedZoom[newFocusGroup] === undefined) 
                // rezoom the map to minimum zoom
                view.setZoom(layer.minNativeZoom - config.globalMinZoom);
               else 
                // set back to where we were
                view.setZoom(rememberedZoom[newFocusGroup]);
              

              const radios = $("input[name='layers']");
              radios.each(function(idx, elem) 
                if (elem.value == layerKey) 
                  elem.checked = true;
                 else 
                  elem.checked = false;
                
              );

              currentSelectedLayer = layerKey;
            
          ;

          radioInput.addEventListener(
            "click",
            selectLayer.bind(this),
            false
          );

          form.appendChild(radioContainer);
        );

      const hr = document.createElement("hr");
      form.appendChild(hr);

      locationElement = document.createElement("div");
      locationElement.innerText = "X: 0, Z: 0";
      form.appendChild(locationElement);

      Control.call(this, 
        element: element,
        target: options.target
      );
    

    if (Control) PapyrusControls.__proto__ = Control;
    PapyrusControls.prototype = Object.create(Control && Control.prototype);
    PapyrusControls.prototype.constructor = PapyrusControls;

    return PapyrusControls;
  )(ol.control.Control);

  map = new ol.Map(
    target: "map",
    layers: tileLayers,
    view: view,
    controls: [
      new ol.control.Zoom(),
      new ol.control.Attribution(),
      new PapyrusControls()
    ]
  );

  map.on("pointermove", function(event) 
    var x = Math.floor(
      (event.coordinate[0] / zoomRatioForMaximumZoom) *
        minecraftTilesAtMostZoomedInLevel
    );
    var z = Math.floor(
      (-event.coordinate[1] / zoomRatioForMaximumZoom) *
        minecraftTilesAtMostZoomedInLevel
    );

    locationElement.innerText = "X: " + x + " Z: " + z;
  );

  if (typeof(playersData) !== "undefined") 
    var playerFeatures = [];

    for (var playerIndex in playersData.players)
    
        var player = playersData.players[playerIndex];

        if (!player.visible) 
            continue;
        

        if (player.dimensionId !== 0) 
            // TODO: Currently I'm only adding player markers who are in the Overworld
            // We'll want to show players depending on which dimension is being viewed
            // Maybe add a separate layer for players in each dimension
            continue;
        

        var style = new ol.style.Style(
            text: new ol.style.Text(
                text: player.name + "\n\uf041", // map-marker
                font: "900 18px 'Font Awesome 5 Free'",
                textBaseline: "bottom",
                fill: new ol.style.Fill(color: player.color),
                stroke: new ol.style.Stroke(color: "white", width: 2)
            )
        );

        var playerFeature = new ol.Feature(
            geometry: new ol.geom.Point([
                (player.position[0] * zoomRatioForMaximumZoom) / minecraftTilesAtMostZoomedInLevel,
                (-player.position[2] * zoomRatioForMaximumZoom) / minecraftTilesAtMostZoomedInLevel
            ])
        );

        playerFeature.setStyle(style);

        playerFeatures.push(playerFeature);
    

    var vectorSource = new ol.source.Vector(
        features: playerFeatures
    );

    var vectorLayer = new ol.layer.Vector(
        source: vectorSource
    );

    map.addLayer(vectorLayer);
  
</script>
答案

好吧,这不是设备问题,这只是我的傻瓜。问题来自我不知道的默认配置。

在我的示例中,如果我将ol.geom.Point中的X和Y值除以2,则得到了所需的内容。我会自行解决其余问题。

感谢@Mike帮助我朝正确的方向看

以上是关于OpenLayers-如果从文件系统或Web服务器上查看,地图比例会有所不同的主要内容,如果未能解决你的问题,请参考以下文章

从 API 到矢量图层 openlayers JSON

如何从 openlayers 读取外部 GeoJSON 文件?

使用OpenLayers发布地图

搭建简易Web GIS网站:使用GeoServer+PostgreSQL+PostGIS+OpenLayers3

电子海图开发第十九篇 web电子海图 使用OpenLayers加载瓦片地图(共一百篇)

关于 WFS-T 与 Openlayers3 的一些问题