d3.js zoom without overflow - javascript

I have a force directed graph with fixed nodes. I have allowed zoom in the graph :
var force = d3.layout.force()
.on("tick", tick);
var zoom = d3.behavior.zoom()
.scaleExtent([0, 50])
.on("zoom", zoomed);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
var graphGroup = svg.append("g")
.attr("height", graphHeight)
.attr("width", graphWidth)
.attr("class", "graph-group")
.attr("transform", "translate(" + margin + "," + margin + ")");
graphGroup.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", graphHeight)
.attr("class", "graph-limit")
.attr("width", graphWidth);
...
function zoomed() {
graphContainer.attr("transform", "translate(" + t + ")scale(" + d3.event.scale + ")");
}
I would like to limit the zoom (scale and translation) of the graph within the rectangle with class "graph-limit".
I've tried to put overflow:hidden in style, but without success.
Any idea ?
EDIT :
Here a jsfiddle
http://jsfiddle.net/Lxc43v8d/20/

This is how you can do it.
Use clip path with dimension exactly same as that off the rectangle:
//make a clip path
svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", graphHeight)
.attr("width", graphWidth);
To the group which holds the rectangle all nodes and links add the clip path like this
var graphGroup = svg.append("g")
.attr("clip-path", "url(#clip)")//add the clip path
.attr("height", graphHeight)
.attr("width", graphWidth)
.attr("class", "graph-group");
Working code here
Hope this helps!

Related

SVG element not being responsive - when screen resized

I have a map-container which shows world map, that is supposed to be responsive but it does not work when I run it and resize the page, I cant find whats the issue. what it is expected when screen is resized. here's my code
var tooltipMap = d3.select("body")
.append("div")
.attr("class", "map-tooltip shadow")
.style("opacity", 0);
var projection = d3.geo.mercator()
.center([0, 62 ])
.scale(150)
.rotate([0, 0]);
var svg = d3.select("#map-container").append("svg")
.attr("width", width)
.attr("height", height)
.attr('viewBox', "0 0 "+(width)+" "+(height))
.attr('preserveAspectRatio', 'xMinYMid')
.attr("class","chart");
var path = d3.geo.path()
.projection(projection);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "bgImg")
.attr("width", 6)
.attr("height", 6)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", '../assets/img/map-tile.png')
.attr("width", 6)
.attr("height", 6)
.attr("x", 0)
.attr("y", 0);
var g = svg.append("g")
.attr("width", width+160)
.attr("height", height);
// load and display the World
d3.json("om.json", function (error, topology) {
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries).geometries)
.enter()
.append("path")
.attr("fill", "url(#bgImg)")
.attr("d", path);
});
<script src="js/d3.v3.min.js"></script>
<div id="map-container"></div>
Basically as of what appears,
.attr("class","chart");
does not work, wondering why ?
Solution -
CSS - strange as hell, but this was the issue my css was not placed perfectly. !!! Facepalm !!!
.chart{ width:100%; height:100%; }

D3 Zoom TypeError: t.apply is not a function

Currently, i'm trying to implement a zoom function to my data visualization. Sometimes an error occurs "d3.min.js:1 Uncaught TypeError: t.apply is not a function" when i try to zoom or to move the svg element. It looks like an internal error within d3 library.
var height = $("#content").height();
var width = $("#content").width();
var svg = d3.select("#content").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svg_canvas")
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
.attr("transform", "translate(" + (width / 2.0) + "," + (height /2.0 )+ ")")
.append("g")
.attr("class", "interaction_group");
zoom_layer = svg;
//Overlay for zooming
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + (-width / 2.0) + "," + -(height/2.0 ) + ")");
The event handler "zoom" is really basic:
function zoom() {
zoom_layer.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
The implementation was realized with the latest D3.js V3 version.
Firstly, declare your zoom behavior:
var myZoomBehavior=d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom)
Then call it to the svg root:
var svg = d3.select("#content").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svg_canvas").call(myZoomBehavior)
Then create the zoomable g with the same variable name as in your zoom function:
var zoom_layer=svg.append("g")

How do i add a clip path for my graph ?

I have this fiddle : http://jsfiddle.net/q0ubpmwj/5/
I have been trying to mess around with the clip path so the graph doesnt go outside the axis but i cant seem to get it to work.
Heres a bit of the clip path code i have used but it doesnt seem to work :/
var svg = viewer.append("svg").attr('id', 'viewerPins')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var clip = viewer.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0").attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)")
//.call(zoom)
;
You appending the defs outside of the svg:
viewer.append("defs").append("svg:clipPath")
should be
svg.append("defs").append("svg:clipPath")

Is this approach right of making a heatmap matrix

I need a heatmap matrix like this,
Now I tried using D3.js, I am able to make matrix and also made it zoomable too, but now I am stuck at adding Notes to rectangles as SVG doesn't supports it.
Am I on right track or can I use Div and jQuery instead to develop this heatmap, I visited hundreds of plugins but non satisfies my needs.
Proper matrix - http://jsfiddle.net/nhe613kt/49/
Trying adding Notes with one rectangle - http://jsfiddle.net/nhe613kt/60
Can I use any other plugin or simple HTML ?
var width = 600,
height = 600;
var margin = {top: -5, right: -5, bottom: -5, left: -5};
var zoom = d3.behavior.zoom()
.scaleExtent([1, 15])
.on("zoom", zoomed);
var svgContainer = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", "black")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var zoomed = function () {
svgContainer.attr("transform", "translate("+ d3.event.translate + ")scale(" + d3.event.scale + ")");
};
var zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed)
.size([width, height]);
svgContainer.call(zoom);
var rectangle1 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red")
.append("text")
.text("Hahaha");
You need to configure the text node properly:
svgContainer.append("text")
.attr("x", 10)
.attr("y", 20)
.attr("fill", "blue")
.text("Hahaha");
Otherwise, it might be outside of the visible are (y=0 is a common mistake; the Y coordinate moves the baseline of the text, not the top-right corner). Also without a color, the text will inherit one from the parent.
Demo: http://jsfiddle.net/nhe613kt/65/

