add each dataLabel a function on mouseover/mouseout - highcharts

I want to add each dataLabel a (just call it "highlightPoint()") function on a mouseover event. It works, if I add this function to a single point.
chartObj.series[0].data[1].dataLabel.on("mouseover", function () {
chartObj.series[0].data[1].setState('hover');
});
It doesn't work if I loop threw my data points. I guess the reference to each individual point is incorrect or something like that.
jsfiddle-link

After you have looped through both data sets, i = 2 and k = 1. So the mouse events are always trying to use i=2 and k=1 to access the data point, which of course is out of bounds. See this fiddle: http://jsfiddle.net/bLvfS/1/
for (var i = 0; i < chartObj.series.length; i++) {
for (var k = 0; k < chartObj.series[i].data.length; k++) {
var onmouseover = function(u, j) {
return function() {chartObj.series[u].data[j].setState('hover');};
}
var onmouseout = function(u, j) {
return function() {chartObj.series[u].data[j].setState();};
}
chartObj.series[i].data[k].dataLabel.on("mouseover", onmouseover(i,k));
chartObj.series[i].data[k].dataLabel.on("mouseout", onmouseout(i,k));
}
}
I've added functions that get passed the current i,k pair and return the actual function you want to run on the mouse events. Maybe someone has a better solution... but it seems to work.

Problem is with closures, see working fiddle: http://jsfiddle.net/Fusher/bLvfS/2/
for (var i = 0; i < chartObj.series.length; i++) {
for (var k = 0; k < chartObj.series[i].data.length; k++) {
(function(i,k){
chartObj.series[i].data[k].dataLabel.on("mouseover", function () {
chartObj.series[i].data[k].setState('hover');
});
chartObj.series[i].data[k].dataLabel.on("mouseout", function () {
chartObj.series[i].data[k].setState();
});
})(i,k);
}
}

Related

AddEventListener only works with the last picture

I have one problem. addEventListener only works with the last element of the loop. I know what is the problem, but I can't figure it out. I get the JSON object from another function with the information. Later on the left side there should be clickable pictures. After clicking it I should get the same picture on the right side showed. Still it works only with the last one.
function myFunction(obj) {
var listItems = document.getElementsByClassName("newimg");
for (var i = 0; i < obj.length; i++) {
(function (i) {
document.getElementById("imgSmall").innerHTML += `<br></br><img id="${i}" class="newimg" src=${obj[i].download_url} >`;
let p = obj[i];
listItems[i].addEventListener('click', function() { makeithappen(p);},true);
}(i));
//obj[i].width,obj[i].height,obj[i].author,obj[i].download_url>
}
}
function makeithappen(k) {
document.getElementById("imgLarge").innerHTML = `<br class="text"> AUTHOR: ${k.author}, WIDTH: ${k.width}, HEIGHT: ${k.height}</br><img class="img2" src=${k.download_url} >`;
}
For quick fix.
Replace in your code
listItems[i].addEventListener('click', function() { makeithappen(p);},true);
with
listItems[i].onload = function() {
listItems[i].addEventListener('click', function () { makeithappen(p); }, true);
}
So when you got your listItems you weren't finished with the creation of more images. So new image means new list.
for (let i = 0; i < obj.length; i++) {
document.getElementById("imgSmall").innerHTML += `<br></br><img id="${i}" class="newimg" src=${obj[i].download_url}>`;
const listItems = document.getElementsByClassName("newimg");
listItems[i].addEventListener('click', function () { makeithappen(p); }, true);
}
function makeithappen(k) {
document.getElementById("imgLarge").innerHTML = `<br class="text"> AUTHOR: ${k.author}, WIDTH: ${k.width}, HEIGHT: ${k.height}</br><img class="img2" src=${k.download_url} >`;
}
Pleas do refactor <br></br> into something with css, margin or padding or whatever. This will then allow you to create the images with let div = document.createElement('img') and bind the event listener directly div.addEventlistener(...)

Where is threshold for cluster strategy in openlayers 3?

