Skip to content

Instantly share code, notes, and snippets.

@cartoda
Last active May 22, 2017 08:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cartoda/fdfca644482223df081c to your computer and use it in GitHub Desktop.
Save cartoda/fdfca644482223df081c to your computer and use it in GitHub Desktop.
Interaction between SVG.js and D3.js libraries. Example of layering

This example shows the use of the SVG.js and D3.js libraries together to:

  • create simple objects and set the drag-and-drop on them
  • grouping all the objects and make both the zoom and moving effects on the entire draw
  • create two layers to hide/show objects created with each library
  • analyze the interaction between libraries
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Interaction between SVG.js and D3.js libraries. Example of layering" />
<meta charset="utf-8">
<title>SVG.js and D3.js libraries interaction</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script type="text/javascript" src="http://wafi.iit.cnr.it/webvis/tmp/svgjslib/svg.js"></script>
<script type="text/javascript" src="http://wafi.iit.cnr.it/webvis/tmp/svgjslib/svg.parser.js"></script>
<script type="text/javascript" src="http://wafi.iit.cnr.it/webvis/tmp/svgjslib/svg.import.js"></script>
<script type="text/javascript" src="http://wafi.iit.cnr.it/webvis/tmp/svgjslib/svg.draggable.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
var MAX_ZOOM_IN = 2.0;
var MAX_ZOOM_OUT = 0.2;
var zoomStep = 0.2;
var actualZoom = 1.0;
var MOVE_STEP = 100;
var SVGdraw, d3draw, group, zoom, nodes_data, drag, layer1Group, layer2Group;
$(function() {
// Get the background image from the server and set the environment
$.get( "http://wafi.iit.cnr.it/webvis/tmp/tiger.svg", function( data ) {
var xmlDataReceived = (new XMLSerializer()).serializeToString(data);
// Create the SVG.js and set the viewport size
SVGdraw = SVG('map').size('960', '420');
//Read the viewport size by d3 library
//alert("width: " + d3.select("svg").attr("width") + ", height: " + d3.select("svg").attr("height"));
//Set the double click event on the viewport by the SVG.js object to zoom and center on the clicked point
/*
SVGdraw.dblclick(function(eventData) {
group.center(eventData.x, eventData.y);
zoomIn();
});
*/
//Create a group with SVG.js for transformations
group = SVGdraw.group();
//Draw the background using SVG.js object and add it to group
SVGdraw.svg(xmlDataReceived).get('viewport').addTo(group);
//Create others two group to create two layers
layer1Group = group.group().attr('id', 'layer1').attr('display', 'block');
layer2Group = group.group().attr('id', 'layer2').attr('display', 'block');
//Draw one circle and one rect using SVG.js object
SVGdraw.circle(100).fill('#ff0').attr("id", "circle_1").draggable().addTo(layer1Group);
SVGdraw.svg('<rect id="rect1235" x="50" y="50" fill="#F7931E" stroke="#C1272D" stroke-width="5" width="100" height="50"/>').get('rect1235').draggable().addTo(layer1Group);
//Read the circle and the rect dimensions using d3
//alert("Id of circle: " + d3.select("#circle_1").attr("id"));
//Create a reference to a d3 object for the draw group and insert a one circle and one rect with d3
d3draw = d3.select("#layer2");
d3draw.append("circle")
.attr("cx", 80)
.attr("cy", 80)
.attr("r", 80)
.style("fill", "#ff4")
.classed('draggable', true);
d3draw.append("rect")
.attr("x", 80)
.attr("y", 80)
.attr("width", 120)
.attr("height", 70)
.attr("stroke", "#C1272D")
.attr("stroke-width", 5)
.style("fill", "#F7931E")
.classed('draggable', true);
//Create the zoom behavior with the d3 library
zoom = d3.behavior.zoom().scaleExtent([MAX_ZOOM_OUT, MAX_ZOOM_IN]).on('zoom', zoomed);
function zoomed() {
//alert('zoom d3');
actualZoom = roundFloat(parseFloat(actualZoom) + parseFloat(zoomStep));
d3draw.attr("transform", "scale(" + actualZoom + ")");
}
//Set the zoom behavior on the #map objects and disable mousedown event on the zoom
d3.select('#map').call(zoom).on("mousedown.zoom", null).on("mousewheel.zoom", null)
.on("DOMMouseScroll.zoom", null) // disables older versions of Firefox
.on("wheel.zoom", null) // disables newer versions of Firefox;;
nodes_data = [
{
x: 0,
y: 0
}, {
x: 0,
y: 0
}, {
x: 0,
y: 0
}, {
x: 0,
y: 0
}
];
//Create the drag and drop behavior with the d3 library
drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged);
function dragstarted(d){
d3.event.sourceEvent.stopPropagation();
}
function dragged(d){
d.x = d3.event.x;
d.y = d3.event.y;
d3.select(this).attr({
transform: "translate(" + d.x + "," + d.y + ")"
});
}
//Set the drag and drop behavior for the nodes having the "draggable" class and set their initial position (by the "nodes_data" matrix)
d3draw.selectAll(".draggable").call(drag).data(nodes_data);
}, 'xml');
});
function zoomIn(){
//alert('zoom svg.js');
if(actualZoom < MAX_ZOOM_IN){
actualZoom = roundFloat(parseFloat(actualZoom) + parseFloat(zoomStep));
group.scale(actualZoom, actualZoom);
}
}
function zoomOut(){
if(actualZoom > MAX_ZOOM_OUT){
actualZoom = roundFloat(parseFloat(actualZoom) - parseFloat(zoomStep));
group.scale(actualZoom, actualZoom);
}
}
function moveDrawLeft(){
group.x(group.x() - MOVE_STEP);
}
function moveDrawRight(){
group.x(group.x() + MOVE_STEP);
}
function moveDrawTop(){
group.y(group.y() - MOVE_STEP);
}
function moveDrawBottom(){
group.y(group.y() + MOVE_STEP);
}
function roundFloat(value){
return value.toFixed(2);
}
//Used to hide/show the two layers created
function layerShowing(buttonId, layerId){
var layerObj = $('#' + layerId);
var buttonObj = $('#' + buttonId);
if(layerObj.attr('display') == 'block'){
layerObj.attr('display', 'none')
buttonObj.text('Show ' + layerId);
}
else{
layerObj.attr('display', 'block');
buttonObj.text('Hide ' + layerId);
}
}
</script>
</head>
<body>
<div id="map" width="960" height="420"></div>
<br/>
<button id="zoomIn" onclick="zoomIn()">Zoom In</button>
<button id="zoomOut" onclick="zoomOut()">Zoom Out</button>
<button id="moveLeft" onclick="moveDrawLeft()">Move left</button>
<button id="moveRight" onclick="moveDrawRight()">Move right</button>
<button id="moveTop" onclick="moveDrawTop()">Move top</button>
<button id="moveBottom" onclick="moveDrawBottom()">Move bottom</button>
<br/>
<button id="layer1Button" onclick="layerShowing('layer1Button', 'layer1')">Hide layer1</button>
<button id="layer2Button" onclick="layerShowing('layer2Button', 'layer2')">Hide layer2</button>
</body>
</html>
@dsokac
Copy link

dsokac commented May 22, 2017

Hello, the solution ( http://bl.ocks.org/cartoda/raw/fdfca644482223df081c/ ) is not working in chrome (Version 58.0.3029.110 (64-bit) ):

Uncaught TypeError: Cannot read property 'numberOfItems' of undefined
at SVG.PathArray.parse (svg.js:607)
at new SVG.Array (svg.js:332)
at SVG.PathArray (svg.js:491)
at initializer.plot (svg.js:2850)
at initializer.path (svg.js:2885)
at convertNodes (svg.import.js:75)
at convertNodes (svg.import.js:87)
at convertNodes (svg.import.js:87)
at convertNodes (svg.import.js:87)
at create.svg (svg.import.js:181)

Please, can you revise it and see what is the issue ? Thank you in advance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment