How to reset scroll behaviour on zoom out? - javascript

I am using the lightning charts(in this case the chartXY) by arction for real time data visualization in my react application.When I zoom in using the mouse wheel or the zoom rectangle the chart stops scrolling as expected.When I zoom out the chart starts scrolling but does not follow the interval I set it to.Is there any way to reset the zoom to go back to the current point in real time.
X Axis configuration:
progressive scroll
interval(0,3000) //in milliseconds I presume
Series configuration:
data pattern Datapatterns.horizontalProgressive
I also cannot find a method to control the zoom Out rectangle please let me know if this is present.
Thanks in advance.

Normally when the zooming rectangle is used to zoom out, LightningChart JS will fit the view to the current data. In your case you would like to go back to the original axis interval. You can attach a listener to Axis.onScaleChange event. In this listener you can check if the new scale range would be larger than the original range. And if it is, set the axis interval back to the original range.
series.axisX
.onScaleChange((start, end) => {
if (end - start > intervalSize) {
series.axisX.setInterval(end - intervalSize, end)
}
})
The "Zoom out rectangle" is called "Fitting rectangle" in LightningChart JS. You can change the visual style of it with ChartXY.setFittingRectangleFillStyle and ChartXY.setFittingRectangleStrokeStyle
chart.setFittingRectangleFillStyle(new SolidFill({color: ColorRGBA(255,0,0,125)}))
// Extract required parts from LightningChartJS.
const {
lightningChart,
DataPatterns,
AxisScrollStrategies,
SolidFill,
ColorRGBA
} = lcjs
const {
createProgressiveTraceGenerator
} = xydata
// Create a XY Chart.
const chart = lightningChart().ChartXY()
// Create progressive line series.
const series = chart.addLineSeries({
dataPattern: DataPatterns.horizontalProgressive
})
// configure axis
const intervalSize = 100
series.axisX
.setScrollStrategy(AxisScrollStrategies.progressive)
.setInterval(0, intervalSize)
// limit the axis interval to the original interval size
series.axisX
.onScaleChange((start, end) => {
if (end - start > intervalSize) {
series.axisX.setInterval(end - intervalSize, end)
}
})
// "Zoom out rectangle"
chart.setFittingRectangleFillStyle(new SolidFill({color: ColorRGBA(255,0,0,125)}))
// Generate traced points stream using 'xydata'-library.
createProgressiveTraceGenerator()
.setNumberOfPoints(1000)
.generate()
.setStreamRepeat(true)
.toStream()
.forEach(data => {
series.add(data)
})
<script src="https://unpkg.com/#arction/xydata#1.2.1/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#1.3.1/dist/lcjs.iife.js"></script>

Related

Plotly.js: how to make markers only show when zoomed in (range slider with time on x-axis)

