javascript - D3.js缩放和触摸设备平滑度

标签 javascript d3.js touch multi-touch

我在图表上使用 d3.behaviour.zoom,桌面上一切正常。然而,当我在 iPad 上执行此操作时,缩放非常不稳定。有什么办法可以让我顺利解决吗?似乎我需要在缩放时取消翻译调用。

我尝试了一些方法,但都没有取得巨大成功。

一个例子是在缩放处理程序中,我得到2个触摸点x和y,然后得到它们之间的距离,并且取决于它是否从最后存储的距离缩小或增长,我在d3.event.scale上添加或减去0.05用于变换。

这是对的还是我离题还需要考虑其他事情

非常感谢帮助

干杯

标记

编辑:

我想在这里包含一些代码,因为我无法通过工作网络使用其他服务

附加缩放处理程序

  RadarDraw.ZoomListener = d3.behavior.zoom().scaleExtent([1, 5]).on("zoom", zoom);
        // Create the SVG element, transforming the coordinates so (0,0) is at the centre
    svg = d3.select("#radarContainer").append("svg")
        .attr("viewBox", "0 0 " + _config.Width + " " + _config.Height + "")
        .attr("id", "chartsvg")
        .attr("width", _config.Width)
        .attr("height", _config.Height)
        //.call(zoom)
        .append("g")
        .attr("id", "svgGElm")
        .attr("transform", "translate(" + _config.Width / 2 + "," + ((_config.Height - _config.Voffset) / 2 + _config.Voffset) + ")")
        .call(_config.RadarType != "dash" ? RadarDraw.ZoomListener : function () { });

这是缩放处理程序

