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

D3.js zoom and touch device smoothness

本文关键字:平滑 触摸 js 缩放 D3      更新时间:2023-09-26

我使用d3. behavior。放大我的图表,桌面上一切正常。然而,当我在ipad上进行缩放时,缩放效果非常不稳定。有办法让我把它弄平吗?似乎我需要在缩放时取消翻译调用。

我试过几件事,但没有一件成功。

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

这是对的还是错了,需要考虑其他因素

帮助非常感谢

欢呼

标记编辑:

我想我应该在这里包括一些代码,因为我不能通过工作网络使用另一个服务

附加缩放处理程序

  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中的触点事件但它没有触发我必须为zoomend附加另一个处理程序并以这种方式检测

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

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

当你放大图形时,你可能需要重新绘制坐标轴、垂直线和水平线,这样它们就不会被放大了。