I'm using Plotly.js (javascript plotly) to configure a line chart that has a range slider and has dates on the x-axis (as in Range Slider and Selector | JavaScript | Plotly and in the snippet below). When you zoom in, I want the line chart to have dots at each data point (aka, mode: 'lines+markers'). When you zoom out, the dots look too crowded because they are very close together. So, I want the dots to disappear ( mode: 'lines') when zoomed in to 30 day's worth of data or less.
Is it possible to add markers to the chart only when zoomed in to a range span of 30 days or less? For example, when looking at an x-axis range of more than a week, the mode of the chart should be ‘lines’ but when zoomed in such that the x-axis’s range spans 30 days or less, the mode should be ‘lines+marker’.
I’m not certain the best language to ask the question, but I’m seeking a way to find a “hook” into the chart’s x-axis range. Since I’ve not defined the range (it’s managed instead via the range slider), how do I get my javascript to say “if the range[1] - range[0] is > 30 days, make mode = 'lines'; else if range[1] - range[0] is not > 30 days, make mode = 'lines+markers'.
// Generate 500 random numbers for Y axis
var randoms = [375438,375436,375434,375430,375428,375428,375428,375428,375422,375413,375412,375408,375405,375405,375405,375403,375393,375383,375380,375373,375373,375373,375375,375374,375371,375371,375367,375367,375367,375364,375348,375330,375325,375324,375324,375324,375318,375301,375295,375276,375254,375254,375254,375251,375243,375225,375209,375203,375221,375221,375221,375205,375183,375172,375153,375153,375153,375147,375130,375114,375094,375083,375083,375083,375083,375067,375050,375028,375023,375023,375021,375027,375008,374992,374988,374967,374967,374967,374971,374955,374938,374921,374898,374898,374896,374893,374873,374861,374840,374828,374828,374835,374835,374827,374809,374798,374772,374773,374773,374773,374761,374748,374738,374738,374738,374738,374749,374749,374729,374718,374717,374717,374717,374713,374728,374714,374705,374697,374697,374697,374702,374682,374668,374654,374637,374636,374636,374637,374637,374637,374622,374622,374622,374622,374624,374611,374604,374597,374592,374592,374592,374597,374588,374582,374573,374579,374579,374579,374579,374579,374572,374576,374570,374570,374570,374570,374559,374559,374567,374546,374546,374546,374552,374542,374530,374527,374505,374505,374505,374486,374467,374451,374450,374439,374439,374439,374433,374422,374429,374424,374373,374373,374373,374376,374371,374371,374358,374350,374350,374350,374356,374340,374348,374341,374307,374307,374307,374311,374318,374299,374282,374272,374272,374272,374271,374265,374238,374234,374224,374224,374223,374215,374199,374180,374171,374171,374171,374171,374170,374175,374168,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374082,374102,374073,374073,374075,374105,374094,374076,374051,374051,374051,374043,374030,374021,374029,374029,374029,374029,374028,374008,373997,373994,373977,373977];
// Make an array 1 - 500 for X axis
var xrange = ["2021-05-29","2021-05-28","2021-05-27","2021-05-26","2021-05-25","2021-05-24","2021-05-23","2021-05-22","2021-05-21","2021-05-20","2021-05-19","2021-05-18","2021-05-17","2021-05-16","2021-05-15","2021-05-14","2021-05-13","2021-05-12","2021-05-11","2021-05-10","2021-05-09","2021-05-08","2021-05-07","2021-05-06","2021-05-05","2021-05-04","2021-05-03","2021-05-02","2021-05-01","2021-04-30","2021-04-29","2021-04-28","2021-04-27","2021-04-26","2021-04-25","2021-04-24","2021-04-23","2021-04-22","2021-04-21","2021-04-20","2021-04-19","2021-04-18","2021-04-17","2021-04-16","2021-04-15","2021-04-14","2021-04-13","2021-04-12","2021-04-11","2021-04-10","2021-04-09","2021-04-08","2021-04-07","2021-04-06","2021-04-05","2021-04-04","2021-04-03","2021-04-02","2021-04-01","2021-03-31","2021-03-30","2021-03-29","2021-03-28","2021-03-27","2021-03-26","2021-03-25","2021-03-24","2021-03-23","2021-03-22","2021-03-21","2021-03-20","2021-03-19","2021-03-18","2021-03-17","2021-03-16","2021-03-15","2021-03-14","2021-03-13","2021-03-12","2021-03-11","2021-03-10","2021-03-09","2021-03-08","2021-03-07","2021-03-06","2021-03-05","2021-03-04","2021-03-03","2021-03-02","2021-03-01","2021-02-28","2021-02-27","2021-02-26","2021-02-25","2021-02-24","2021-02-23","2021-02-22","2021-02-21","2021-02-20","2021-02-19","2021-02-18","2021-02-17","2021-02-16","2021-02-15","2021-02-14","2021-02-13","2021-02-12","2021-02-11","2021-02-10","2021-02-09","2021-02-08","2021-02-07","2021-02-06","2021-02-05","2021-02-04","2021-02-03","2021-02-02","2021-02-01","2021-01-31","2021-01-30","2021-01-29","2021-01-28","2021-01-27","2021-01-26","2021-01-25","2021-01-24","2021-01-23","2021-01-22","2021-01-21","2021-01-20","2021-01-19","2021-01-18","2021-01-17","2021-01-16","2021-01-15","2021-01-14","2021-01-13","2021-01-12","2021-01-11","2021-01-10","2021-01-09","2021-01-08","2021-01-07","2021-01-06","2021-01-05","2021-01-04","2021-01-03","2021-01-02","2021-01-01","2020-12-31","2020-12-30","2020-12-29","2020-12-28","2020-12-27","2020-12-26","2020-12-25","2020-12-24","2020-12-23","2020-12-22","2020-12-21","2020-12-20","2020-12-19","2020-12-18","2020-12-17","2020-12-16","2020-12-15","2020-12-14","2020-12-13","2020-12-11","2020-12-10","2020-12-09","2020-12-08","2020-12-07","2020-12-06","2020-12-05","2020-12-04","2020-12-03","2020-12-02","2020-12-01","2020-11-16","2020-11-15","2020-11-14","2020-11-13","2020-11-12","2020-11-11","2020-11-10","2020-11-09","2020-11-08","2020-11-07","2020-11-06","2020-11-05","2020-11-04","2020-11-03","2020-11-02","2020-11-01","2020-10-31","2020-10-30","2020-10-29","2020-10-28","2020-10-27","2020-10-26","2020-10-25","2020-10-24","2020-10-23","2020-10-22","2020-10-21","2020-10-20","2020-10-19","2020-10-18","2020-10-17","2020-10-16","2020-10-15","2020-10-14","2020-10-13","2020-10-12","2020-10-11","2020-10-10","2020-10-09","2020-10-08","2020-10-07","2020-10-06","2020-10-05","2020-10-04","2020-10-03","2020-10-02","2020-10-01","2020-09-30","2020-09-29","2020-09-28","2020-09-27","2020-09-26","2020-09-25","2020-09-24","2020-09-23","2020-09-22","2020-09-21","2020-09-20","2020-09-19","2020-09-18","2020-09-17","2020-09-16","2020-09-15","2020-09-14","2020-09-13","2020-09-12","2020-09-11","2020-09-10","2020-09-09","2020-09-08","2020-09-07","2020-09-06","2020-09-05","2020-09-04","2020-09-03","2020-09-02","2020-09-01","2020-08-31"]
var trace = {
x: xrange,
y: randoms,
mode: 'lines+markers'
};
var layout = {
title: 'Time series with range slider and too many markers when zoomed out',
height: 400,
xaxis: {
rangeslider: {}
},
yaxis: {
fixedrange: true
}
};
var data = [trace];
Plotly.newPlot('myDiv', data, layout);
<body>
<div id="myDiv"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js" crossorigin="anonymous"></script>
</body>
Thanks in advance!

