0

As shown in this example, when the blur is set to 0, the opacity of each point correlates to the weight, and the opacity parameter is layered on top of the weight opacity.

Here is an example image of the opacity corresponding to point weight:

enter image description here

How do I make all the points full opacity regardless of weight and layering?

Here is my current heatmap object:

const rainbow = [
    'rgba(127.5, 0.0, 255.0, 1.0)',
    'rgba(0.4999999999999982, 180.8667334394926, 235.43872205689976, 1.0)',
    'rgba(128.5, 254.99516197392535, 179.75601446106756, 1.0)',
    'rgba(255.0, 178.63847458628922, 96.49481776078913, 1.0)',
    'rgba(255.0, 3.122849337825751e-14, 1.5614246689128753e-14, 1.0)',
]

const heatmapLayer = new ol.layer.Heatmap({
    source: vectorSource,
    blur: 1,
    radius: 3,
    gradient: rainbow,
    weight: function() {
        return 0.1;
    },
});
0

1 Answer 1

1

There seems to be no option or method to set point opacity in ol.layer.Heatmap layer to 1, regardless of weight.

One possible solution would be to use ol.layer.Raster layer to manipulate pixels of ol.layer.Heatmap layer. Problem is that raster layer requires image layer as input, which ol.layer.Heatmap layer is not.

So one possible solution that works is to use ol.layer.VectorImage layer to create vector layer with points that have opacity set to values below 1 (color is not important), and then use ol.layer.Raster layer to manipulate pixels of that layer.

Logic of this solution goes like this:

  1. Lets's say there are n colors for the heat map colors rainbow.
  2. Create ol.layer.VectorImage vector layer, styling points with circles that have opacity set to 1/n (color is not important). When circles will overlap, resultant opacity will increase proportionally with the number of overlaps. Layer is not added to the map.
  3. Create ol.layer.Raster layer, taking ol.layer.VectorImage layer as input. Layer is used for pixel manipulation. In option operation opacity of input pixels (value range is 0 to 255) is divided in n + 1 classes using simple formula colorIndex = Math.round(opacity / (255 / n).
  4. Index from previous step is used to get corresponding color from rainbow array. This is then returned in operation function as pixel color.
  5. One extra thing to be taken into account is that individual circle, created by ol.layer.VectorImage layer, does not have uniform opacity, because it fades (decreases) a bit at the edge for smoothing purposes. This is important for nonoverlapped circles which get the first color. For this reason extra color is added at the beginning, being copy of the first actual color, just with half of the opacity.

So code for earthquake heatmap could then look something like this (with gradient colors from your question):

const n = 5;

var vectorLayer = new ol.layer.VectorImage({
  source: new ol.source.Vector({
    url: 'data/2012_Earthquakes_Mag5.kml',
    format: new ol.format.KML({
      extractStyles: false,
    }),
  }),
  style: function (feature, resolution) {
    var style = new ol.style.Style({
      image: new ol.style.Circle({
        radius: 5,
        fill: new ol.style.Fill({
          color: 'rgba(255, 0, 0,' + (1 / n) + ')'
        })
      })
    });
    return(style);
  },
});

function heat(pixels, data) {
  const rainbow = [
      [127.5, 0.0, 255.0, 125],
      [127.5, 0.0, 255.0, 255],
      [0.4999999999999982, 180.8667334394926, 235.43872205689976, 255],
      [128.5, 254.99516197392535, 179.75601446106756, 255],
      [255.0, 178.63847458628922, 96.49481776078913, 255],
      [255.0, 3.122849337825751e-14, 1.5614246689128753e-14, 255]
  ];
  var pixel = pixels[0];
  if (pixel[3]) {
    var colorIndex = Math.floor(pixel[3] / (255 / n));
    pixel = rainbow[colorIndex];
  }
  return pixel;
}

var rasterSource = new ol.source.Raster({
  sources: [vectorLayer],
  operation: heat
});

var rasterLayer = new ol.layer.Image({
  source: rasterSource
});

var baseLayer = new ol.layer.Tile({
  source: new ol.source.Stamen({
    layer: 'toner',
  }),
});

new ol.Map({
  layers: [baseLayer, rasterLayer],
  target: 'map',
  view: new ol.View({
    center: [0, 0],
    zoom: 2,
  }),
});      

Heatmap then looks like this:

enter image description here

4
  • Thank you so much! Sorry for the slow reply, I still have some questions though: (1) Could you explain a bit how the heat function works? Specifically the part about pixel[3] / 51. (2) The map is also very slow to drag around and zoom, is this a characteristic of raster layers in general? (3) The colour array rainbow was originally passed to the to the gradient parameter, so here there are only 5 colours available, how could this be worked around other than just adding more colour intervals? Thanks again! Jul 12, 2021 at 13:15
  • If answer helped you solve your problem, it's customary on GIS SE site to mark it as accepted, to let other users with similar questions/problems know that problem was resolved. As for (1) and (3), I'll ad some explanation, as for (2) I cannot tell why your map is slow since I don't know how it's layers are defined/structured. The example from the image above worked without any problems.
    – TomazicM
    Jul 12, 2021 at 13:59
  • Marked as accepted! (2) The only layers I used were the ones shown in your answer, were you able to drag and zoom without the map lagging and having to refresh? Jul 12, 2021 at 14:39
  • See modified answer.
    – TomazicM
    Jul 13, 2021 at 10:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.