d3.js - 在 D3 中平移、缩放 Canvas 以及拖动节点

标签 d3.js

我在 D3 中有以下代码(来自基本示例),用于平移和缩放 Canvas - 以及用于拖动单个元素的第二个代码块。我想要的是既能够在整个 Canvas 上平移/缩放,又能够在用户在特定对象上开始拖动时移动单个对象。

我的平移/缩放代码是:

var svgCanvas = d3.select('body')
    .append("svg:svg")
    .attr("width", 800)
    .attr("height", 800)

var g = svgCanvas.append("g")

$('body').append(
    $("<div>", {id: "canvas-wrapper" })
        .append("<div/>", { id: "canvas" })
);

var svg = d3.select("svg");
var canvas = d3.select("#canvas");
var canvasWrapper = d3.select("#canvas-wrapper");

var root = svg.append("g");

root.append("rect")
    .attr("x", 50).attr("y", 50)
    .attr("width", 50).attr("height", 50)
    .style("fill", "blue")
    .style("stroke", "green").style("stroke-width", "3px");

root.append("rect")
    .attr("x", 150).attr("y", 150)
    .attr("width", 50).attr("height", 50)
    .style("fill", "blue")
    .style("stroke", "green").style("stroke-width", "3px");

var zoom = d3.zoom()
    .scaleExtent([1, 8])
    .on("zoom", function () {
        var t = d3.event.transform;
        root.attr("transform", t);
        canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")")
    });

canvasWrapper.call(zoom);

我的拖动代码是:

var svg = d3.select('body')
    .append("svg:svg")
    .attr("width", 800)
    .attr("height", 800)

var nodes = svg
    .selectAll('.node')
    .data([
        { x: 10, y: 10 }, 
        { x: 100, y: 100 }
    ])
    .enter()
    .append('g')
    .attr('class', 'node')
    .attr("transform", function (data) {
        return "translate(" + [data.x, data.y] + ")";
    })
    .call(function () {
        return d3.drag()
            .on('drag', function (d, i) {
                d.x += d3.event.dx;
                d.y += d3.event.dy;
                d3.select(this).attr("transform", function () {
                    return "translate(" + [d.x, d.y] + ")";
                });
            })
            .on('start', function (d, i) {})
            .on('end', function (d, i) {});
    }());

nodes.append("svg:rect")
    .attr("width", 100)
    .attr("height", 100)
    .style("fill", "red")

除了当用户在开放区域上拖动时在整个 Canvas 上拖动之外,我还需要做什么才能允许单独拖动每个对象?

显然,两个代码部分之间的区别在于,一个在整个 Canvas 上工作,一个在单个元素上工作(第一个有额外的外部容器) - 我如何将两者结合起来?

我尝试通过向外部容器添加节点并向每个节点添加拖动处理来简单地组合两个代码示例,但 Canvas 似乎捕获所有事件,从而忽略节点上的拖动。

组合的非工作代码:

d3.select('body')
    .append("svg:svg")
    .attr("width", 800)
    .attr("height", 800);

$('body').append(
    $("<div>", {
        id: "canvas-wrapper"
    }).append("<div/>", {
        id: "canvas"
    })
);

var svg = d3.select("svg");
var canvas = d3.select("#canvas");
var canvasWrapper = d3.select("#canvas-wrapper");

var root = svg.append("g");

var nodes = root
    .selectAll('.node')
    .data(dataArray)
    .enter()
    .append('g')
    .attr('class', 'node')
    .attr("transform", function (data) {
        return "translate(" + [data.x, data.y] + ")";
    })
    .call(function () {
        return d3.drag().on('drag', function (d, i) {
            d.x += d3.event.dx;
            d.y += d3.event.dy;
            d3.select(this).attr("transform", function () {
                return "translate(" + [d.x, d.y] + ")";
            });
        })
    }());

nodes.append("svg:rect")
    .attr("width", 50)
    .attr("height", 50)
    .style("fill", "#ffb5b5")
    .style("fill", "#ffb5b5")
    .style("stroke", "green").style("stroke-width", "3px");

var zoom = d3.zoom()
    .scaleExtent([1, 8])
    .on("zoom", function () {
        var t = d3.event.transform;
        root.attr("transform", t);
        canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")")
    });

canvasWrapper.call(zoom);

已解决:

通过检测 Canvas 中的鼠标事件位置,可以隐藏/显示覆盖 SVG Canvas 的 Canvas 。因此,当鼠标事件在节点上启动时, Canvas 应隐藏,允许拖动功能,而其他事件应由 Canvas 捕获,允许平移/缩放

最佳答案

首先向 svg 添加一个 rect 并在此 rect 上调用缩放。任何未被元素捕获的鼠标事件都将用于缩放,删除 Canvas 包装。

对于 Chrome,您可以在 svg 上调用缩放,无需额外的 rect

var dataArray = [{x:100, y:100}, {x:200, y:200}];

var svgWidth = 800, svgHeight = 800;

var svg = d3.select('body')
    .append("svg:svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight);
var zoomRect = svg.append('rect')
    .attr("width", svgWidth)
    .attr("height", svgHeight)
    .attr("fill", "white");

var root = svg.append("g");

var nodes = root
    .selectAll('.node')
    .data(dataArray)
    .enter()
    .append('g')
    .attr('class', 'node')
    .attr("transform", function (data) {
        return "translate(" + [data.x, data.y] + ")";
    })
    .call(function () {
        return d3.drag().on('drag', function (d, i) {
            d.x += d3.event.dx;
            d.y += d3.event.dy;
            d3.select(this).attr("transform", function () {
                return "translate(" + [d.x, d.y] + ")";
            });
        })
    }());

nodes.append("svg:rect")
    .attr("width", 50)
    .attr("height", 50)
    .style("fill", "#ffb5b5")
    .style("stroke", "green").style("stroke-width", "3px");

var zoom = d3.zoom()
    .scaleExtent([1, 8])
    .on("zoom", function () {
        var t = d3.event.transform;
        root.attr("transform", t);
        //canvas.style("transform", "translateX(" + t.x + "px) translateY(" + t.y + "px) scale(" + t.k + ")");
    });

zoomRect.call(zoom);
<script src="http://d3js.org/d3.v5.min.js"></script>

关于d3.js - 在 D3 中平移、缩放 Canvas 以及拖动节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53420396/

相关文章:

javascript - d3.js 用异步函数替换 random() 数据函数

Javascript OOP,getters,setters,运行 - D3.js - 通过选项设置使图表可重新使用

javascript - d3 操作 html 的最佳方式是什么?

javascript - 如何在人力车中将 y 轴设置为固定范围?

javascript - 如何将分层 csv(分号分隔)转换为多维数组

javascript - 将选择显示为 SVG 矩形 (JavaScript)

javascript - 如何用组和汇总替换 d3js 嵌套函数

javascript - 使用嵌套 json 数据的 d3 热图 : how to create grids

javascript - 如何获得比节点间最短路径更多的路径?

javascript - 是否可以将 SVG 图像插入到页面上已渲染的现有 SVG 元素中?