chart.js Line chart with different background colors for each section

Lets say I have a Line chart with mon-fri for 4 weeks.
I want that these 4 weeks are diveded in sections. I want the first monday to friday have a white background color.
The second monday to friday a gray background.
The thirth a white bg again.
And the fourth weeks with monday to friday to have a gray background color.
What Im talking about is the background of the graph.
Is there a way to do this?
Chart.js clears the canvas before drawing (or redrawing) a chart.
We can jump in on this and draw our background once the chart is cleared. Just extend the Line chart and override the clear function in the initialize override.
Preview
Script
Chart.types.Line.extend({
name: "LineAlt",
initialize: function(data){
Chart.types.Line.prototype.initialize.apply(this, arguments);
// keep a reference to the original clear
this.originalClear = this.clear;
this.clear = function () {
this.originalClear();
// 1 x scale unit
var unitX = this.datasets[0].points[1].x - this.datasets[0].points[0].x;
var yTop = this.scale.startPoint;
var yHeight = this.scale.endPoint - this.scale.startPoint;
// change your color here
this.chart.ctx.fillStyle = 'rgba(100,100,100,0.8)';
// we shift it by half a x scale unit to the left because the space between gridline is actually a shared space
this.chart.ctx.fillRect(this.datasets[0].points[5].x - 0.5 * unitX, yTop, unitX * 5, yHeight);
this.chart.ctx.fillRect(this.datasets[0].points[15].x - 0.5 * unitX, yTop, unitX * 5, yHeight);
}
}
});
Then just use LineAlt instead of Line
var myNewChart = new Chart(ctx).LineAlt(data);
Fiddle - http://jsfiddle.net/oe2606ww/
Some people here have requested something that works for later versions, here's my hacked together solution that works on ChartJS 2.7.2 (EDIT: Apr 2020: Also 2.9.3) and could probably be adapted. Chart.types.Line.extend used in the answer above, doesn't seem to be valid in v2.
I managed to figure this out with help from this thread to get the plugin code, and also found this thread useful for gathering co-ordinates of the data points.
With some work this fiddle should allow you to pass the label array keys as start/stop positions via the following code (where 0 and 1 are the keys):
var start = meta.data[0]._model.x;
var stop = meta.data[1]._model.x;
You could loop this, along with the ctx.fillRect function to draw multiple rectangles.
Here's the working fiddle: http://jsfiddle.net/oe2606ww/436/
I combined #potatopeelings's and #v25's solutions for a chart.js v2 solution. It utilizes the format of #potatopeelings's solution, allowing to use an alternate chart type (LineAlt), and the updated implementation from #v25's solution.
Chart.controllers.LineAlt = Chart.controllers.line.extend({
draw: function (ease) {
if (this.chart.config.options.chartArea && this.chart.config.options.chartArea.backgroundColor) {
var ctx = this.chart.chart.ctx;
var chartArea = this.chart.chartArea;
var meta = this.chart.getDatasetMeta(0);
var start = meta.data[1]._model.x;
var stop = meta.data[2]._model.x;
ctx.save();
ctx.fillStyle = this.chart.config.options.chartArea.backgroundColor;
ctx.fillRect(start, chartArea.top, stop - start, chartArea.bottom - chartArea.top);
ctx.restore();
}
// Perform regular chart draw
Chart.controllers.line.prototype.draw.call(this, ease);
}
});
Then you can use the custom chart type just as in #potatopeelings's solution:
var myNewChart = new Chart(ctx, {type: 'LineAlt', data: data});
I'd try a little work around,I'd draw an image with four line each one with width 1px and a different color; then in a CSS sheet define:
canvas {
background-image: url(backgroundimage.jpg);
background-size: contain;
}

