Chart.js (line chart) tooltip duration/delay - javascript

There does not seem to be any option or implementation on showing the tooltip for a second or two before it dissapears when going from a hovering to non-hovering state. So when you have your mouse hovering over the tooltip, great, it shows but then when you remove your mouse from the point I would like to have that showing for an extra 2 seconds instead of dissapearing instantly as it does currently.
What I've done so far
I've looked through the documentation and the available tooltip options. It has a customTooltip function available but that is for when you want to implement a completely custom tooltip.
Gone through the chart.js line chart's codebase where it attaches the events and can't seem to figure out how to add in a delay.
Seen the 'mouseout', 'mouseover' events array list of strings but can't seem to figure out how to use them.
Can someone please point me in the right direction as to what I need to do on implementing this delay/fade effect on the tooltip.

The tooltips are cleared by the showTooltip function (the redraw clears off the existing tooltips). So one naïve way would be to hook into this to introduce your delay, like so
var data = {
labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
datasets: [
{
data: [12, 23, 23, 43, 45, 12, 33]
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myLineChart = new Chart(ctx).Line(data);
var originalShowTooltip = myLineChart.showTooltip;
var timeout;
myLineChart.showTooltip = function (activeElements) {
var delay = (activeElements.length === 0) ? 2000 : 0;
clearTimeout(timeout);
timeout = setTimeout(function () {
originalShowTooltip.call(myLineChart, activeElements);
}, delay);
}
This delays the tooltips if the chart is going to clear off all tooltips.
Notice that there is no delay in removing the old tooltip if you move on to another tooltip. If you want it this to be a delayed disappearance, you'll need to maintain your own array of active points pushing in elements (instantaneously) / popping out elements (with a delay)
Fiddle - http://jsfiddle.net/zubynd0c/

Related

visjs timeline - set initial vertical position of items

I'm using vis-timeline to render a hundred rows of data. When the component loads, I want to see the rows starting from the beginning: 1, 2, 3, and so on. Instead, by default, vis-timeline starts by displaying the end of the list (...97, 98, 99, 100), so that you have to scroll up to get to the top?
There are methods like setWindow() for setting the horizontal time frame, but what about the vertical position? I've tried the HTML scroll() method, but that doesn't seem to do anything.
Normally I would use orientation: { item: 'top' } } in the options, but there is a bug that prevents scrolling in that case; it must be set to 'bottom'.
I've thought about initializing the component with the orientation to 'top', then once it displays, setting it to 'bottom' to allow scrolling, but that seems pretty hacky.
Is there a cleaner solution?
You can implement a custom ordering function for items (groups as well) using the order configuration option:
Provide a custom sort function to order the items. The order of the
items is determining the way they are stacked. The function order is
called with two arguments containing the data of two items to be
compared.
WARNING: Use with caution. Custom ordering is not suitable for large
amounts of items. On load, the Timeline will render all items once to
determine their width and height. Keep the number of items in this
configuration limited to a maximum of a few hundred items.
See below for an example:
var items = new vis.DataSet();
for (let i=0; i<100; i++) {
items.add({
id: i,
content: 'item ' + i,
start: new Date(2022, 4, 1),
end: new Date(2022, 4, 14)
});
}
var container = document.getElementById('visualization1');
var options = {
order: function (a, b) {
return b.id - a.id;
}
}
var timeline = new vis.Timeline(container);
timeline.setOptions(options);
timeline.setItems(items);
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis-timeline-graph2d.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" rel="script"></script>
<div id="visualization1"></div>

Chart.js updating-animations of radar-charts

I was not able to find an answer to the following what I think is best described by example:
I change one single value in radar-chart-data from 6 to 10 while the other ones stay the same. If I now trigger an update with non-zero animation-time it will repaint the chart while starting from zero for each value. I would prefer the animation to just animate the changing, i.e. a movement from 6 to 10 for the property in question. Is that possible?
Below is an example showing the chart updating without redrawing. Run the snippet and press the 'Update' button to increase data point b by 1 each time.
let myChart = new Chart(document.getElementById('chart'), {
type: 'radar',
data: {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [{
label: 'series1',
data: [0, 2, 7, 10, 3]
}]
},
options: {
maintainAspectRatio: false
}
});
document.getElementById('update').addEventListener('click', function() {
myChart.data.datasets[0].data[1] += 1;
myChart.update();
});
<button id="update">Update!</button>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="chart"></canvas>
Yes. It is possible. It depends on how you update the chart option. See chartjs documentations
To update the options, mutating the options property in place or passing in a new options object are supported.
If the options are mutated in place, other option properties would be preserved, including those calculated by Chart.js.
If created as a new object, it would be like creating a new chart with the options - old options would be discarded.

Plotly.js hover across multiple subplots

I have a plotly.js graph with multiple subplots that share an x-axis as in https://plot.ly/javascript/subplots/#stacked-subplots-with-a-shared-x-axis
I'm trying to hover across all of the subplots so that the values of all of the points with the same x value are displayed at once.
I've attempted to solve this by calling Plotly.Fx.hover on each subplot, but it only seems to take effect for the last subplot on which it is called.
http://codepen.io/john-soklaski/pen/adQwBa
The code I tried is:
Plotly.Fx.hover('myDiv', {xval: 2, curveNumber: 0}, "xy")
Plotly.Fx.hover('myDiv', {xval: 2, curveNumber: 1}, "xy2")
Ideally the API would be such that I could do this in a single call:
Plotly.Fx.hover('myDiv', [{xval: 2, curveNumber: 0, subplot: "xy"}, {xval: 2, curveNumber: 1, subplot: "xy2"}])
Any thoughts on how to get this to work?
I see this question is old, but this functionality has been added: https://github.com/plotly/plotly.js/pull/301
Plotly.plot('myDiv', data, layout);
graph = document.getElementById('myDiv');
graph.on('plotly_hover', function(eventdata) {
if (eventdata.xvals) {
Plotly.Fx.hover(graph, {
xval: eventdata.xvals[0]
}, ['xy', 'x2y2', 'x3y3', 'x4y4']);
}
});
For multiple subplots add the axis labels array also.
In this case
['xy', 'x2y2', 'x3y3', 'x4y4']
In this way you can get coupled hover events for subplots in a div
You'll have to pass the visible subplots as the third arg to Plotly.Fx.hover func.
This worked for me:
chartContainer.current.on('plotly_hover', function () {
var points = eventdata.points[0]
var pointNum = points.pointNumber
Plotly.Fx.hover(
chartContainer.current,
props.data.map((_, i) => ({
curveNumber: i,
pointNumber: pointNum
})),
Object.keys((chartContainer.current)._fullLayout._plots))
})
chartContainer.current is the div here.
Object.keys((chartContainer.current)._fullLayout._plots) will return the visible plots, for example: ['xy', 'xy2'...]

Show gap of missing data with Highstock

Using Highstock to chart a sorted time serie: [[timestamp, value], ...]
The datasource is sampled at irregular intervals. As result the distances between two points (in the time axis) varies.
If two adjacent points are separated for more than 5 minutes I want to show a gap in the chart.
Using the gapSize option doesn't work, because it doesn't allows to specify the 'size' of the gap as a function of time.
Showing gaps is already a part of Highstock, I just need a way to specify it as a fixed amount of time (5 minutes). Ideas?
Btw, beside that the plot works great.
Here's a slightly unclean way to "manipulate" gapSize to work so that it's value is the amount of milliseconds required to create a gap.
(function (H) {
// Wrap getSegments to change gapSize functionality to work based on time (milliseconds)
H.wrap(H.Series.prototype, 'getSegments', function (proceed) {
var cPR = this.xAxis.closestPointRange;
this.xAxis.closestPointRange = 1;
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
this.xAxis.closestPointRange = cPR;
});
}(Highcharts));
This utilizes that gapSize is only used within the getSegments function (see source), and it works based on the closestPointRange of the axis. It wraps the getSegments, sets closestPointRange to 1, calls the original method and then resets closestPointRange to its original value.
With the code above you could do gaps for 5 minutes like this:
plotOptions: {
line: {
gapSize: 300000 // 5 minutes in milliseconds
}
}
See this JSFiddle demonstration of how it may work.
Halvor Strand function wrapper did not work for me as long as getSegments is not part of highstock source code anymore to calculate that gap. Anyway, you can find an approximation to solve the problem combining this other topic and the previows answer like this:
(function(H) {
H.wrap(H.Series.prototype, 'gappedPath', function(proceed) {
var gapSize = this.options.gapSize,
xAxis = this.xAxis,
points = this.points.slice(),
i = points.length - 1;
if (gapSize && i > 0) { // #5008
while (i--) {
if (points[i + 1].x - points[i].x > gapSize) { // gapSize redefinition to be the real threshold instead of using this.closestPointRange * gapSize
points.splice( // insert after this one
i + 1,
0, {
isNull: true
}
);
}
}
}
return this.getGraphPath(points);
});
}(Highcharts))
setting gapSize in plotOptions to the desired size (in ms) like Halvor said:
plotOptions: {
line: {
gapSize: 300000 // 5 minutes in milliseconds
}
}
In case anyone comes across this and is spending hours trying to figure out why gapSize is not working like me. Make sure your time series data is sorted, only then will the gaps appear in the graph.
Another issue I ran into was my data series was in this format
[
{x: 1643967900000, y: 72},
{x: 1643967600000, y: 72},
{x: 1643967300000, y: 72}
]
However this does not seem to work with gapSize and needs to be in the format below
[
[1643967900000, 72],
[1643967600000, 91],
[1643967300000, 241]
]

three.js animate a Mesh with Color transition (tween.js)

I'm getting crazy trying to achieve this. I want to change the color of a mesh(ConvexGeometry) when I hovered, until here I can do it without any problem, I can change the color of the mesh.
The problem comes when I want to make it with a color transition/interpolation from a to b, right now I'm using tween.js but its not working. I don't know if the mesh support a material color transition, or the problem is other...I would appreciate any help on this.
I can´t find any example doing this...only this similar approach.
In any case, when I hovered the object I'm doing the follow:
var tween = new TWEEN.Tween(INTERSECTED.material.materials[0].color)
.to({r: 0, g: 25, b: 155}, 5000)
.easing(TWEEN.Easing.Quartic.In)
.onUpdate(function() {
INTERSECTED.material.materials[0].color.r = this.r;
INTERSECTED.material.materials[0].color.g = this.g;
INTERSECTED.material.materials[0].color.b = this.b;
}).start()
Basically you need to do tween.update(time) for each requested animation frame.
I hvae modified an example from threejs.org to demonstrate this: http://jsfiddle.net/up1wg1Lo/2/
Note that I add parameter to animte and render so that they can know the tick. Also note the usage of tween.update(time) on line 143
A simple color tween using TweenLite:
var col = new THREE.Color('#ff00ff');
TweenLite.to(mesh.material.color, 1, {
r: col.r,
g: col.g,
b: col.b,
});
If you want to optimize performance and be 100% accurate you should do the computation step on your tween in each render frame, But its really not necessary to do so for a color tween usually:
This is using gsap, which has never failed me:
var initial = new THREE.Color(target.material.color.getHex());
var value = new THREE.Color(value.color.getHex());
TweenLite.to(initial, 1, {
r: value.r,
g: value.g,
b: value.b,
onUpdate: function () {
target.material.color = initial;
}
});
}

Categories

Resources