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

时间:2014-08-13 13:46:25

标签: javascript d3.js touch multi-touch

我在我的图表上使用d3.behaviour.zoom,桌面上的一切都很好。但是,当我在ipad上执行此操作时,缩放非常不稳定。有没有办法可以让它顺利出来?看起来我需要在缩放时取消翻译调用。

我尝试过几件事但没有取得任何成功。

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

这是正确的还是我离开了,需要考虑其他因素

非常感谢

干杯

标记

编辑:

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

附加缩放处理程序

  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;
}

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

无需进行所有计算即可实现缩放。

var onZoom = function() {
    var scale = d3.event.scale,
        translate = d3.event.translate;

    elemToZoom.attr('transform', 'scale(' + scale + ')translate(' + translate + ')');
};

var zoom = d3.behavior.zoom().on('zoom', onZoom);
var elemToZoom = d3.select('#zoomable')
                .call(zoom);

当你放大图形时,你可能需要重新绘制轴以及垂直和水平线,这样它们也不会被缩放。