Paper.js change layer coordinate start point

everyone.
It is possible in paper.js change layer start coordinate position from top-left corner?
Use case: I put image into bottom layer and draw some stuff on top layer. Image can be scalled and moved. I need to get my drawing path points coord in image coordinate system. And I want to set my drawing layer coordinate start to image top left point and move it then image scale/move.
I try do this:
var layer = new Layer();
project.activeLayer.setName("DrawingStuff");
project.activeLayer.setPosition(paperjs.project.view.center);
project.activeLayer.bounds.x = 300;
project.activeLayer.bounds.y = 300;
project.activeLayer.bounds.width = raster.width;
project.activeLayer.bounds.height = raster.height;
But it is don't work. Name is setted, but bounds and position still empty.
Will be very thankfull for any advise.
P.S. I know that I can just recalculate path point from canvas coords system to image coords system, but I want to try change layer coords start point
It would be easier to use the current coordinate system and change the zoom and center properties of the project's view. Take a look at the code behind the zoom tool in main.js at http://sketch.paperjs.org:
var lastPoint;
var body = $('body');
zoomTool = new Tool({
buttonClass: 'icon-zoom'
}).on({
mousedown: function(event) {
if (event.modifiers.space) {
lastPoint = paper.view.projectToView(event.point);
return;
}
var factor = 1.25;
if (event.modifiers.option)
factor = 1 / factor;
paper.view.zoom *= factor;
paper.view.center = event.point;
},
...
mousedrag: function(event) {
if (event.modifiers.space) {
body.addClass('zoom-grab');
// In order to have coordinate changes not mess up the
// dragging, we need to convert coordinates to view space,
// and then back to project space after the view space has
// changed.
var point = paper.view.projectToView(event.point),
last = paper.view.viewToProject(lastPoint);
paper.view.scrollBy(last.subtract(event.point));
lastPoint = point;
}
},
...
});

