0

I'm developing an application where one functionality is displaying a device on a map using open-layers. These devices can be added by the user and they all can have a custom icon-image using an uploaded image. This image can also be changed on runtime depending on some of the devices attributes (for example the temperature). From what i understood reading through their documentation, there are some properties on the ol.style.Icon object like imgSize which is are all cutting, but not scaling the image. There is also an other property called scale which does in fact scale the image. But since the image size can vary, the scale is not always the same and must be calculated in order to have the same icon size on each device (40 width).

For calculating the right icon depending on the device i am using this style-function on my layer.Vector object.

function(feature){
  var device = feature.get("device");
  var icon = (device.familyIds.length > 0 ? icons.find(i => i.familyIds.includes(device.familyIds[0])) : undefined);
  return new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: (icon != undefined ? new Function("device", "familyProperty", icon.iconSource)(device, icon.familyProperty) : './img/icons/icon_default.png')
    }),
    text: new ol.style.Text({
      text: device.name,
      offsetY: 15,
      font: "20px Calibri,sans-serif"
    })
  });
}

When a certain device has an icon to display, i am injecting a code into a funciton. This function returns the desired img-src. When a device has no icon, i am displaying a default one. So till now, I managed to display the right icon depending on each device but i am still struggling with the different image-sizes. I tried configuring the attributes in the ol.style.Icon object in every imaginable way using imgSize, size and scale but nothing really worked. Thank you for your help.

Patrick
  • 367
  • 1
  • 13

2 Answers2

1

I suggest you use a style cache indexed by src url (it's more efficient in any situation should resolve the async problem)

var styleCache = {};

var styleFunction = function(feature){
  var device = feature.get("device");
  var icon = (device.familyIds.length > 0 ? icons.find(i => i.familyIds.includes(device.familyIds[0])) : undefined);
  var url = (icon != undefined ? new Function("device", "familyProperty", icon.iconSource)(device, icon.familyProperty) : './img/icons/icon_default.png');
  var style = styleCache[url];
  if (!style) {
    style = new ol.style.Style({
      image: new ol.style.Icon({
        anchor: [0.5, 1],
        src: url,
        scale: 0
      }),
      text: new ol.style.Text({
        offsetY: 15,
        font: "20px Calibri,sans-serif"
      })
    });
    var img = new Image();
    img.onload = function() {
      style.getImage().setScale(40/img.width);
      feature.changed();  // force a refresh or just wait until next render?
    }
    img.src = url;
    styleCache[url] = style;
  }
  style.getText().setText(device.name);
  return style;
}

The device name text will need to be set "on demand" as devices might shares images.

Mike
  • 16,042
  • 2
  • 14
  • 30
  • Thanks a lot man. Exactly what i was looking for. It still seems a little strange to me that till now they haven't implemented an ablsolute scaling property. Anyway, thank you for your help. – Patrick Aug 14 '19 at 11:38
-1

Scale icon if too big in -> image: new ol.style.Icon(....):

scale: 0.4,
Nonameix
  • 11
  • 1
  • This does not help. Have you read the question? (different images with different sizes) – Patrick Aug 14 '19 at 10:14
  • Get image size and calculate scale: https://stackoverflow.com/questions/11442712/get-width-height-of-remote-image-from-url – Nonameix Aug 14 '19 at 10:23
  • Loading the image for calculating the scale is async while the style function in the vector needs an immediately returned value. You cannot simply load an image, wait and then return the parent function. This is not how javascript works. – Patrick Aug 14 '19 at 10:26
  • How should this help?? – Patrick Aug 14 '19 at 10:36
  • When marker image loaded (hide image with css: display: none) run function (with in): calculate scale from image size and run function create map, for example. Regards. – Nonameix Aug 14 '19 at 10:40
  • First of all i am not the one running the function. The function i provided above gets executed whenever the map gets changed (moved or zoomed) because it gets passed as parameter to the vector. So i cannot load the image and then execute the style function because i am not the one who executes this function. Furthermore the images can be changed on runtime (after the map is loaded) so same problem. – Patrick Aug 14 '19 at 10:51
  • You need read how events works because you don't understand (you can change image dynamically and after change do stuff... on map every event is triggered). Nice day. See: https://gis.stackexchange.com/questions/214400/dynamically-update-position-of-geolocation-marker-in-openlayers-3 – Nonameix Aug 14 '19 at 10:57
  • https://stackoverflow.com/questions/55598816/dynamically-change-point-marker-on-click-openlayers-5 – Nonameix Aug 14 '19 at 10:57
  • 1
    By the time the event fires the style function will have already completed - it is called by OpenLayers and the developer has no control over that. – Mike Aug 14 '19 at 11:01