how to plot data from JSON object on .svg file using D3.js

Image is appending as a background which is not clear.
Able to plot data on svg element which is created in this code.
But want to plot json data on image/.svg file with the following..
Will appreciate if any references...
$(function(){
makePlot();
// $('#zoomReset').on('click',function(e){
// e.preventDefault();
// //$('#chart').empty();
// console.log("sadf");
// makePlot();
// });
});
var makePlot = function() {
d3.json("scatter-data-2010.json", function(dataset) {
//Width and height
var margin = {top: 80, right: 10, bottom: 60, left: 80},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var centered = undefined;
//Create SVG element
tooltip = d3.select("body").append("div")
.attr("class", "plan_tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("");
var svg = d3.select("#vis")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
/// Set Scales and Distortions
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['n_workers_change']; }), d3.max(dataset, function(d) { return d['n_workers_change']; })])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['earnings_change']; }), d3.max(dataset, function(d) { return d['earnings_change']; })])
.range([height,0]);
var color_scale = d3.scale.category20();
//Add 2 more colors to category 20 because there are 22 parent industry categories
var color_scale_range = color_scale.range();
color_scale_range.push("#e6550d","#6baed6")
radiusScale = d3.scale.sqrt()
.domain([d3.min(dataset, function(d) { return d['n_workers_y']; }), d3.max(dataset, function(d) { return d['n_workers_y']; }) ])
.range([3, 15]);
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
var rect = svg.append("rect")
.attr("class", "background")
.attr("pointer-events", "all")
//.attr("fill","none")
.attr("fill","url(#background)")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().x(xScale).y(yScale).on("zoom", redraw));
// Tooltips for Dots
set_tooltip_label = function (d) {
var company_name;
tooltip.html(d.category + "<br><strong>N Workers in 2010 (thousands)</strong>: " + d['n_workers_y'] + "<br><strong>Med. Wkly Earnings in 2010 ($)</strong>: " + d.earnings_y + "<br><strong> Category</strong>: " + d.parent_name );
if (!(event === undefined)) {
tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px")
}
};
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("clip-path", "url(#clip)")
// Set cx, cy in the redraw function
.attr("r", function(d) {
return radiusScale(d['n_workers_y']);
})
.attr("fill", function(d) {
return color_scale(d.parent_id)
})
.on("mouseover", function () {
return tooltip.style("visibility", "visible")
}).on("mousemove", function (d) {
set_tooltip_label(d);
}).on("mouseout", function () {
tooltip.style("visibility", "hidden");
});
// Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
.tickSize(-height)
.tickFormat(d3.format("s"));
// Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
.tickFormat(function(d) { return d + " %"; })
.tickSize(-width);
// Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
// Create Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + 0 + ",0)")
.call(yAxis);
// Add Label to X Axis
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "middle")
.attr("x", width - width/2)
.attr("y", height + margin.bottom/2)
.text("Percent Change in Number of Workers in Industry");
// Add label to Y Axis
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "middle")
.attr("y", -margin.left + 5)
.attr("x", 0 - (height/2))
.attr("dy", "1em")
.attr("transform", "rotate(-90)")
.text("Percent Change in Inflation Adjusted Median Weekly Earnings");
// Add title
svg.append("text")
.attr("class", " title")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2)
.text("Changes in Employment and Salary by Industry, 2003 - 2010");
// Add subtitle
svg.append("text")
.attr("class", "subtitle")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2 + 15)
.text("Scroll and drag to zoom/pan, hover for details.");
var objects = svg.append("svg")
.attr("class", "objects")
.attr("width", width)
.attr("height", height);
//Create main 0,0 axis lines:
hAxisLine = objects.append("svg:line")
.attr("class", "axisLine hAxisLine");
vAxisLine = objects.append("svg:line")
.attr("class", "axisLine vAxisLine");
// Zoom/pan behavior:
function redraw(duration) {
var duration = typeof duration !== 'undefined' ? duration : 0;
if (d3.event){
//console.log("In the zoom function now");
//console.log(d3.event.scale);
//console.log(d3.event.translate);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
hAxisLine.transition().duration(duration)
.attr("x1",0)
.attr("y1",0)
.attr("x2",width)
.attr("y2",0)
.attr("transform", "translate(0," + (yScale(0)) + ")");
vAxisLine.transition().duration(duration)
.attr("x1",xScale(0))
.attr("y1",yScale(height))
.attr("x2",xScale(0))
.attr("y2",yScale(-height));
circles.transition().duration(duration)
.attr("cx", function(d) {
return xScale(d['n_workers_change']);
})
.attr("cy", function(d) {
return yScale(d['earnings_change']);
})
}; // <-------- End of zoom function
redraw(0); // call zoom to place elements
}); // end of json loading section
};
You need to define the background image as a pattern and then fill the rect with that pattern:
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("fill", "url(#background)");

Categories

Resources