Adding Object with Transition in D3.js after Zooming

In the d3.js example, the goal is to change the X & Y scales to reveal a newly added circle which is added offscreen.
Currently, if you were to change the zoom scale, then click on the button to add a new circle, the zoom level suddenly resets to 1. Now dragging the view will cause the zoom scale to become correct again, which is the same zoom scale right before adding the circle.
However this problem goes away if you change redrawWithTransition() on line 123 to redraw() which removes the transitions.
Everything works fine if you add the circle without first zooming.
Why do we have to drag the view again to get the correct zoom scale back? How can we avoid having to do this additional drag and still use transitions in redrawWithTransition()? Thank you!!
Jsfiddle: http://jsfiddle.net/NgWmU/
Because panning again after adding the circle solves the problem, I tried calling redraw() at the end but theres no difference! Is the panning/zooming triggering something else in addition to redraw()?
Jsfiddle: http://jsfiddle.net/NgWmU/2/
First the user zooms/pans around and ends up with a view like in figure A. Next the new circle is added and we should get figure C, but instead we get figure B where the user's current translate/zoom is changed significantly.
Another case
If the user pan/zoom to a view similar to the top figure, adding the new circle should reposition the existing circles slightly, but instead the entire view is reset.
Was thinking about something like:
// Copy existing domains
var xMinOld = xMin,
xMaxOld = xMax,
yMinOld = yMin,
yMaxOld = yMax;
// Update domains
var yMin = d3.min(data.map( function(d) { return d; } )),
yMax = d3.max(data.map( function(d) { return d; } )),
xMin = d3.min(data.map( function(d) { return d; } )),
xMax = d3.max(data.map( function(d) { return d; } ));
if(x.domain()[0] > newData[0] || x.domain()[1] < newData[0]) {
if(x.domain()[0] > newData[0]) {
x.domain([xMin, xMaxOld]);
} else {
x.domain([xMinOld, xMax]);
}
zoom.x(x);
}
if(y.domain()[0] > newData[0] || y.domain()[1] < newData[0]) {
if(y.domain()[0] > newData[0]) {
y.domain([yMin, yMaxOld]);
} else {
y.domain([yMinOld, yMax]);
}
zoom.y(y);
}
But eventually the view will still be reset because we pass the updated scales x and y into zoom...

How to navigate between points on flot chart?

I would like to build some sort of forward/back pager that will navigate between the points on my chart, highlighting the current point.
The closest example I've seen is something similar to the news legend on google finance charts, https://www.google.ca/finance?q=goog&ei=AD6dUvjOLMi0iAL9Uw
(you can click each news article/event and it will jump in the graph to the relevant point in time on the graph)
Can this be done with Flot and any suggestions on how to do this? Thanks!
Here's a real quick example to demonstrate one approach to this problem. On previous/next button clicks it highlights the previous/next point in the series and adjusts the xaxis so that the hightlighted point stays centered on the screen.
var highlightPoint = 15; // our first highlight
var xmin = 10, xmax = 20; // some arbitrary slice of series
var plot = $.plot("#placeholder", [ d1 ], //initial plot call
{
xaxis:{min: xmin, max: xmax}
});
plot.highlight(0,highlightPoint); // initial highlight
$('#prevPoint').click(function(){
plot.unhighlight(0,highlightPoint); // unhighlight previous selection
highlightPoint -= 1; // move to left
xmin = highlightPoint - 5; // adjust xaxis
xmax = highlightPoint + 5;
plot.getOptions().xaxes[0].min = xmin; // set xaxis into options
plot.getOptions().xaxes[0].max = xmax;
plot.setupGrid(); // refresh chart with new xaxis
plot.draw(); // redraw
plot.highlight(0,highlightPoint); //highlight new point
});
Makes more sense to look at the Fiddle here.

Categories

Resources