function zoom(){
    if (d3.event.scale <= 1 || d3.event.scale >= 5) {

            if (!tools.IsArcFocused) {
                svg.attr("transform", "translate("
                    + (d3.event.translate[0] + (_config.Width / 2)) + "," + (d3.event.translate[1] + (_config.Height / 2))
                    + ")scale(" + d3.event.scale + ")");
            }

                //handle the zoom of arc that occurs from dblclick. this moves to arc and centers it and zooms in into it.
                if (tools.IsArcFocused) {
                    svg.attr("transform", "translate(" + _config.Width / 2 + "," + _config.Height / 2 + ")scale(" + 5 + ")translate("
                 + -RadarDraw.transPosX + "," + -RadarDraw.transPosY + ")");
                }

                debugInfoBar(" scale: " + d3.event.scale
                        + " last distance: " + lastDistance
                        + " current distance: " + currentDistance);



                //detect mouse wheel
                if(d3.event.sourceEvent != null)
                {
                    if (d3.event.sourceEvent.type=='mousewheel' || d3.event.sourceEvent.type=='wheel' || d3.event.sourceEvent.type=='DOMMouseScroll')
                    {
                        //if we are zoom in on an arc only listen to zoom out command to exit the zoom

                        //if wheeldelta is forward and in focus mode then ignore it
                        if (d3.event.sourceEvent.wheelDelta > 0 && tools.IsArcFocused)
                        {
                            //make sure dots stay smallest zoomed in size
                            scaleDots(5);
                            return;
                        }

                         if (d3.event.sourceEvent.wheelDelta < 0) {
                             if ((tools.IsArcFocused && d3.event.scale >= 5) || (tools.IsArcFocused && d3.event.scale <= 1)) {
                                tools.ExitZoom(false);
                             }

                             //reset to 0,0 scale 1 as we want to zoom out fully
                             if (d3.event.scale <= 1 && tools.IsArcFocused)
                             {
                                 svg.attr("transform", "translate(" + _config.Width / 2 + "," + _config.Height / 2 + ")scale(" + 1 + ")");
                             }
                        }
                    }

                    if (d3.event.sourceEvent.type == "mousemove" && tools.IsArcFocused)
                    {
                        d3.event.scale = 5;
                        scaleDots(5);
                        return;
                    }

                    if (d3.event.sourceEvent.type == "touchmove")
                    {
                        //need to handle zoom out via touch (like whats done with mouse wheel)
                        return;
                    }

                    //deal with stopping double tap and double click events via the zoom
                    if (d3.event.sourceEvent.type == 'dblclick' || d3.event.sourceEvent.type == 'touchstart')
                    {
                        if (typeof (d3.event.preventDefault) == "function") {
                            d3.event.preventDefault();
                            d3.event.stopPropagation();
                        }

                        return;
                    }
                }

                scaleDots(d3.event.scale);

                if(tools.IsArcFocused)
                    previousZoomLevel = 5;
                else
                    previousZoomLevel = 1;

                return;
        } else {
            if (tools.IsArcFocused) {
                svg.attr("transform", "translate(" + _config.Width / 2 + "," + _config.Height / 2 + ")scale(" + 5 + ")translate("
             + -RadarDraw.transPosX + "," + -RadarDraw.transPosY + ")");
            }


            inTouchZoom = false;


            //detect forward scroll when zoomed in so it exits zoom
            if(d3.event.sourceEvent != null)
            {
                if (d3.event.sourceEvent.type == 'mousewheel' || d3.event.sourceEvent.type == 'wheel' || d3.event.sourceEvent.type == 'DOMMouseScroll') {
                    if (d3.event.sourceEvent.wheelDelta == 120)
                    {
                        d3.event.scale += 0.05;
                        if (d3.event.scale > 4.9)
                            d3.event.scale = 4.9;
                    }
                    else if (d3.event.sourceEvent.wheelDelta -= 120)
                    {
                        d3.event.scale -= 0.05;
                        if (d3.event.scale < 1)
                            d3.event.scale = 1;
                    }

                    //previousZoomLevel -gets confused sometimes and is 1 when it should be >=5
                    if (tools.IsArcFocused && previousZoomLevel >= 5) {
                        tools.ExitZoom(false);
                        previousZoomLevel = d3.event.scale;
                    }
                }

                if (d3.event.sourceEvent.type == "touchmove") {
                    //if only one touch point then do translation for pan otherwise leave as is
                    if (d3.event.sourceEvent.touches.length > 1) {

                        inTouchZoom = true;
                        //dont update translate use what was take before
                        d3.event.translate = touchZoomTranslate;

                        //we have atleast 2 points so use the first 2
                        var currentDistance = PointDistance(d3.event.sourceEvent.touches[0].pageX, d3.event.sourceEvent.touches[0].pageY, d3.event.sourceEvent.touches[1].pageX, d3.event.sourceEvent.touches[1].pageY);


                        debugInfoBar(" scale: " + d3.event.scale
                                + " tp1 X: " + d3.event.sourceEvent.touches[0].pageX + "  tp1Y: " + d3.event.sourceEvent.touches[0].pageY
                                + " tp2 X: " + d3.event.sourceEvent.touches[1].pageX + "  tp2Y: " + d3.event.sourceEvent.touches[1].pageY
                                + " last distance: " + lastDistance
                                + " current distance: " + currentDistance);

                        if (currentDistance > lastDistance) {
                            d3.event.scale += 0.05;
                            if(d3.event.scale  > 4.9)
                                d3.event.scale = 4.9;


                            lastDistance = currentDistance;
                        }
                        else {
                            d3.event.scale -= 0.05;
                            if (d3.event.scale < 1)
                                d3.event.scale = 1;

                            lastDistance = currentDistance;
                        }



                        svg.attr("transform", "translate(" + _config.Width / 2 + "," + _config.Height / 2 + ")scale(" + d3.event.scale + ")");
                        return;
                    }

                }

                if (d3.event.sourceEvent.type == "touchend") {
                    //wipe last distance and we have finished touch
                    lastDistance = 0;
                }

                //deal with stopping double tap and double click events via the zoom
                if (d3.event.sourceEvent.type == 'dblclick' || (d3.event.sourceEvent.type == 'touchstart' && !inTouchZoom))
                {
                    if (typeof (d3.event.preventDefault) == "function") {
                        d3.event.preventDefault();
                        d3.event.stopPropagation();
                    }

                    return;
                }
            }

            if (!tools.IsArcFocused) {
                svg.attr("transform", "translate("
                + (d3.event.translate[0] + (_config.Width / 2)) + "," + (d3.event.translate[1] + (_config.Height / 2))
                + ")scale(" + d3.event.scale + ")");
            }

                if (d3.event.scale > 1)
                    previousZoom = true;

                //if we are zoomed in and our previous zoom level is 5 or above then exit zoom (we are either scrolling out or pinching out of zoom)
                if (tools.IsArcFocused && previousZoomLevel >= 5) {
                     tools.ExitZoom(false);
                }

                scaleDots(d3.event.scale);
        }

        if (d3.event.scale > 4.9)
            d3.event.scale = 4.9;

        if(!inTouchZoom)
            touchZoomTranslate = d3.event.translate;
}

最佳答案

我通过重写缩放处理程序纠正了这个问题,使其具有特定的触摸输入更新,我在其中处理缩放而不依赖 d3。我还在 Zoom 中监听了 touchend 事件,但它没有触发我必须为 Zoomend 附加另一个处理程序并以这种方式检测它

关于javascript - D3.js缩放和触摸设备平滑度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25287905/

相关文章:

javascript - 使用 angularJS Controller 生成下拉菜单

javascript - 使用文件 ://在本地加载的来自移动 WebView 的 CORS cookie 凭据

javascript - 如何在 nvd3 多参数图上显示值?

android - 如何制作一个简单的触摸屏测试应用?

javascript - 有没有更优雅的方法来检测触摸事件支持并分配 "click"或 "touchend"事件?

ios - iOS SDK中通过手指滑动获取当前 View

javascript - 使用javascript将值推送到上一页

javascript - 检查复选框和单选按钮是否被选中

javascript - svg - 获取重叠形状区域的路径坐标

javascript - 鼠标移出 D3 后如何设置元素的默认颜色