In openlayers 2.8 there was a threshold associated with the cluster strategy as per ticket https://trac.osgeo.org/openlayers/ticket/1815.
In openlayers 3 there is no mention of it anywhere (and the strategy paradigm seems to be gone as well).
http://openlayers.org/en/master/apidoc/ol.source.Cluster.html
Does anyone know if there exist a ticket for this feature?
The paradigm has changed considerably. In OpenLayers 3 you create a new layer, with a cluster style, and the "threshold" is set as a maxResolution, or minResolution in the layer's options.
Similar to:
var clusterLayer = new ol.layer.Vector({
visible: true,
zIndex: insightMap.totalServcies - element.SortOrder,
id: Id,
serviceId: element.Id,
minResolution: clusteringThreshold,
cluster: true,
});
You can also use minZoom and maxZoom according to the documentaiton, but I've encountered issues with them performing consistently.
Update
It's actually possible to have a proper cluster threshold without recompiling the library. You need to use the geometry of each feature (from the features property of the cluster) in the style function.
const noClusterStyles = [];
vectorLayer.setStyle(feature => {
const features = feature.get('features');
if (features.length > 5) {
return clusterStyle;
} else {
for (let i = 0; ii = features.length; i < ii; ++i) {
const clone = noClusterStyles[i] ? noClusterStyles[i] : noClusterStyle.clone();
clone.setGeometry(features[i].getGeometry());
noClusterStyles[i] = clone;
}
noClusterStyles.length = features.length;
return noClusterStyles;
}
});
Thank you to #ahocevar for the code snippet.
Another solution would require modifying the OL3 library itself.
The ol.source.Cluster.prototype.cluster_ function has the following code snippet :
var neighbors = this.source_.getFeaturesInExtent(extent);
ol.DEBUG && console.assert(neighbors.length >= 1, 'at least one neighbor found');
neighbors = neighbors.filter(function(neighbor) {
var uid = ol.getUid(neighbor).toString();
if (!(uid in clustered)) {
clustered[uid] = true;
return true;
} else {
return false;
}
});
// Add the following
// If one element has more too many neighbors, register it as a cluster of one
// Size-based styling should be handled separately, in the layer style function
let THRESHOLD= 3;
if(neighbors.length > THRESHOLD) {
this.features_.push(this.createCluster_(neighbors));
} else {
for(var j = 0 ; j < neighbors.length ; j++) {
this.features_.push(this.createCluster_([neighbors[j]]));
}
}

Updating a point in a line chart when data grouping is in effect

I need to update a specific point in the chart when new data arrives. I've written the following function:
function updatePoint(series, x, y) {
for (i = 0; i < series.data.length - 1; i++) {
var point = series.data[i];
if (point.x === x) {
point.update(y);
return;
}
}
}
This works fine, unless the chart has more than turboThreshold points, in which case the series.data is gone, and I only have series.xData and series.yData to work with. I tried the following variant, but the chart does not actually update:
function updateTurboPoint(series, x, y) {
for (i = 0; i < series.xData.length; i++) {
if (series.xData[i] === x) {
if (series.yData.length > i) {
series.yData[i] = y;
return;
}
}
}
}
Setting a breakpoint on the return, I verified that series.yData[i] has the new value, even though it did not appear on the chart. How can I get this to actually update the chart?
I am using HighStock 2.0.4.
EDIT: Created a JSFiddle: http://jsfiddle.net/swish014/2unh1cLa/
EDIT: Changed the title, as I (now) do not believe turbo mode has anything to do with it.
The two comments were key to figuring out my own problem.
It is related to dataGrouping (and not turbo mode as I first thought).
The series.points array does exist, and updating a point there does update the chart as desired.
In my question, I listed two separate functions to update points, but I believe I can use just one function:
function updatePoint(series, x, y) {
for (i = 0; i < series.points.length - 1; i++) {
var point = series.points[i];
if (point.x === x) {
point.update(y);
return;
}
}
}

Titanium WebView.toImage on coverFlowView

A have several views with WebViews on them. I need to make it in a coverFlowView. For that i make my views toImage, to put after on the coverFlow, but the issue is that i get images with webView not loaded... I tried to make setTimeout, but it doesn't help.
var cover = Titanium.UI.iOS.createCoverFlowView({
images: forflowImages
});
for (var k = start; k < cData.length; k++) {
r = Ti.UI.createView({});
for (var j = 0; j < child.objects.length; j++) {
tmp = Ti.UI.createWebView({
left : 10,
top : 10,
right : 10,
bottom : 10,
width : Ti.UI.FILL,
height : Ti.UI.SIZE,
willHandleTouches: true,
backgroundColor : '#fff2df',
});
tmp.html = obj.html;
no.add(tmp);
r.add(no);
}
}
r.addEventListener("load", function(e) {
blob = r.toImage();
});
forflowImages.push(blob);
}
cover.setImages(forflowImages);
With this code, coverFlowView doesn't have any views.
setTimeout(function() {
blob = r.toImage();
}, 500);
Also doesn't help, i have activity indicator on the page saved, content seems didn't have time to load before toImage function acted.
You are ordering things the wrong way, and you have multiple syntax errors, also you are listeneing for the load event on the wrong type of view, you shold be listeneing on the WebView, try this instead:
var forflowImages = [];
var container = // This should already be in the view stack somewhere
var cover = Titanium.UI.iOS.createCoverFlowView();
function loadListener(e) {
forflowImages.push(e.source.toImage());
if(forFlowImages.length == child.objects.length) {
// We have all the images for cover flow
cover.setImages(forflowImages);
}
}
var containerView = Ti.UI.createView();
for (var j = 0; j < child.objects.length; j++) {
var tmp = Ti.UI.createWebView({html : obj.html);
tmp.addEventListener("load", loadListener);
container.add(tmp);
tmp.repaint();
}
I removed some of your code that was syntactically incorrect and trimmed it down so it would be easy to understand. All this code does is add an event listener that handles the conversion of a webview to an image.

my shapes aren't changing colors I'm not sure why

I have a code that draws a bunch of customized shapes from an xml... I want to make each shape select-able /de-selectable by changing the color of the object and changing backk all other colors when things change but my codes broken but i'm not getting any errors or anything it just doesn't work.
var graphicsShape
function drawLayer(layer){
for (var i =0; i < xmlDoc.getElementsByTagName("polygon").length; i++)
{
if (layer == xmlDoc.getElementsByTagName("polygon")[i].childNodes[0].attributes[4].value)
{ drawSegment(i);
}
}
}
// layer = index z
function drawSegment(a){
var vertexList = xmlDoc.getElementsByTagName("polygon")[a].childNodes;
var graphicsObject = new createjs.Graphics();
graphicsShape = new createjs.Shape(graphicsObject);
graphicsObject.setStrokeStyle(1);
graphicsObject.beginStroke(createjs.Graphics.getRGB(0,0,0));
graphicsObject.beginFill(createjs.Graphics.getRGB(255,0,0));
for(var i = 0; i < vertexList.length; i++){
graphicsObject.lineTo(vertexList[i].attributes[2].value, vertexList[i].attributes[3].value)
stage.addChild(graphicsShape);
}
segmentsArray.push(graphicsShape);
//createContainer(segmentsArray[i]);
}
function createArraysForSegments() {
for(var i=0; i <segmentsArray.length; i++){
segmentsData[i] = new Array;
}
}
function ColorChangeAddEventListener() {
for(var i = 0; i < segmentsArray.length; i++){
segmentsArray[i].addEventListener('click', colorChange(i));
}
}
function colorChange(index){
segmentsArray[index].graphics.beginFill('white');
stage.update();
}
i call the functions later
ColorChangeAddEventListener();
drawLayer(0);
stage.update();
if i type segmentsArray[0].alpha =0.5; it works for that shape, but when I put it in segmentsArray[0].addEventsListener('click', function){segmentsArray[0].alpha=0.5;}) that doesn't work
Just setting the beginFill won't affect the current shape, you will also have to segmentsArray[index].graphics.clear() and redraw the shape.
beginFill() is not the setter for a property but rather a command that affects subsequents commands, like drawRect() for example.

Resources