here map pointerenter not working with polyline grupe, but tap is working - addeventlistener

I try to do arrow polyline (like here https://developer.here.com/documentation/maps/3.1.30.17/dev_guide/topics/routing.html -> Show route direction arrows). And I want to add to this routeLine pointerenter event, to make it hold and drag to add endpoints and recalculate road. But then I add pointerevents nothing happens. Tap is working, but pointerenter no. I found only one solution is use use MapEvents, but I have it imported https://js.api.here.com/v3/3.1/mapsjs-mapevents.js, so, as I understand this, it should work.
My code now is really simple:
displayOnMap(result) {
if (result.routes.length) {
result.routes[0].sections.forEach((section) => {
let linestring = H.geo.LineString.fromFlexiblePolyline(section.polyline)
let routeOutline = new H.map.Polyline(linestring, {
style: {
lineWidth: 10,
strokeColor: 'rgba(0, 128, 255, 0.7)',
lineTailCap: 'arrow-tail',
lineHeadCap: 'arrow-head'
}
});
let routeArrows = new H.map.Polyline(linestring, {
style: {
lineWidth: 10,
fillColor: 'white',
strokeColor: 'rgba(255, 255, 255, 1)',
lineDash: [0, 2],
lineTailCap: 'arrow-tail',
lineHeadCap: 'arrow-head'
}
}
);
let routeLine = new H.map.Group({
volatility: true,
objects: [routeOutline, routeArrows]
})
//why pointerenter is not working?
routeLine.addEventListener('pointerenter', function(evt) {
console.log('test 123', evt)
})
let startMarker = new H.map.Marker(section.departure.place.location)
let endMarker = new H.map.Marker(section.arrival.place.location)
this.routeObjects = [routeLine, startMarker, endMarker]
this.map.addObjects(this.routeObjects)
this.map.setCenter(section.departure.place.location)
})
}
};

OK, I found a solution. In this case addEventListener require third parameter (opt_capture) set on "true".Thanks to this group scope listen event listener.
routeLine.addEventListener('pointerenter', function(evt) {
console.log('test 123', evt)
}, true) //<- this true is a key

Related

ol3 ext-ol how can make cluster for different layers

I'm using ol3/ol4 with ol-ext
I create two layer:
clusterSource = new ol.source.Cluster({
distance: distanceFt,
source: new ol.source.Vector()
});
// Animated cluster layer
clusterLayer = new ol.layer.AnimatedCluster({
name: 'Cluster',
source: clusterSource,
animationDuration: 700, //$("#animatecluster").prop('checked') ? 700 : 0,
// Cluster style
style: getStyle
});
layersArray.push(clusterLayer); // adding to array
sourceReclamos_Eventos = new ol.source.Cluster({
distance: distanceFt,
source: new ol.source.Vector()
});
capaReclamos_Eventos = new ol.layer.AnimatedCluster({
name: "Reclamos_Eventos",
source: sourceReclamos_Eventos,
animationDuration: 700,
style: getStyle
});
layersArray.push(capaReclamos_Eventos);
Later, add that layers in:
selectCluster = new ol.interaction.SelectCluster({
layers: arraySelectCLuster,
// Point radius: to calculate distance between the features
pointRadius: 20,
animate: true, //$("#animatesel").prop('checked'),
// Feature style when it springs apart
featureStyle: featureStyle,
selectCluster: false, // disable cluster selection
});
After load the layers, only persist the Features in the first layer, in the second layer the Features is removed (clear) after zoom changing... why?
please, help
EDIT
I'm adding features using clusterLayer.getSource().addFeatures() and capaReclamos_Eventos.getSource().addFeatures().
function addFeatures_Reclamos_Eventos(ffs, centrar) {
var transform = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
var features = [];
for (var i = 0; i < ffs.length; i++) {
features[i] = new ol.Feature();
features[i].setProperties(ffs[i]);
var geometry = new ol.geom.Point(transform([parseFloat(ffs[i].lon), parseFloat(ffs[i].lat)]));
features[i].setGeometry(geometry);
}
qweFeature = features;
capaReclamos_Eventos.getSource().addFeatures(features);
removeloading('mapLoading');
if (document.getElementById('botonFiltrar')) {
document.getElementById('botonFiltrar').disabled = false;
}
if (centrar) {
window.setTimeout(function () {
var extent = capaReclamos_Eventos.getSource().getExtent();
map.getView().fit(extent, map.getSize());
}, 700);// 1/2 seg
}
}

Breadcrumbs in Highcharts large treemap [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a requirement to show breadcrumbs in High charts large tree map as we drill down the level.
As we drill down, need to show the name in the breadcrumbs and user should be able to navigate.
Something similar to the Breadcrumbs in highchart-treemap
But I could not find any solution. Let me know how to achieve this
Drilldown events are not available for a treemap series. Instead you can use point click event for displaying/destroying breadcrumb element - a label.
Disable drill up button:
Highcharts.seriesTypes.treemap.prototype.showDrillUpButton = function () {
this.drillUpButton = {
destroy: function () {}
}
}
Function for creating a breadcrumb element can look like this:
function makeNode(id, name, series, prev) {
const chart = series.chart
const node = {
id,
name
}
let x = chart.plotLeft
if (prev) {
const { width, height, y } = prev.element.getBBox()
x = width + prev.x + 10
node.prev = prev
prev.next = node
prev.element.attr({
anchorX: x,
anchorY: chart.plotTop - 20 + height / 2
})
}
node.destroyNext = function () {
const next = this.next
if (next) {
next.destroyNext()
next.element.destroy()
delete this.next
delete chart.bread[next.id]
}
}
const element = node.element = chart.renderer.label(name, x, chart.plotTop - 20, 'callout').attr({
fill: '#FFFFEF',
stroke: 'gray',
'stroke-width': 2,
padding: 5,
r: 5,
zIndex: 10
}).add()
element.on('click', () => {
node.destroyNext()
node.element.attr({
anchorX: undefined,
anchorY: undefined
})
if (chart.series[0].rootNode !== '') series.drillToNode(id)
})
node.x = x
return node
}
Call that function on chart load:
chart: {
events: {
load: function() {
this.bread = {
'': makeNode('', this.series[0].name, this.series[0])
}
}
}
},
and on point click event:
plotOptions: {
series: {
point: {
events: {
click: function(e) {
const hasChildren = !!this.node.childrenTotal
if (hasChildren) {
const bread = this.series.chart.bread
bread[this.id] = makeNode(this.id, this.name, this.series, bread[this.node.parent])
}
}
}
}
}
},
Example and output
http://jsfiddle.net/z0zc1btk/

view.fit() using view.animate() in OpenLayers 3.20+

I have the following code, written for OpenLayers pre 3.20:
fitViewToFeature: function (viewer, feature) {
var pan = ol.animation.pan({
source: viewer.olView.getCenter(),
duration: 1000
})
var zoom = ol.animation.zoom({
resolution: viewer.olView.getResolution(),
duration: 1000
})
viewer.olMap.beforeRender(pan, zoom)
viewer.olView.fit(feature.getGeometry(), viewer.olMap.getSize(), {
padding: [ 100, 100, 100, 100 ],
constrainResolution: false,
maxZoom: 4
})
}
My question is how to translate this function into the new view.animate() syntax introduced in OpenLayers 3.20?
Or alternately, should I open a GitHub issue and request a new option to be added to view.animate?
You should be able to achieve the same animation in a much simpler way, with the duration option of ol.View#fit():
viewer.olView.fit(feature.getGeometry(), {
duration: 1000
});
The above works in OpenLayers 4.x.
#zsero, I use the same function to zoom to the extent of a layer source. I use view.animate() for up to half of my route and at the callback function I use view.fit().
I need to setTimeout on the view.fit() otherwise I have an error message:
Cannot read property 'length' of null at ol.View.updateAnimations_
var origine = view.getCenter();
var destination = ol.extent.getCenter(extent);
var middleDestination = [(origine[0] + destination[0]) / 2, (origine[1] + destination[1]) / 2];
var viewFit = function() {
setTimeout( function() {
view.fit(extent, map.getSize(), {
duration: duration / 2,
padding: [ 64, 10, 10, 328 ],
constrainResolution: false
})
}, 0)
}
var animation = function() {
view.animate({
center: middleDestination,
duration: duration / 2
});
view.animate({
zoom: zoom - backZoom,
duration: duration / 2
}, viewFit);
}

How to show one label per multi-polygon in open layers 3?

I'm having an issue trying to figure out how to show one label per multipolygon in OL3. It currently shows the label for every polygon which is not ideal under any circumstance in this particular scenario.
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
format: new ol.format.GeoJSON(),
projection: 'EPSG:4326',
url: 'resources/ol3/countries.geojson'
}),
style: function (feature, resolution) {
style.getText().setText(resolution < 10000 ? feature.get('NAME') : '');
style.getFill().setColor('rgba(255, 255, 255, 0)');
return styles;
}});
I'd like to show the label on the largest polygon if possible.
One more option for the client side is to label just the bigger one, out of the polygon parts of the multipolygon.
For this option you dont need any control on the server-side. So use the following code or go direclty to the fiddle to see it in action:
var vector = new ol.layer.Vector({
style: function (feature, resolution) {
var polyStyleConfig = {
stroke: new ol.style.Stroke({
color: 'rgba(255, 255, 255, 1)',
width: 1
}),
fill: new ol.style.Fill({
color: 'rgba(255, 0, 0,0.3)'
})
}
var textStyleConfig = {
text:new ol.style.Text({
text:resolution < 100000 ? feature.get('NAME') : '' ,
fill: new ol.style.Fill({ color: "#000000" }),
stroke: new ol.style.Stroke({ color: "#FFFFFF", width: 2 })
}),
geometry: function(feature){
var retPoint;
if (feature.getGeometry().getType() === 'MultiPolygon') {
retPoint = getMaxPoly(feature.getGeometry().getPolygons()).getInteriorPoint();
} else if (feature.getGeometry().getType() === 'Polygon') {
retPoint = feature.getGeometry().getInteriorPoint();
}
console.log(retPoint)
return retPoint;
}
}
var textStyle = new ol.style.Style(textStyleConfig);
var style = new ol.style.Style(polyStyleConfig);
return [style,textStyle];
},
source: new ol.source.Vector({
url: 'http://openlayers.org/en/v3.8.2/examples/data/geojson/countries.geojson',
format: new ol.format.GeoJSON(),
wrapX: false
})
});
You also need a helper function to verify which one is the bigger polygon:
function getMaxPoly(polys) {
var polyObj = [];
//now need to find which one is the greater and so label only this
for (var b = 0; b < polys.length; b++) {
polyObj.push({ poly: polys[b], area: polys[b].getArea() });
}
polyObj.sort(function (a, b) { return a.area - b.area });
return polyObj[polyObj.length - 1].poly;
}
What you want to do is not supported by ol3, at least not 'natively'. There are several ways to accomplish what you want but I don't think doing it on the 'client side' is the best approach.
1 - Simple and fast way, server-side
If you have control over your data / server, then I'd manage which label to show from there. You could create a 'label-specific' field that contains a copy of the text you want to show, and for those you don't leave it blank. That would work if you only want the biggest chunk of island to always have the label.
2 - complex and slow way - client-side
On the client side, in your style function, you could loop in each feature and collect those having the same name as the feature attempting to be labelled, then compare their geometry area. Only label the feature if it has no other features of the same name having a bigger area.
This solution could also be implemented on the server-side. You could return an extra field with value 1 if the feature is the one with the largest area among those sharing the same name, and 0 if it doesn't. You would only label features with this field = 1.

