-
Notifications
You must be signed in to change notification settings - Fork 606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
panEdgeFraction ignored on touch screen #713
Comments
@calebvandenberg ok, so I managed to implement panEdgeFraction for touch input: interactionModel: {
touchstart: function(event, g, context) {
Dygraph.defaultInteractionModel.touchstart(event, g, context);
Dygraph.Interaction.startPan(event, g, context);
},
touchmove: function(event, g, context) {
moveTouch(event, g, context);
},
touchend: Dygraph.defaultInteractionModel.touchend,
} (Normally Now we need a custom interactionModel for touchmove. I took the default --- see post below --- Only tested on Chrome desktop & mobile, but it should be a starting point :) And a big thanks for your great work btw! |
update: //Dygraph.Interaction.moveTouch = function(event, g, context) {
moveTouch = function(event, g, context) {
// If the tap moves, then it's definitely not part of a double-tap.
context.startTimeForDoubleTapMs = null;
var i, touches = [];
for (i = 0; i < event.touches.length; i++) {
var t = event.touches[i];
touches.push({
pageX: t.pageX,
pageY: t.pageY
});
}
var initialTouches = context.initialTouches;
var c_now;
// old and new centers.
var c_init = context.initialPinchCenter;
if (touches.length == 1) {
c_now = touches[0];
} else {
c_now = {
pageX: 0.5 * (touches[0].pageX + touches[1].pageX),
pageY: 0.5 * (touches[0].pageY + touches[1].pageY)
};
}
// this is the "swipe" component
// we toss it out for now, but could use it in the future.
var swipe = {
pageX: c_now.pageX - c_init.pageX,
pageY: c_now.pageY - c_init.pageY
};
var dataWidth = context.initialRange.x[1] - context.initialRange.x[0];
var dataHeight = context.initialRange.y[0] - context.initialRange.y[1];
swipe.dataX = (swipe.pageX / g.plotter_.area.w) * dataWidth;
swipe.dataY = (swipe.pageY / g.plotter_.area.h) * dataHeight;
var xScale, yScale;
// The residual bits are usually split into scale & rotate bits, but we split
// them into x-scale and y-scale bits.
if (touches.length == 1) {
xScale = 1.0;
yScale = 1.0;
} else if (touches.length >= 2) {
var initHalfWidth = (initialTouches[1].pageX - c_init.pageX);
xScale = (touches[1].pageX - c_now.pageX) / initHalfWidth;
var initHalfHeight = (initialTouches[1].pageY - c_init.pageY);
yScale = (touches[1].pageY - c_now.pageY) / initHalfHeight;
}
// Clip scaling to [1/8, 8] to prevent too much blowup.
xScale = Math.min(8, Math.max(0.125, xScale));
yScale = Math.min(8, Math.max(0.125, yScale));
var didZoom = false;
//in Dygraph.Interaction.movePan dragEndX/Y are declared like this what gives NaN:
//context.dragEndX = Dygraph.dragGetX_(event, context);
//context.dragEndY = Dygraph.dragGetY_(event, context);
context.dragEndX = event.touches[0].pageX - context.px;
context.dragEndY = event.touches[0].pageY - context.py;
//in Dygraph.Interaction.movePan dragStartX/Y is not declared but needed here
context.dragStartX = context.initialTouches[0].pageX - context.px;
context.dragStartY = context.initialTouches[0].pageY - context.py;
if (context.touchDirections.x) {
if (event.touches.length == 1){
var minDate = context.initialLeftmostDate -
(context.dragEndX - context.dragStartX) * context.xUnitsPerPixel;
if (context.boundedDates) {
minDate = Math.max(minDate, context.boundedDates[0]);
}
var maxDate = minDate + context.dateRange;
if (context.boundedDates) {
if (maxDate > context.boundedDates[1]) {
// Adjust minDate, and recompute maxDate.
minDate = minDate - (maxDate - context.boundedDates[1]);
maxDate = minDate + context.dateRange;
}
}
if (g.getOptionForAxis("logscale", "x")) {
g.dateWindow_ = [ Math.pow(Dygraph.LOG_SCALE, minDate),
Math.pow(Dygraph.LOG_SCALE, maxDate) ];
} else {
g.dateWindow_ = [minDate, maxDate];
}
} else {
var minDateWindow = c_init.dataX - swipe.dataX + (context.initialRange.x[0] - c_init.dataX) / xScale
var maxDateWindow = c_init.dataX - swipe.dataX + (context.initialRange.x[1] - c_init.dataX) / xScale
if (context.boundedDates) {
if (minDateWindow < context.boundedDates[0]){
minDateWindow = context.boundedDates[0];
}
if (maxDateWindow > context.boundedDates[1]){
maxDateWindow = context.boundedDates[1];
}
}
// limit the smallest shown resolution for xAxes to 1 sec
if (maxDateWindow - minDateWindow <= 60000){
return;
}
g.dateWindow_ = [
minDateWindow,
maxDateWindow
];
didZoom = true;
}
}
if (context.touchDirections.y) {
var pixelsDragged = context.dragEndY - context.dragStartY;
// Adjust each axis appropriately.
for (var i = 0; i < g.axes_.length; i++) {
var axis = g.axes_[i];
var axis_data = context.axes[i];
var unitsDragged = pixelsDragged * axis_data.unitsPerPixel;
var boundedValue = context.boundedValues ? context.boundedValues[i] : null;
var logscale = g.attributes_.getForAxis("logscale", i);
if (event.touches.length == 1){
// y-axis scaling is automatic unless this is a full 2D pan.
if (context.is2DPan) {
// In log scale, maxValue and minValue are the logs of those values.
var maxValue = axis_data.initialTopValue + unitsDragged;
if (boundedValue) {
maxValue = Math.min(maxValue, boundedValue[1]);
}
var minValue = maxValue - axis_data.dragValueRange;
if (boundedValue) {
if (minValue < boundedValue[0]) {
// Adjust maxValue, and recompute minValue.
maxValue = maxValue - (minValue - boundedValue[0]);
minValue = maxValue - axis_data.dragValueRange;
}
}
if (logscale) {
axis.valueWindow = [ Math.pow(Dygraph.LOG_SCALE, minValue),
Math.pow(Dygraph.LOG_SCALE, maxValue) ];
} else {
axis.valueWindow = [ minValue, maxValue ];
}
}
} else {
var minValueWindow = c_init.dataY - swipe.dataY + (context.initialRange.y[0] - c_init.dataY) / yScale
var maxValueWindow = c_init.dataY - swipe.dataY + (context.initialRange.y[1] - c_init.dataY) / yScale
if (boundedValue) {
if (minValueWindow < boundedValue[0]){
minValueWindow = boundedValue[0];
}
if (maxValueWindow > boundedValue[1]){
maxValueWindow = boundedValue[1];
}
}
if (logscale) {
// TODO(danvk): implement
} else {
// limit the smallest shown resolution for yAxes
// TODO: make dependend of actual values
if (maxValueWindow - minValueWindow <= 0.1){
return;
}
axis.valueWindow = [
minValueWindow,
maxValueWindow
];
didZoom = true;
}
}
}
}
if (event.touches.length == 2){
Dygraph.Interaction.startPan(event, g, context);
}
g.drawGraph_(false);
// We only call zoomCallback on zooms, not pans, to mirror desktop behavior.
if (didZoom && touches.length > 1 && g.getFunctionOption('zoomCallback')) {
var viewWindow = g.xAxisRange();
g.getFunctionOption("zoomCallback").call(g, viewWindow[0], viewWindow[1], g.yAxisRanges());
}
}; |
Thanks for putting this together. I finally got around to implementing this on my own site! For my own purposes I modified the dygraphs source instead of creating a custom interaction model.
|
This would be a great feature! I tried the proposed solution but didn't manage to get it working (I suppose mainly because its related to an older version). Any updates on this? Thanks! |
Please, make it work. Zooming on mobile is very difficult. It goes to almost -Infinity, +Infinity very soon. It is not easy to zoom. Are there any quick fixes? The above workaround does not work. It completely disables touch interaction. Update: I found a fix, and made a pull request |
Thanks for a fantastic library.
PanEdgeFraction doesn't do anything on touch screens- graph axes go off infinitely making it difficult to find graph back.
Example here: http://swellmatrix.com/current/panEdgeFraction.html
Panning limited as expected when using keyboard (shift) + mouse.
Tested on:
Android 5.1 Firefox 43.0
Android 5.1 Chrome 47
Android 4.2.2 Chrome 45
iPad iOS 9.2 Safari 9.0
The text was updated successfully, but these errors were encountered: