I use leaflet to show data for users on a map. I also use different leaflet plugins.
One of them is the leaflet.timedimension plugin so a user can scroll through WMS layers valid at different times. But I have trouble figuring out how to make the period of timeDimensionsOptions selectable by the user.
I have set the period to 1 hour (PT60MIN), but some of my data are in 15 minutes interval (PT15MIN). What is the appropriate approach to let the user select the period or change the period based on the selected product?
I initialise my map like so:
var map = L.map('mapid', {
zoom: 6,
fullscreenControl: true,
timeDimension: true,
timeDimensionControl: true,
scrollWheelZoom: true,
timeDimensionOptions:{
timeInterval: now + "/PT48H",
period: "PT60M"
},
timeDimensionControlOptions: {
autoPlay: false,
timeZones: ['utc'],
playerOptions: {
buffer: 0,
transitionTime: 500, // 1000/1500 ~ 0.7 fps
loop: true,
},
speedSlider: true,
limitSliders: true,
displayDate: true
position: 'bottomleft'
},
center: mapCenter: [56, 10],
minZoom: 4,
})
where period is the parameter that I would like to change dynamically.
I have made a MWE here of what I have now, but of course, without the option to change the period (timestep of the WMS layers). I am aware that the WMS layers do not work. I use a WMS-server behind a VPN wall, but it should not matter for the part related to timedimensions I hope.
My experience with javascript and leaflet is rather limited, so probably there is plenty of examples of bad practice.
Can you have the value of period changed by the user from a dropdown or input somewhere in the HTML?
let user_input = 'PT60M' // Let PT60M be the default.
// Get user_input somewhere, (i.e. from a HTML dropdown, radio button, you can
// easily test using javascript's `prompt()` before coding up a lot of html)
// addEventListener to that input and onChange, re-create the `L` object
// and return it to wherever you need it to. In your MWE it would be initMap()
// just have that function take a param for `L` and call initMap with the new 'L' from onChange when
// the user changes the time period.
L.map('mapid', {
...
timeDimensionOptions:{
timeInterval: now + "/PT48H",
period: user_input // Value selected by user.
},
timeDimensionControlOptions: {
...
})
Related
I am using Plotly.js to show a heatmap of electrochemical data. It works really well, however, sometimes the data matrix can be a bit large (3000x4000). I paste the code here if it is of any help, as it is a method of a class you will see many references to "this" to get the array, name strings, etc.
My main problem is that for large data arrays, the heatmap takes a lot to render when I load the data or press a button to replot, for example, after filtering. It usually takes approximately between 1500 - 2000 ms. By looking into Plotly.js issues, I have tried several things which did not work, or made it worse:
Use 'heatmapgl' as plot type instead of 'heatmap' when the data goes beyond a million points.
Use plotly.react() instead of plotly.newPlot(). It did not change although in the plotly.js reference they claim it is more efficient when replotting in the same division.
Remove the axes and ticks.
I have also tried to use a canvas to show the heatmap as an image.. but the fact that I need to cast the array to 0-255 and therefore lose resolution in the range of values is also not great for this particular application.
I was wondering if anyone new any other way to improve the performance of heatmaps in plotly.js or if they know of any other workaround. Thanks in advance!
//Function to plot the main color plot.
var graph_data = [{
z:this.current.array,
x:this.cycling_time.array,
type:this.plot_type,
colorscale:this.color_palette,
colorbar: {len:0.5, xpad:30, title:this.current.name+' ('+this.current.units+')'},
zsmooth: false
}];
this.plot_layout = this.plot_settings.plot_layout;
this.plot_layout.title.text = "<b>"+this.name_of_file+"</b>";
this.plot_layout.xaxis = {
title:this.cycling_time.name+' ('+this.cycling_time.units+')'
};
this.plot_layout.yaxis = {
title:'Samples'
};
console.time('plot');
Plotly.newPlot(div, graph_data, this.plot_layout, this.plot_settings.plot_configuration);
_(div).on('plotly_click', function(data){main_graph_clicked(data)});
console.timeEnd('plot');
Edit
The plot settings and configurations are below. I keep them separated because I use them in several different plots and it saves space to save them in the class.
this.plot_configuration = {
showEditInChartStudio: true,
plotlyServerURL: "https://chart-studio.plotly.com",
displayModeBar: true,
displaylogo: false,
responsive: true,
toImageButtonOptions: {
format: 'svg',
filename: 'plot',
height: 600,
width: 800,
scale: 1
}};
this.plot_layout = {
autosize: true,
title: {
text: '<b> Blank </b>',
font: {
size: 20,
family:'Arial'
},
x: 0.05,
y: 1.2,
xanchor: 'left',
yanchor: 'bottom',
}
};
I using LayerSlider to make carousel on my website. Now when I click to Prev/Next button, the slider move to the first layer automatically.
I want to custom my Javascript. Click next to get next layer, not get the first layer. Here is my code:
var sliderObject = lsjQuery("#layerslider_6").layerSlider({
// height : __height,
responsive: false,
responsiveUnder: 1900,
layersContainer: 1900,
pauseOnHover: false,
navStartStop: false,
twoWaySlideshow: true,
navButtons: false,
// skin : 'fullwidth',
showCircleTimer: false,
cbInit: function (data) {
matchSizeLayerElement();
},
cbAnimStart: function (data) {
matchSizeLayerElement();
// console.log('Animate Start' + (new Date().getTime() / 1000));
},
cbAnimStop: function (data) {
matchSizeLayerElement();
// console.log('Animate Stop' + (new Date().getTime() / 1000));
},
cbPrev : function(data){
console.log('Click Prev');
},
cbNext : function(data){
console.log('Click Next');
},
});
lsjQuery("#layerslider_6").layerSlider('start');
I was searching more and more times, but I counln't any solutions.
Sorry for my bad English.
Each answers will become the God save my life!
Check out the API Methods section of the LayerSlider documentation, I believe it has the information you're looking for.
// moves to the layer after the current layer:
lsjQuery("#layerSlider_6").layerSlider('next');
// moves to the layer before the current layer:
lsjQuery("#layerSlider_6").layerSlider('prev');
// moves to the 4th layer (regardless of current layer):
lsjQuery("#layerSlider_6").layerSlider(4);
Im Trying to implement a heatmap to Leaflet via the Leafletplugin//www.patrick-wied.at/static/heatmapjs/plugin-leaflet-layer.html,
but for some reason it seams to ignore my "Value" so all datapoints have the same colour
window.onload = function() {
var baseLayer = L.tileLayer(
'http://{s}.www.toolserver.org/tiles/bw-mapnik/{z}/{x}/{y}.png',{
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
maxZoom: 20
}
);
var cfg = {
// radius should be small ONLY if scaleRadius is true (or small radius is intended)
"radius": 0.00007,
minOpacity: 0.5,
maxOpacity: 1,
// scales the radius based on map zoom
"scaleRadius": true,
// if set to false the heatmap uses the global maximum for colorization
// if activated: uses the data maximum within the current map boundaries
// (there will always be a red spot with useLocalExtremas true)
"useLocalExtrema": false,
// which field name in your data represents the latitude - default "lat"
latField: 'lat',
// which field name in your data represents the longitude - default "lng"
lngField: 'lng',
// which field name in your data represents the data value - default "value"
value: 'sig',
blur:0,
gradient: {
// enter n keys between 0 and 1 here
// for gradient color customization
'1': 'red',
'.3': 'yellow',
'0.9': 'green'
},
};
var heatmapLayer = new HeatmapOverlay(cfg);
var map = new L.Map('map-canvas', {
center: new L.LatLng(52.400458, 13.052260),
zoom: 14,
layers: [baseLayer, heatmapLayer]
});
heatmapLayer.setData(testData);
// make accessible for debugging
layer = heatmapLayer;
};
my data looks like this:
var testData = {
data:[{lat:52.40486, lng:13.04916, sig:30}, {lat:52.40486, lng:13.04916, sig:70}, {lat:52.40496, lng:13.04894, sig:67}, {lat:52.40496, lng:13.04894, sig:72}, {lat:52.40486, lng:13.04916, sig:74}, {lat:52.40486, lng:13.04916, sig:78}, {lat:52.40493, lng:13.04925, sig:67},]}
you can se it live on http://www.frief.de/heatmap/test2.html
would be great if someone has an idea, mybe Im just to stupid
Just a quick suggestion.
Have you tried using the Leaflet.Heatmap plug-in by Vladimir Agafonkin(the author of Leaflet.js himself). It seems it's not listed on the plug-ins page.
I think it's faster and probably will be a better solution: https://github.com/Leaflet/Leaflet.heat
http://mourner.github.io/simpleheat/demo/
I think this is not working because your code is wrong around here:
<div class="wrapper">
<div class="heatmap" id="map-canvas">
</div>
</div>
</script> <----THIS <script src="src/heatmap.js"></script>
<script src="src/leaflet-heatmap.js"></script>
Open link you said is a demo page and inspect code. Fix this orphaned </script tag and see if it's working now.
I know this is old, but I just ran into this issue, so here's how I solved it.
In the library "pa7_leaflet_hm.min.js" there's a part where it sets the min/max values, and it's hardcoded to 1 and 0
this._data = [];
this._max = 1;
this._min = 0;
Apparently this controls the intensity of the spots based on the value, and this is only overwritten if useLocalExtrema is set to false, which would always set it to the highest visible spot.
If you don't wish to always check the highest value based on the visible area, you can just change the this._max value to something higher, or maybe even set it to a value from the config, to expose it
this._data = [];
this._max = (this.cfg.max ? this.cfg.max : 1);
this._min = (this.cfg.min ? this.cfg.min : 0);
this way you would get a more traditional functioning heatmap
I am new to client-side programming. Thus far I've been writing only asp and php based solutions. But now I need to retrieve data from json and plot on a map (I don't know how to do that yet, but this is later).
After days of searching, I think OpenLayers can give me what I need.
I have gone through the Examples on dev.openlayers site, (such as this one http://dev.openlayers.org/releases/OpenLayers-2.13.1/examples/vector-features-with-text.html), and also searched (and found some) solutions on stackoverflow, but they don't offer solutions to my problems).
Please view what I've done so far:
http://www.nusantech.com/bangkuujian/openlayer.html
The canvas.js is as follows:
// create some sample features
var Feature = OpenLayers.Feature.Vector;
var Geometry = OpenLayers.Geometry;
var features = [
new Feature(new Geometry.Point(-220, -60),attributes = { name: "Mercury",align: "cm",xOffset:10,yOffset:50 }),
new Feature(new Geometry.Point(-70, 120),attributes = { name: "Venus" }),
new Feature(new Geometry.Point(0, 0),attributes = { name: "Earth" }),
new Feature(new Geometry.Point(160, -100),attributes = { name: "Mars",align: "cm",xOffset:10,yOffset:50 })];
// create rule based styles
var Rule = OpenLayers.Rule;
var Filter = OpenLayers.Filter;
var style = new OpenLayers.Style({
pointRadius: 10,
strokeWidth: 3,
strokeOpacity: 0.7,
strokeColor: "#ffdd77",
fillColor: "#eecc66",
fillOpacity: 1,
label : "${name}",
fontColor: "#f0f0f0",
fontSize: "12px",
fontFamily: "Calibri, monospace",
labelAlign: "${align}",
labelXOffset: "${xOffset}",
labelYOffset: "${yOffset}",
labelOutlineWidth : 1
},
{
rules: [
new Rule({
elseFilter: true,
symbolizer: {graphicName: "circle"}
})
]
});
var layer = new OpenLayers.Layer.Vector(null, {
styleMap: new OpenLayers.StyleMap({'default': style,
select: {
pointRadius: 14,
strokeColor: "#e0e0e0",
strokeWidth: 5
}
}),
isBaseLayer: true,
renderers: ["Canvas"]
});
layer.addFeatures(features);
var map = new OpenLayers.Map({
div: "map",
layers: [layer],
center: new OpenLayers.LonLat(50, 45),
zoom: 0
});
var select = new OpenLayers.Control.SelectFeature(layer);
map.addControl(select);
select.activate();
What I have problems with:
Label offset
In the samples, the labels should offset from the centre by labelXOffset: "(xvalue)", labelYOffset: "(yvalue)", but this is not happening in my page. Is there something I forgot?
Zoom-in
When I click the + button on the map, all the features look like they are zoomed in, however, the sizes of the features stay the same. How do I enlarge the features (circles) too?
Hit Detection
i) When I click on a circle, it is selected as designed. However, is it possible when I select a circle, I also change the right side (now there is a red "text here") and fill it up with html? Can you show me an example how to change the red "text here" to the label-name of the selected circle with a different colour?
ii) Secondly, after I select a circle, how do I add a label under all the other circles denoting the distance between each circle and the selected circle?
Thank you in advance, hopefully these questions are not too much.
I have another question about retrieving an array of coordinates from json to plot the circles, but I will do more research on that. If you can point me in the right direction with regards to this, it would be much appreciated too.
I know how to do them server-side asp or php, but client side is very new to me. However client-side can do all of this much-much faster and can reduce a lot of load.
Cheers,
masCh
I think I have managed to most of it.
Labels not offsetting
Not sure what I did, but I declared a WMS layer and made a few changes to offset and now it is offsetting correctly.
var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://hendak.seribudaya.com/starmap.jpg",
{
layers: "modis,global_mosaic",
}, {
opacity: 0.5,
singleTile: true
});
var context = {
getSize: function(feature) {
return feature.attributes["jejari"] / map.getResolution() * .703125;
}
};
var template = {
pointRadius: "${getSize}", // using context.getSize(feature)
label : "\n\n\n\n${name}\n${jarak}",
labelAlign: "left",
labelXOffset: "${xoff}",
labelYOffset: "${yoff}",
labelOutlineWidth : 0
};
var style = new OpenLayers.Style(template, {context: context});
And I declared xoff & yoff under new OpenLayers.Geometry.Point(x,y), { jejari:5, xoff: -10, yoff: -15 }
2) Zoom in on point features.
This was a weird problem. Anyway, I declared a radius called jejari as in the code above next to xoff and yoff. Then modified pointRadius from a static number to "${getSize}" And then added the getSize function to var template which retrieves the current radius. I think that was all I did for that. But the labels were running all over the place, I still haven't solved that.
3) Hit detection and changing another in html
This adds what happens to the once a point feature has been selected
layer.addFeatures(features);
layer.events.on({ "featureselected": function(e) {
kemasMaklumat('maklumat', "<FONT FACE='Calibri' color='#f0f0f0' size=5><center>"+
e.feature.attributes.name+
"<p>This is displayed text when a feature has been selected";
maklumat.style.color="black";
layer.redraw();
}
});
map.addLayers([layer]);
And in the html the and the kemasMaklumat function is declared as
<script type="text/javascript">
function kemasMaklumat(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
}
</script>
<td valign="top"><div id="maklumat" style="border-radius:25px; background-color:#000000;box-shadow: 8px 8px 4px #686868;">
Write Something Here<P>
</div></td>
The second part of this question was changing the labels of all the UNselected features, i.e. modifying attributes of all features that weren't the selected one. To do this, I added a for loop through all the features and check if it has the same label as the feature that was selected, this was done under the layer.events.on "featureselected" as was done in the above part 1 of this question.
layer.addFeatures(features);
layer.events.on({ "featureselected": function(e) {
kemasMaklumat('maklumat', "<FONT FACE='Calibri' color='#f0f0f0' size=5><center>"+
e.feature.attributes.name+
"<p>This is displayed text when a feature has been selected";
maklumat.style.color="black";
for (var i = 0, l = layer.features.length; i < l; i++) {
var feature = layer.features[i];
if (feature.attributes.name!=e.feature.attributes.name) {
feature.attributes.name="I was not selected"; }}
layer.redraw();
}
});
map.addLayers([layer]);
I'm trying a simple test where I have a base image with draggable features on top. These point features have associated external graphics (I'd prefer to use polygons with associated graphics but that's a whole other question).
I have a hover control that works perfectly. I also have a select control that almost works. However I cannot reselect a feature once I have clicked out once. Similarly, I cannot select features if I click anywhere outside of the features before trying to select one.
I hope that's clear - but if not then this example should be (and you can also see the whole code) http://sigfrid.co.uk/oltest/simple.html
I'll put what I think are the key bits of code below....
Create a map
var map = new OpenLayers.Map({
div:'map',
});
Add a base layer
var base = new OpenLayers.Layer.Image(
'Base level',
'img/base.png',
new OpenLayers.Bounds(-1000, -1000, 1000, 1000),
new OpenLayers.Size(864,864),
options
);
map.addLayer(base);
Add styles
var markerStyleMap = new OpenLayers.StyleMap
({
"default": new OpenLayers.Style(template, {context: context}),
"hover": new OpenLayers.Style ({graphicOpacity:0.5}),
"select": new OpenLayers.Style ({graphicOpacity:0.1})});
Add points
pt1 = new OpenLayers.Geometry.Point(0,0);
pt1Feature = new OpenLayers.Feature.Vector(pt1);
...
markerLayer.addFeatures([pt1Feature,pt2Feature,pt3Feature]);
Add unique lookup for the different marker images
var lookup = {
"f1": {externalGraphic:"img/f1.png"},
"f2": {externalGraphic:"img/f2.png"},
"f3": {externalGraphic:"img/f3.png"},
}
markerStyleMap.addUniqueValueRules("default", "type", lookup);
markerLayer.styleMap = markerStyleMap;
markerLayer.features[0].attributes.type = "f1";
...
Add controls
var dragControl = new OpenLayers.Control.DragFeature(markerLayer)
map.addControl(dragControl);
dragControl.activate();
var highlightCtrl = new OpenLayers.Control.SelectFeature(markerLayer, {
hover: true,
highlightOnly: true,
renderIntent: "hover",
});
map.addControl(highlightCtrl);
highlightCtrl.activate();
var selectCtrl = new OpenLayers.Control.SelectFeature(markerLayer, {
clickout: true,
renderIntent: "select",
});
map.addControl(selectCtrl);
selectCtrl.activate();
Thanks for any help,
Nick
Turns out drag and select are not compatible. However, there are some work arounds such as
http://fastr.wordpress.com/2012/04/17/openlayers-selectfeature-where-did-i-clicked-2/
although this does add some event problems...