Closed velocat closed 3 years ago
Hi velocat, If I remember correctly wp-gpx-maps had a similar function (ie. fit chart to dragged track selection).
Let me know if you achieve to develop a working example, Raruto
Unfortunately, they don't use d3, but use chart.js I've spent a lot of time trying to figure out d3, but I haven't made any significant progress yet. At the moment, I only managed to trigger the event leading to zooming, but the wisdom of transformations is confusing me more and more....
so Far like this: https://github.com/velocat/leaflet-elevation/tree/Zoom
I hope You can tell me what to add, because I'm stuck and can't move on ))
Hi velocat,
here it is a proof of concept (tested with version 1.4.0):
L.Control.Elevation.Chart.addInitHook(function(){
let svg = this._container;
let g = this._container.select('g');
// let path = this._path;
// let gx = this._axis.select('.x.axis.bottom');
let zoom = d3.zoom()
.scaleExtent([1, 10])
.on("zoom", (e) => {
this._updateScale(); // hacky way for restoring x scale when zooming out
this._x = d3.event.transform.rescaleX(this._x); // calculate x scale at zoom level
this._updateAxis();
this._updateArea();
});
g.call(zoom); // add zoom functionality to "svg" group
});
// and after that continue as usual
let controlElevation = L.control.elevation(...);
controlElevation.load(...)
To learn more, take a look at the following resources:
<clipPath>
element)Hoping this can help you, Raruto
This is great! And I kept trying to rewrite all this in the code itself ))) It turned out through the hook everything is simple))) I've been studying the D3 documentation for a few days now, but I still don't understand it, although I already understand how it works better )))
But the truth is, you still need to register something... Since Ticks disappear when zooming and there are no restrictions, the chart spreads to the entire width of the page:
before zoom:
after zoom:
And after the reverse zoom of such an expanded chart, it turns out like this:
And after that, it will not be able to expand it normally.
PS Also: scaling is only applied to the elevation graph, and slopes, speed, and so on are not scaled
PPS It seems to me that for the sake of beauty, it would not be bad to add a timeout fade for FocusLabel if the cursor left the chart area, for example, after 10 seconds, and then it remains always hanging over the chart after hovering
I've been studying the D3 documentation for a few days now, but I still don't understand it, although I already understand how it works better )))
Yep, working with "svg" can be a pain 😄
you still need to register something...
I don't have so much free time to devote to it...
the chart spreads to the entire width of the page
Take a look at: https://observablehq.com/@d3/zoomable-area-chart?collection=@d3/d3-zoom
In particular, start playing with these portions of code:
.extent([[margin.left, 0], [width - margin.right, height]])
.translateExtent([[margin.left, -Infinity], [width - margin.right, Infinity]])
svg.append("clipPath")
.attr("id", clip.id)
.append("rect")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("width", width - margin.left - margin.right)
.attr("height", height - margin.top - margin.bottom);
const path = svg.append("path")
.attr("clip-path", clip)
NB https://observablehq.com examples can be directly edited (in browser) to understand how they works.
scaling is only applied to the elevation graph, and slopes, speed, and so on are not scaled
Probably this happens because the following events are not being fired:
https://github.com/Raruto/leaflet-elevation/blob/936486b897a7f5e5827c0a06266ece3933b14711/src/control.js#L734 https://github.com/Raruto/leaflet-elevation/blob/936486b897a7f5e5827c0a06266ece3933b14711/src/control.js#L735
It seems to me that for the sake of beauty, it would not be bad to add a timeout fade for FocusLabel if the cursor left the chart area, for example, after 10 seconds, and then it remains always hanging over the chart after hovering
The following hook might help you:
Here it is a more complete example:
L.Control.Elevation.Chart.addInitHook(function(){
let svg = this._container;
let g = this._container.select('g');
let path = this._path;
let area = this._area;
let margin = this.options.margins;
let clipper_id = 'clipper-altitude'; // TODO: generate unique ids
const clip = area.append("clipPath") // generate and append <clipPath> element
.attr("id", clipper_id)
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", this._width())
.attr("height", this._height());
path.attr("clip-path", 'url(#' + clipper_id + ')'); // bind <clipPath> mask ("Altitude")
let zoom = d3.zoom()
.scaleExtent([1, 10])
.extent([[margin.left, 0], [this._width() - margin.right, this._height()]])
.translateExtent([[margin.left, -Infinity], [this._width() - margin.right, Infinity]])
.on("zoom", (e) => {
this._updateScale(); // hacky way for restoring x scale when zooming out
this._x = d3.event.transform.rescaleX(this._x); // calculate x scale at zoom level
this._updateAxis();
this._updateArea();
});
g.call(zoom); // add zoom functionality to "svg" group
});
// and after that continue as usual
let controlElevation = L.control.elevation(...);
controlElevation.load(...)
That's great! :) Many thanks! Now it does not move out))
It remains only to solve 2 more questions, and everything will be fine in general:
PS Although I'm afraid I won't stop there.... XD the idea is maturing in my head that it would be nice to add an x-axis switch between distance and time ))))))
It remains only to solve 2 more questions, and everything will be fine in general:
- Missing ticks on the right when zooming
- No scaling on other charts (on reception. Speed, etc.)
Take a look at the d3-zoom
branch
zoom = ctrl + wheel
pan = ctrl + drag
I tried to apply it to myself. Dragging and zooming works, but the result is not what is expected: When zooming in, the graphs also expand beyond the block, to the entire page.
I decided that the problem is how the coordinates are calculated and substituted them with constant values, but the result is still the same ((
let zoom = d3.zoom()
.scaleExtent([1, 10])
.extent([[ 50, 0 ], [ 614, 160 ]])
.translateExtent([[ 50, -Infinity ], [ 750, Infinity ]])
.filter(() => d3.event.ctrlKey);
PS I have achieved the desired result, but this only happens in the following sequence of actions:
PS it seems to me that using Ctrl+wheel is not a good idea, since in the browser this combination is used to scale all the content. This way, if the cursor suddenly appears outside of this block, the entire page will be scaled.
it seems to me that using Ctrl+wheel is not a good idea, since in the browser this combination is used to scale all the content. This way, if the cursor suddenly appears outside of this block, the entire page will be scaled.
This is also a quite common behavior (I moved the zoom listener to the whole <svg>
element, for more info take a look at my latest commits: https://github.com/Raruto/leaflet-elevation/commit/421286216030ae3dd8ad706522de76a60c62283d )
But this does not cancel the zoom change of the entire page if suddenly the cursor went out of the svg area, and Ctrl is still pressed and the wheel turns?
In General, I meant that in this case you need to either completely cancel the Ctrl+mousewheel event on the entire page, or replace it with Shift+mousewheel, for example To avoid accidental user behavior.
This problem arises when the elevation div is detached, to "partially" solve it you can do as follows:
d3.select('body')
.on("wheel", function() {
if (d3.event.ctrlKey) d3.event.preventDefault();
});
In order to avoid unwanted effects, I wouldn't disable it within the library.
Is it possible to implement scaling of charts, for example, setting cursors for a selected area on the chart?
That is, we select an area on the X scale (2 vertical rulers) and the graph is automatically expanded for this area. This would be very useful for viewing finer details in graphs.
I found something similar here (for D3): https://jsfiddle.net/cyril123/aebnL4sL/ Only scaling along one axis is desirable, and it would be more beautiful so that it does not come from the mouse wheel, but with the help of vertical rulers :)
PS I find this useful, as it will allow, for example, in the future to create a script with the following content: We find an area with erroneous heights (it often happens that some points fall out), zoom in to select a small area with problem points, select it with the mouse, and then send a request to the elevation server. As a result, you can correct the track with problem areas. This is all, of course, another script, not within the framework of this, but the presence of this feature will allow you to create what I described :))