Pan, zoom canvas together with drag nodes in D3












0















I have the following code in D3 (from basic examples) for panning and zooming a canvas - and the second code block for dragging individual elements. What I would like is to both be able to pan/zoom on the entire canvas and also be allowed move a single object around when user's drag starts on a specific object.



The pan/zoom code I have is:



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


The drag code I have is:



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


What do I need to do to allow dragging each object individually - in addition to drag on the entire canvas when user drags on an open are?



Obviously the difference between the two code sections is that one is working on entire canvas and one on individual elements (the first has the additional outer container) - how can I combine the two?



I have tried to simply combine the two code examples by adding nodes to the outer container and add drag handling to each node but the canvas seems to capture all events thus ignoring the drag on nodes.



The combined non-working code:



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


SOLVED:



By detecting mouse event locations in the canvas one may hide/show the canvas which is overlaying the SVG canvas. Therefore when there are mouse events which are started over a node then canvas should be hidden allowing drag to function while other events should be caught by canvas allowing pan/zoom










share|improve this question

























  • look at the d3-force examples from the docs, it is called drag

    – rioV8
    Nov 21 '18 at 22:14











  • From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

    – Evan M.
    Nov 22 '18 at 3:02











  • drag is not a force feature, it is independent and can be used on any element

    – rioV8
    Nov 22 '18 at 3:43











  • I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

    – Evan M.
    Nov 22 '18 at 4:01
















0















I have the following code in D3 (from basic examples) for panning and zooming a canvas - and the second code block for dragging individual elements. What I would like is to both be able to pan/zoom on the entire canvas and also be allowed move a single object around when user's drag starts on a specific object.



The pan/zoom code I have is:



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


The drag code I have is:



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


What do I need to do to allow dragging each object individually - in addition to drag on the entire canvas when user drags on an open are?



Obviously the difference between the two code sections is that one is working on entire canvas and one on individual elements (the first has the additional outer container) - how can I combine the two?



I have tried to simply combine the two code examples by adding nodes to the outer container and add drag handling to each node but the canvas seems to capture all events thus ignoring the drag on nodes.



The combined non-working code:



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


SOLVED:



By detecting mouse event locations in the canvas one may hide/show the canvas which is overlaying the SVG canvas. Therefore when there are mouse events which are started over a node then canvas should be hidden allowing drag to function while other events should be caught by canvas allowing pan/zoom










share|improve this question

























  • look at the d3-force examples from the docs, it is called drag

    – rioV8
    Nov 21 '18 at 22:14











  • From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

    – Evan M.
    Nov 22 '18 at 3:02











  • drag is not a force feature, it is independent and can be used on any element

    – rioV8
    Nov 22 '18 at 3:43











  • I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

    – Evan M.
    Nov 22 '18 at 4:01














0












0








0


1






I have the following code in D3 (from basic examples) for panning and zooming a canvas - and the second code block for dragging individual elements. What I would like is to both be able to pan/zoom on the entire canvas and also be allowed move a single object around when user's drag starts on a specific object.



The pan/zoom code I have is:



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


The drag code I have is:



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


What do I need to do to allow dragging each object individually - in addition to drag on the entire canvas when user drags on an open are?



Obviously the difference between the two code sections is that one is working on entire canvas and one on individual elements (the first has the additional outer container) - how can I combine the two?



I have tried to simply combine the two code examples by adding nodes to the outer container and add drag handling to each node but the canvas seems to capture all events thus ignoring the drag on nodes.



The combined non-working code:



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


SOLVED:



By detecting mouse event locations in the canvas one may hide/show the canvas which is overlaying the SVG canvas. Therefore when there are mouse events which are started over a node then canvas should be hidden allowing drag to function while other events should be caught by canvas allowing pan/zoom










share|improve this question
















I have the following code in D3 (from basic examples) for panning and zooming a canvas - and the second code block for dragging individual elements. What I would like is to both be able to pan/zoom on the entire canvas and also be allowed move a single object around when user's drag starts on a specific object.



The pan/zoom code I have is:



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


The drag code I have is:



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


What do I need to do to allow dragging each object individually - in addition to drag on the entire canvas when user drags on an open are?



Obviously the difference between the two code sections is that one is working on entire canvas and one on individual elements (the first has the additional outer container) - how can I combine the two?



I have tried to simply combine the two code examples by adding nodes to the outer container and add drag handling to each node but the canvas seems to capture all events thus ignoring the drag on nodes.



The combined non-working code:



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


SOLVED:



By detecting mouse event locations in the canvas one may hide/show the canvas which is overlaying the SVG canvas. Therefore when there are mouse events which are started over a node then canvas should be hidden allowing drag to function while other events should be caught by canvas allowing pan/zoom







d3.js






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 5:25







Evan M.

















asked Nov 21 '18 at 20:59









Evan M.Evan M.

938




938













  • look at the d3-force examples from the docs, it is called drag

    – rioV8
    Nov 21 '18 at 22:14











  • From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

    – Evan M.
    Nov 22 '18 at 3:02











  • drag is not a force feature, it is independent and can be used on any element

    – rioV8
    Nov 22 '18 at 3:43











  • I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

    – Evan M.
    Nov 22 '18 at 4:01



















  • look at the d3-force examples from the docs, it is called drag

    – rioV8
    Nov 21 '18 at 22:14











  • From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

    – Evan M.
    Nov 22 '18 at 3:02











  • drag is not a force feature, it is independent and can be used on any element

    – rioV8
    Nov 22 '18 at 3:43











  • I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

    – Evan M.
    Nov 22 '18 at 4:01

















look at the d3-force examples from the docs, it is called drag

– rioV8
Nov 21 '18 at 22:14





look at the d3-force examples from the docs, it is called drag

– rioV8
Nov 21 '18 at 22:14













From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

– Evan M.
Nov 22 '18 at 3:02





From what I have seen this forces positioning of nodes too right? I need node positioning to be exactly as user sets it without any additional automatic positioning, gravity etc

– Evan M.
Nov 22 '18 at 3:02













drag is not a force feature, it is independent and can be used on any element

– rioV8
Nov 22 '18 at 3:43





drag is not a force feature, it is independent and can be used on any element

– rioV8
Nov 22 '18 at 3:43













I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

– Evan M.
Nov 22 '18 at 4:01





I think I have found a direction (will update question shortly) - all I need is to be able to remove/hide/move z-index of canvas which is overlaying the SVG when mouse down starts over one of the nodes.

– Evan M.
Nov 22 '18 at 4:01












1 Answer
1






active

oldest

votes


















0














As the first thing add a rect to the svg and call zoom on this rect. Any mouse event not catched by an element will be used for zoom, remove the canvas wrapper.



For Chrome you can call zoom on the svg, no need for the additional 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>








share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420396%2fpan-zoom-canvas-together-with-drag-nodes-in-d3%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    As the first thing add a rect to the svg and call zoom on this rect. Any mouse event not catched by an element will be used for zoom, remove the canvas wrapper.



    For Chrome you can call zoom on the svg, no need for the additional 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>








    share|improve this answer




























      0














      As the first thing add a rect to the svg and call zoom on this rect. Any mouse event not catched by an element will be used for zoom, remove the canvas wrapper.



      For Chrome you can call zoom on the svg, no need for the additional 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>








      share|improve this answer


























        0












        0








        0







        As the first thing add a rect to the svg and call zoom on this rect. Any mouse event not catched by an element will be used for zoom, remove the canvas wrapper.



        For Chrome you can call zoom on the svg, no need for the additional 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>








        share|improve this answer













        As the first thing add a rect to the svg and call zoom on this rect. Any mouse event not catched by an element will be used for zoom, remove the canvas wrapper.



        For Chrome you can call zoom on the svg, no need for the additional 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>








        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>





        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>






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 9:42









        rioV8rioV8

        4,5142312




        4,5142312
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420396%2fpan-zoom-canvas-together-with-drag-nodes-in-d3%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to change which sound is reproduced for terminal bell?

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

            Can I use Tabulator js library in my java Spring + Thymeleaf project?