Панорамирование при перетаскивании в D3JS

Чего я хочу добиться, так это возможности панорамировать весь SVG-образ во время операции перетаскивания.

Теперь я играю с этим примером: https://bl.ocks.org/mbostock/6123708 как я нашел его наиболее подходящим для меня (большинство, потому что это обрабатывает перетаскивание "правильно", большинство других примеров просто центрируют точку во время операции перетаскивания I будет перетаскивать более сложный объект, так что для меня эта функция, которую я увеличиваю позицию, а не меняю ее, является более подходящей), но я не знаю, как я могу обработать эту функцию панорамирования во время перетаскивания

  1. пользователь начинает перетаскивать кружок с помощью LeftMouseButton
  2. удерживая эту кнопку, нажмите кнопку RightMouseButton (и тогда волшебство начинает происходить)
  3. весь SVG начинает двигаться (панорамирование) и, таким образом, перетаскиваемый элемент (перетаскивание все еще работает и обновляет положение, чтобы положение мыши над перетаскиваемым элементом не изменялось)
  4. пользователь отпускает RightMouseButton, SVG прекращает панорамирование, и только перетаскивание все еще работает
  5. пользователь отпускает LeftMouseButton, а элементы перетаскивания обновляют свою позицию

Насколько я знаю, что я должен:

  • обрабатывать кастрюлю только для RightMouseButton - решено
  • обрабатывать Drag только для LeftMouseButton - в разработке:)
  • разрешить запуск Pan, когда я нахожусь в режиме "перетаскивания" - это больше всего вопрос
  • не разрешать запуск контекстного меню при выпуске RightMenuButton - решено

Извините за английские ошибки, это не моя родная, не стесняйтесь задавать любые вопросы, которые могут решить эту проблему

Обновить

На данный момент я заканчиваю souch код для перетаскивания:

  var drag = d3.behavior.drag()
  .on("dragstart", function () {

    //d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);

  }).on("drag", function () {

    var $this = d3.select(this);
    var t = d3.transform($this.attr("transform"));
    t.translate[0] += d3.event.dx;
    t.translate[1] += d3.event.dy;

    $this.attr("transform", "translate(" + t.translate + ")");

  }).on("dragend", function () {

    console.log("dragend");
    d3.select(this).classed("dragging", false);

  });

И сумка для увеличения:

var zoom = d3.behavior.zoom()
            .scaleExtent([0.1, 2])
            .on("zoomstart", function() {

                if (d3.event.sourceEvent.buttons != 2) {
                    savedTranslation = zoom.translate();
                } else {
                    savedTranslation = null;
                }

            }).on("zoom", function() {

                var translate = d3.event.translate;

                if (d3.event.sourceEvent.buttons != 2) {
                    zoom.translate(savedTranslation);
                    translate = savedTranslation;
                }

                svgContainer.attr("transform", "translate(" + translate + ")scale(" + d3.event.scale + ")");

            }).on("zoomend", function() {

                if (savedTranslation) {
                    zoom.translate(savedTranslation);
                    savedTranslation = null;
                }

            });

Использование всплывающего контекстного меню "Увеличить + предотвратить" (также блокируйте двойной щелчок для увеличения, так как он будет использоваться для редактирования всплывающего окна)

var svg = d3.select("#svg-workspace")
            .call(zoom)
            .on("dblclick.zoom", null)
            .on('contextmenu',function () {
                d3.event.preventDefault();
                return false;
            });

И прикрепить к D3.JS

d3.select($foreignObject.get(0))
    .call(drag);

$ ForeignObject является захваченным объектом jQuery

И все же проблема заключается в том, чтобы начать перетаскивание при перетаскивании.

1 ответ

Решение

Это, вероятно, действительно трудно достичь в D3JS, поэтому я заканчиваю писать код JS. Действительно полезной была эта страница: http://www.petercollingridge.co.uk/interactive-svg-components/pan-and-zoom-control

    var transMatrix = [1,0,0,1,0,0];

var $svg = $("#svg-workspace");

mapMatrix = $("#svg-workspace-group")[0];

function pan(dx, dy)
{
  transMatrix[4] += dx;
  transMatrix[5] += dy;

  newMatrix = "matrix(" +  transMatrix.join(' ') + ")";
  mapMatrix.setAttributeNS(null, "transform", newMatrix);
}

    function zoom(scale, mousex, mousey)
    {
        for (var i=0; i < transMatrix.length; i++)
        {
            transMatrix[i] *= scale;
        }

        transMatrix[4] += (1-scale) * mousex;
        transMatrix[5] += (1-scale) * mousey;

        newMatrix = "matrix(" +  transMatrix.join(' ') + ")";
        mapMatrix.setAttributeNS(null, "transform", newMatrix);
}

$svg.contextmenu(function () {return false;});

var drag = false;
var distanceX = 0;
var distanceY = 0;

var initX = 0;
var initY = 0;

$svg.on("mousedown", function(evt) {
  if(evt.originalEvent.which == 1) {
    drag = true;
    distanceX = 0;
    distanceY = 0;
  }
});

$svg.on("mouseup", function(evt) {
  if (evt.originalEvent.which == 1) {
    drag = false;
    initX = parseInt($("#dragtest").attr("cx"));
    initY = parseInt($("#dragtest").attr("cy"));
  }
});

$svg.on("mousemove", function(evt) {
  if( (evt.originalEvent.buttons & 2) == 2) {
    pan(evt.originalEvent.movementX, evt.originalEvent.movementY);
  } else if(drag) {
    distanceX += evt.originalEvent.movementX;
    distanceY += evt.originalEvent.movementY;

    $("#dragtest").attr("cx", initX + distanceX / transMatrix[0]);
    $("#dragtest").attr("cy", initY + distanceY / transMatrix[0]);
  }
});

$svg.on("mousewheel", function(evt) {
  if(evt.originalEvent.deltaY > 0) {
    zoom(0.9, evt.originalEvent.offsetX, evt.originalEvent.offsetY);
  } else if (evt.originalEvent.deltaY < 0) {
    zoom(1.1, evt.originalEvent.offsetX, evt.originalEvent.offsetY);
  }
});

Соответствующий HTML-код:

<svg id="svg-workspace" xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 900 600" style="display: block; margin: 0 auto; border: 1px solid #ddd;">
  <g id="svg-workspace-group" transform="translate(0,0)scale(1)">
    <circle cx="0" cy="0" r="5" stroke="black" stroke-width="1" fill="red" />
    <circle cx="100" cy="-100" r="5" stroke="black" stroke-width="1" fill="red" />
    <circle cx="100" cy="100" r="5" stroke="black" stroke-width="1" fill="red" />
    <circle cx="-100" cy="100" r="5" stroke="black" stroke-width="1" fill="red" />
    <circle id="dragtest" cx="-100" cy="-100" r="5" stroke="black" stroke-width="1" fill="red" />
  </g>
</svg>

Я обнаружил только одну проблему с этим кодом. Перетаскивание не работает должным образом с масштабированием, но да, я мог бы жить с этим;)

Другие вопросы по тегам