highcharts - chart names for multiple pie chart series in one chart

I need to display multiple pie charts that are all related to the same data. As such I want them all to be part of the same chart and implement them as individual series.
This all works no problems until I tried to put labels/titles over each individual pie chart. It seems that I can only have a title over the entire group. See jsfiddle
Is there any way to have the titles over each chart?
See above jsfiddle for example
I encountered the same problem, and found this solution via highcharts support forum :
http://highcharts.uservoice.com/forums/55896-general/suggestions/3073133-pie-title
The Highcharts dude has written a plugin that you can see working on the following jsfiddle : http://jsfiddle.net/highcharts/tnSRA/
I have copy-pasted this plugin in a highcharts-plugins.js file that I included in my website, works like a charm!
Here's the plugin code :
/**
* Pie title plugin
* Last revision: 2012-12-21
*/
(function (Highcharts) {
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
var chart = this.chart,
center = this.center || (this.yAxis && this.yAxis.center),
titleOption = this.options.title,
box;
proceed.call(this);
if (center && titleOption) {
box = {
x: chart.plotLeft + center[0] - 0.5 * center[2],
y: chart.plotTop + center[1] - 0.5 * center[2],
width: center[2],
height: center[2]
};
if (!this.title) {
this.title = this.chart.renderer.label(titleOption.text)
.css(titleOption.style)
.add()
.align(titleOption, null, box);
} else {
this.title.align(titleOption, null, box);
}
}
});
}(Highcharts));
And this is how you configure your title (put this in your series elements) :
title: {
// align: 'left',
// x: 0
// style: { color: XXX, fontStyle: etc }
text: '<b>Pie 1</b><br>Subtext',
verticalAlign: 'top',
y: -40
},
To further improve on this, the code below correctly handles left, center, and right justification for the titles. See fiddle at http://jsfiddle.net/9y4Lj4yr/ for an example.
/**
* Pie title plugin
* Last revision: 2015-5-20
*/
(function (Highcharts) {
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
var chart = this.chart,
center = this.center || (this.yAxis && this.yAxis.center),
titleOption = this.options.title,
box;
proceed.call(this);
if (center && titleOption) {
box = {
x: chart.plotLeft + center[0] - 0.5 * center[2],
y: chart.plotTop + center[1] - 0.5 * center[2],
width: center[2],
height: center[2]
};
if (!this.title) {
this.title = this.chart.renderer.label(titleOption.text)
.css(titleOption.style)
.add()
}
var labelBBox = this.title.getBBox();
if (titleOption.align == "center")
box.x -= labelBBox.width/2;
else if (titleOption.align == "right")
box.x -= labelBBox.width;
this.title.align(titleOption, null, box);
}
});
} (Highcharts));
You can use renderer which allows to add text in any place.
http://api.highcharts.com/highcharts#Renderer.text()
Improving on Vincent's answer. This is how I used it for simple Text titles.
extendHighcharts = function(){
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
//Clear the title if added previously
//if your chart data does not change, this reference storage for removal can be left out
if(this.chart.subChartTitleElement){
this.chart.subChartTitleElement[this.id].destroy();
}
proceed.call(this);
if (this.center && this.options.title) {
//first, add the title, at center or anywhere, we need the container width to center it
this.chart.subChartTitleElement[this.id] = this.chart.renderer.text(this.options.title.text,this.center[0],this.center[1]);
this.chart.subChartTitleElement[this.id].css(this.options.title.style)
this.chart.subChartTitleElement[this.id].add();
//Center the title using the container(Bounding Box = BBox) width
var xCenter = this.chart.plotLeft + this.center[0] - (this.chart.subChartTitleElement[this.id].getBBox().width/2),
yCenter = this.chart.plotTop + this.center[1] - 0.6 * this.center[2];
this.chart.subChartTitleElement[this.id].attr(
{
x:xCenter,
y:yCenter
}
);
}
});
}
USAGE
this.chart.addSeries({
type: 'pie',
name: 'pie_chart_1',
data: pieChartData,
center: ['80%','25%'],
size: '35%',
showInLegend: false,
dataLabels: {
enabled: false
},
//this part adds the relevant information
title: {
text:'Pie Chart Title',
verticalAlign: 'top',
y: -40
},
id:'a_unique_id_or_name'
});

Resources