InvoiceGuy
InvoiceGuy

Reputation: 22

OpenLayers3 Custom Map Resize Markers on Zoom

I was recently tasked with creating the map for my Wurm Online game alliance. I crafted a genius SVG-based overlay over a static image of an in-game map. Basically it takes data from a spreadsheet and renders Villages as colored circles on the map.

However, we have members all the over the map, so went about to seeing how I could create a zoom-able web-based map of our lands. The game admins give us a map dump every year or thereabouts, so we can create custom map applications however we feel. I downloaded the recent map dump for the island/server I care about, Xanadu.

The Xanadu dump is a 62MB PNG with a resolution of 8192 x 8192 pixels. I found a tile making program (MapTiler version 7), and I went about creating tiles. After the tiles are done rendering, the program itself creates HTML files with embedded JavaScript all programatically. It gave me a head start with OpenLayers3.

I was able to re-calculate Village coordinates and cobble together a zoom-able tiled map with Village circles. Needless to say, I was very happy when I got my custom OpenLayers3 map. (Working example: http://jackswurmtools.com/Content/Static/map.html)

The way I got it set up, each map "decoration" or colored circle is its own Vector.

The chief complaint from my fellow gamers about my zoom-able map, is that the color Village circles are too big zoomed out, yet too small when zoomed in. I've tried all kinds of things, but I have yet to find the right examples. I'm used to finding and transforming SVG elements based on events, but the OP3 canvas rendering is NOT obvious to me in the DOM.

Some of my questions are:

// jacks fully zoomable xanadu map
var data = 
      [{
        X: "6744",
        Y: "-2355.75",
        Name: "Amish Creek",
        Villagers: ["Aniceset", "Fulano"],
        BackColor: "Aquamarine",
        LandMarkType: "Member"
      }, {
        X: "6808.75",
        Y: "-2265.125",
        Name: "Amish Estates",
        Villagers: ["Aniceset", "Villagers"],
        BackColor: "Purple",
        LandMarkType: "Member"
      }];
    
    
console.log(data);

var mapExtent = [0.00000000, -8192.00000000, 8192.00000000, 0.00000000];
var mapMinZoom = 0;
var mapMaxZoom = 5;
var mapMaxResolution = 1.00000000;
var tileExtent = [0.00000000, -8192.00000000, 8192.00000000, 0.00000000];

var mapResolutions = [];
for (var z = 0; z <= mapMaxZoom; z++) {
  mapResolutions.push(Math.pow(2, mapMaxZoom - z) * mapMaxResolution);
}

var mapTileGrid = new ol.tilegrid.TileGrid({
  extent: tileExtent,
  minZoom: mapMinZoom,
  resolutions: mapResolutions
});

var features = [];

var map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        projection: 'PNGMAP',
        tileGrid: mapTileGrid,
        url: "http://jackswurmtools.com/Content/Static/{z}/{x}/{y}.png"
      })
    }),
  ],
  view: new ol.View({
    zoom: 4,
    center: [6602.375, -2250.3125],
    projection: ol.proj.get('PNGMap'),
    maxResolution: mapTileGrid.getResolution(mapMinZoom)
  }),
});
map.getView();

map.on('singleclick', function(evt) {
  var coord = evt.coordinate;
  console.log(coord);

  $("#coord-overlay").html("[" + coord[0] + ", " + coord[1] + "]");
});

// zoom stuff?


// add layers via JSON iteration
renderSVG(data);

drawLines();

function renderSVG(data) {
  var vectorSource = new ol.layer.Vector({});

  console.log(map.getView().getZoom());

  jQuery.each(data, function() {

    var fill = new ol.style.Fill({
      color: this.BackColor
    });

    var stroke = new ol.style.Stroke({
      color: [180, 0, 0, 1],
      width: 1
    });

    var style = new ol.style.Style({
      image: new ol.style.Circle({
        fill: fill,
        stroke: stroke,
        radius: map.getView().getZoom() * 5,
        opacity: 0.7
      }),
      fill: fill,
      stroke: stroke,
      text: new ol.style.Text({
        font: '12px helvetica,sans-serif',
        text: this.Name,
        fill: new ol.style.Fill({
          color: '#000'
        }),
        stroke: new ol.style.Stroke({
          color: '#fff',
          width: 2
        })
      })
    });

    var point_feature = new ol.Feature({});

    var point_geom = new ol.geom.Point([this.X, this.Y]);
    point_feature.setGeometry(point_geom);

    var vector_layer = new ol.layer.Vector({
      source: new ol.source.Vector({
        features: [point_feature],

      })
    });
    vector_layer.setStyle(style);
    map.addLayer(vector_layer);
  });
}

function drawLines() {
  var stroke = new ol.style.Stroke({
    color: [255, 0, 0, 1],
    width: 6
  });

  var style = new ol.style.Style({
    fill: null,
    stroke: stroke,
    text: new ol.style.Text({
      font: '12px helvetica,sans-serif',
      text: "Sandokhan / Wargasm Canal",
      fill: new ol.style.Fill({
        color: '#000'
      }),
      stroke: new ol.style.Stroke({
        color: '#fff',
        width: 2
      })
    })
  });

  var line_feature = new ol.Feature({});

  var coords = [
    [6607.5, -1921],
    [6894, -1921]
  ];

  var layerLines = new ol.layer.Vector({
    source: new ol.source.Vector({
      features: [new ol.Feature({
        geometry: new ol.geom.LineString(coords, 'XY'),
        name: 'Line',
      })]
    })
  });

  layerLines.setStyle(style);

  map.addLayer(layerLines);


}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.8.2/ol.min.css" type="text/css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.8.2/ol.min.js" type="text/javascript"></script>
<div id="map"></div>
<div id="coord-overlay">[6612, -2252]</div>
<input id="slider" type="range" min="0" max="1" step="0.1" value="1" oninput="layer.setOpacity(this.value)">

Upvotes: 1

Views: 1624

Answers (2)

Hicham Zouarhi
Hicham Zouarhi

Reputation: 1060

you can listen to the moveend event for the zoom, however it is also fired when you move the map:

map.on('moveend', function(){
    var radius= map.getView().getZoom() * someFactor; // or whatever +,/ ...
    yourVectorVillage.setStyle(new ol.style.Circle({ radius : radius}));
    // or a style of your own where you can modify the radius
});

Upvotes: 1

Jonatas Walker
Jonatas Walker

Reputation: 14150

You are looking for a resolution listener, the API docs is an excellent place:

map.getView().on('change:resolution', function(){
  var zoom = map.getView().getZoom();

  // your conditions
  if (zoom < 10) {
    // your ol.layer.Vector assuming `vector_layer` global variable
    vector_layer.setStyle(style_with_another_radius);
  }
});

Upvotes: 1

Related Questions