I am trying to modify a d3 animation example at http://bl.ocks.org/JMStewart/6455921
!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
var line = d3.svg.diagonal();
var lineData = {source:{x:25, y:25},
target:{x:400, y:400}};
var path = svg.append("path")
.attr("d", line(lineData))
.style("stroke", "black")
.style("fill", "none");
svg.append("circle")
.attr("cx", 25) //Starting x
.attr("cy", 25) //Starting y
.attr("r", 25)
.transition()
.delay(250)
.duration(1000)
.ease("linear")
.tween("pathTween", function(){return pathTween(path)})
// .tween("pathTween", pathTween); //Custom tween to set the cx and cy attributes
function pathTween(path){
var length = path.node().getTotalLength(); // Get the length of the path
var r = d3.interpolate(0, length); //Set up interpolation from 0 to the path length
return function(t){
var point = path.node().getPointAtLength(r(t)); // Get the next point along the path
d3.select(this) // Select the circle
.attr("cx", point.x) // Set the cx
.attr("cy", point.y) // Set the cy
}
}
</script>
</body>
</html>
What I would like to do is to replace the circle in the animation with a valid SVG segment and animate that along the path. This is what my code looks like. I am able to append the svg image of a person but I cannot animate the same as the circle. What am I missing?
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
var line = d3.svg.diagonal();
var lineData = {source:{x:25, y:25},
target:{x:400, y:400}};
var person = `
<g transform="scale(.4 .4)">
<g>
<path d="M40.84,0.14 C36.68,0.82 33.28,3.92 32.24,7.99 C30.99,12.84 33.29,17.87 37.77,20.09 C39.42,20.91 40.54,21.15 42.55,21.14 C43.94,21.13 44.28,21.1 45.12,20.87 C48.75,19.9 51.61,17.13 52.64,13.59 C53.39,10.99 53.15,8.39 51.95,5.95 C50.56,3.14 48.08,1.12 45.05,0.34 C43.82,0.03 42.04,-0.06 40.84,0.14 z" fill="#000000"/>
<path d="M37.65,23.45 C36.16,23.69 34.56,24.31 33.22,25.17 C32.48,25.63 11.89,42.32 11.2,43 C10.6,43.59 10.21,44.21 9.96,44.97 C9.74,45.67 5.22,66.05 5.14,66.7 C5.06,67.42 5.29,68.5 5.7,69.3 C6.57,71.02 8.63,72.08 10.53,71.79 C11.44,71.65 12.48,71.11 13.19,70.39 C14.1,69.48 14.41,68.76 14.96,66.3 C15.51,63.8 18.47,50.32 18.52,50.07 C18.54,49.94 25.9,43.87 25.97,43.93 C25.98,43.94 23.43,55.27 20.3,69.11 L14.62,94.27 L7.77,105.77 C4,112.1 0.8,117.54 0.67,117.86 C-0.24,120.04 -0.21,121.98 0.76,123.99 C1.14,124.77 1.36,125.07 2.08,125.8 C3.07,126.79 3.94,127.32 5.12,127.67 C7.62,128.39 10.09,127.8 12.01,126.03 C12.34,125.72 12.81,125.19 13.04,124.86 C13.85,123.72 28.21,99.4 28.8,98.17 L29.39,96.95 L31.17,88.72 C32.14,84.2 32.97,80.51 33.01,80.52 C33.13,80.58 48.3,97.21 48.3,97.29 C48.3,97.45 52.89,121.54 53.06,122.25 C53.64,124.78 55.56,126.91 57.94,127.66 C61.24,128.7 64.9,127.16 66.46,124.08 C67.17,122.68 67.39,120.84 67.06,119.09 C66.98,118.68 66.61,116.76 66.25,114.84 C65.89,112.92 65.1,108.76 64.5,105.6 C63.9,102.44 63.11,98.27 62.75,96.35 C62.1,92.9 61.8,91.73 61.41,91.09 C61.3,90.91 56.99,85.77 51.83,79.67 C46.67,73.58 42.46,68.53 42.47,68.47 C42.55,68.03 47.22,47.54 47.25,47.51 C47.27,47.49 48.21,49.32 49.33,51.57 C50.91,54.72 51.48,55.77 51.84,56.17 C52.41,56.8 67.96,67.56 68.95,68.01 C70.84,68.86 72.94,68.47 74.34,67.01 C76.07,65.19 76.13,62.38 74.47,60.54 C74.16,60.19 71.78,58.5 66.62,54.94 L59.22,49.85 L57.77,46.95 C51.34,34.17 48.46,28.54 48.11,28.07 C45.54,24.58 41.55,22.82 37.65,23.45 z" fill="#000000"/>
</g>
</g>`
var path = svg.append("path")
.attr("d", line(lineData))
.style("stroke", "black")
.style("fill", "none");
svg.append('g').attr('id','person').html(person)
.attr("cx", 25) //Starting x
.attr("cy", 25) //Starting y
.attr("r", 25)
.transition()
.delay(250)
.duration(1000)
.ease("linear")
.tween("pathTween", function(){return pathTween(path)})
// .tween("pathTween", pathTween); //Custom tween to set the cx and cy attributes
function pathTween(path){
var length = path.node().getTotalLength(); // Get the length of the path
var r = d3.interpolate(0, length); //Set up interpolation from 0 to the path length
return function(t){
var point = path.node().getPointAtLength(r(t)); // Get the next point along the path
d3.select(this) // Select the circle
.attr("cx", point.x) // Set the cx
.attr("cy", point.y) // Set the cy
}
}
</script>
</body>
</html>
cx and cy are attributes valid for the circle only. To animate a group, use a transform attribute with the translate(x,y) value. More about transform here: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform
You could define your person with a <svg> element - they can be nested, and you can use x and y attributes for positioning:
var person = `
<g transform="scale(.4 .4)">
<path d="M40.84,0.14 C36.68,0.82 33.28,3.92 32.24,7.99 C30.99,12.84 33.29,17.87 37.77,20.09 C39.42,20.91 40.54,21.15 42.55,21.14 C43.94,21.13 44.28,21.1 45.12,20.87 C48.75,19.9 51.61,17.13 52.64,13.59 C53.39,10.99 53.15,8.39 51.95,5.95 C50.56,3.14 48.08,1.12 45.05,0.34 C43.82,0.03 42.04,-0.06 40.84,0.14 z" fill="#000000"/>
<path d="M37.65,23.45 C36.16,23.69 34.56,24.31 33.22,25.17 C32.48,25.63 11.89,42.32 11.2,43 C10.6,43.59 10.21,44.21 9.96,44.97 C9.74,45.67 5.22,66.05 5.14,66.7 C5.06,67.42 5.29,68.5 5.7,69.3 C6.57,71.02 8.63,72.08 10.53,71.79 C11.44,71.65 12.48,71.11 13.19,70.39 C14.1,69.48 14.41,68.76 14.96,66.3 C15.51,63.8 18.47,50.32 18.52,50.07 C18.54,49.94 25.9,43.87 25.97,43.93 C25.98,43.94 23.43,55.27 20.3,69.11 L14.62,94.27 L7.77,105.77 C4,112.1 0.8,117.54 0.67,117.86 C-0.24,120.04 -0.21,121.98 0.76,123.99 C1.14,124.77 1.36,125.07 2.08,125.8 C3.07,126.79 3.94,127.32 5.12,127.67 C7.62,128.39 10.09,127.8 12.01,126.03 C12.34,125.72 12.81,125.19 13.04,124.86 C13.85,123.72 28.21,99.4 28.8,98.17 L29.39,96.95 L31.17,88.72 C32.14,84.2 32.97,80.51 33.01,80.52 C33.13,80.58 48.3,97.21 48.3,97.29 C48.3,97.45 52.89,121.54 53.06,122.25 C53.64,124.78 55.56,126.91 57.94,127.66 C61.24,128.7 64.9,127.16 66.46,124.08 C67.17,122.68 67.39,120.84 67.06,119.09 C66.98,118.68 66.61,116.76 66.25,114.84 C65.89,112.92 65.1,108.76 64.5,105.6 C63.9,102.44 63.11,98.27 62.75,96.35 C62.1,92.9 61.8,91.73 61.41,91.09 C61.3,90.91 56.99,85.77 51.83,79.67 C46.67,73.58 42.46,68.53 42.47,68.47 C42.55,68.03 47.22,47.54 47.25,47.51 C47.27,47.49 48.21,49.32 49.33,51.57 C50.91,54.72 51.48,55.77 51.84,56.17 C52.41,56.8 67.96,67.56 68.95,68.01 C70.84,68.86 72.94,68.47 74.34,67.01 C76.07,65.19 76.13,62.38 74.47,60.54 C74.16,60.19 71.78,58.5 66.62,54.94 L59.22,49.85 L57.77,46.95 C51.34,34.17 48.46,28.54 48.11,28.07 C45.54,24.58 41.55,22.82 37.65,23.45 z" fill="#000000"/>
</g>`
....
svg.append('svg').attr('id','person').html(person)
.attr("x", 25) //Starting x, left side
.attr("y", 25) //Starting y, top side
.transition()
....
Related
I need to make my doughnut chart a horizontal graph like in this image >
this is the code that i use for other doughnut charts
var dataset = {
hddrives: [total - value, value],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range([secondColor, mainColor]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select(divName).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Draw the Circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 65)
.attr("fill", "#F6FBF3");
var path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function (d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", "0em")
.style("text-anchor", "middle")
.attr("class", "inside")
.attr("font-size", "30px")
.text(function (d) { return value; });
svg.append("text")
.attr("dy", "1.5em")
.style("text-anchor", "middle")
.attr("class", "data")
.text(function (d) { return nomeGtin; });
}
I tried messing around with the attr values and the arc value, but without success, any ideas on how to approach this? Thanks
That isn't much of a donut chart, it's now a stacked bar chart (with a single bar). The pie and arc helpers aren't much help for that, they are concerned with calculating angles and circular things; you are now dealing with rectangles. d3.stack could help, but is probably overkill. Here's a quicky where I've just done the math (ie positioning) myself:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<script>
var width = 500,
height = 200,
w = 300,
h = 100;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var total = 0,
l = 0,
// fake random data
raw = d3.range(5).map(function(d){
var v = Math.random() * 10;
total += v;
return v;
}),
// calculate percents and cumulative position
data = raw.map(function(d){
var rv = {
v: d,
l: l,
p: d/total
}
l += rv.p;
return rv;
});
// scale and color
var s = d3.scale.linear()
.range([0, w])
.domain([0, 1]),
c = d3.scale.category20();
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', function(d){
return s(d.l) + width/2 - w/2; // place based on cumulative
})
.attr('width', function(d){
return s(d.p); // width from scale
})
.attr('height', h)
.attr('y', height/2 - h/2)
.style('fill', function(d,i){
return c(i);
})
.style('stroke', 'white')
.style('stroke-width', '2px');
</script>
</body>
</html>
I'm attempting to nest an arc generated using d3.arc perfectly inside another arc.
I can do this by drawing "on my own":
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
function arc_position(x, y, radius, angle) {
return {
x: x + (radius * Math.cos(angle)),
y: y + (radius * Math.sin(angle))
};
}
function describe_arc(x, y, radius, startAngle, endAngle) {
var s = arc_position(x, y, radius, endAngle);
var e = arc_position(x, y, radius, startAngle);
var sweep = e - s <= 180 ? '0' : '1';
var d = [
'M', s.x, s.y,
'A', radius, radius, 0, sweep, 0, e.x, e.y
].join(' ');
return d;
}
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.append("g");
var s = arc_position(250, 250, 200, Math.PI/2);
var e = arc_position(250, 250, 200, (Math.PI * 3)/2);
svg.append("path")
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", "20px")
.attr("d", describe_arc(250,250,180,(Math.PI * 3)/2, Math.PI/2));
svg.append("path")
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", "20px")
.attr("d", "M" + (s.x + 30) + "," + s.y + "L" + (e.x + 30) + "," + e.y);
svg.append("path")
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "20px")
.attr("d", describe_arc(250,250,200,(Math.PI * 3)/2, Math.PI/2));
svg.append("path")
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "20px")
.attr("d", "M" + (s.x + 10) + "," + s.y + "L" + (e.x + 10) + "," + e.y);
</script>
</body>
</html>
But I can't figure out a methodology using d3.arc:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.append("g")
.attr("transform","translate(250,250)");
var arc = d3.arc()
.innerRadius(0)
.outerRadius(200)
.startAngle(0)
.endAngle(Math.PI);
svg.append("path")
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "20px")
.attr("d", arc());
arc.outerRadius(200 - 40);
svg.append("path")
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", "20px")
.attr("d", arc())
.attr("transform", "translate(20,0)")
</script>
</body>
</html>
Any ideas?
I don't think that there is a good way to do this just using d3.arc because that is meant for drawing sections of circles and you're trying to draw a partial ellipse.
You can get close by generating the angle offset using the stroke width and the radius of the inner arc as offsetAngle = sin(stroke width / inner radius). The arc's startAngle is the offsetAngle and the endAngle is Math.PI - offsetAngle.
Unfortunately, that will generate a path which includes the center point of the circle. You can hack together something that works by just removing the L0,0 from the generated path (innerArc().replace("L0,0","")) and this will give you what you want, albeit in an ugly fashion.
Because it is a fairly simple path, it is probably best to use your own path generator to do this instead.
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.append("g")
.attr("transform","translate(250,250)");
var outerRadius = 200;
var stroke = 20;
var innerRadius = outerRadius - stroke;
var innerAngle = Math.sin(stroke/innerRadius);
var outerArc = d3.arc()
.innerRadius(0)
.outerRadius(outerRadius)
.startAngle(0)
.endAngle(Math.PI);
var innerArc = d3.arc()
.innerRadius(0)
.outerRadius(innerRadius)
.startAngle(innerAngle)
.endAngle(Math.PI - innerAngle);
svg.append("path")
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", stroke)
.attr("d", outerArc());
svg.append("path")
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", stroke)
.attr("d", innerArc().replace("L0,0",""));
</script>
</body>
</html>
(This is not an answer, but just a comment, which I chose to disguise as an answer because I need the S.O. snippet)
I believe that Paul S is right, and he deserves the big prize of the green tick: what you're trying to paint in the inner (orange) path is not an arc of a circumference, but an ellipse instead. And, as the docs say,
The arc generator produces a circular or annular sector
, which will not work for creating an elliptic sector.
You can easily see that in the following demo: using a for loop, we draw arcs with decreasing outer radius. The only way to perfectly fill the internal space of each arc is if the next, smaller arch has the same center of the precedent, bigger one:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.append("g")
.attr("transform","translate(250,250)");
var arc = d3.arc()
.innerRadius(0)
.outerRadius(200)
.startAngle(0)
.endAngle(Math.PI);
var color = d3.scaleOrdinal(d3.schemeCategory10);
for(var i = 0; i<11; i++){
svg.append("path")
.style("stroke", color(i))
.style("fill", "none")
.style("stroke-width", "20px")
.attr("d", arc());
arc.outerRadius(200 - 20*i);
};
</script>
</body>
</html>
There is an even easier way to visualize that. Let's create a single arc, with a huge stroke:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
.append("g")
.attr("transform","translate(250,250)");
var arc = d3.arc()
.innerRadius(0)
.outerRadius(150)
.startAngle(0)
.endAngle(Math.PI);
svg.append("path")
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "100px")
.attr("d", arc());
</script>
</body>
</html>
Look at the blue arc: it is a semicircle. Now look at the white space inside it: it's clearly not a semicircle. The blue thing is a semicircle, but the space inside it is not.
So, as d3.arc() right now doesn't have the option to set two different focal points, the options are creating your own function (as you did) or hacking the path (as Paul S did).
You draw second arc with outer radius R - 2 * strokewidth and center shifted by strokewidth.
But smaller arc should have the same center as larger one and outer radius R - strokewidth
All:
I am pretty new to D3 transition, I wonder how can I not apply length transition on axis tick lines when I switch data?
My code is like:
var data1 = [1,2,3,4]
var data2 = [1,4,8,12]
function draw(data){
var svg = d3.select(".chart svg");
if(svg.empty()){
svg = d3.select(".chart")
.append("svg");
svg.append("g")
.classed("yaxis", true)
}
svg.attr("width", 400)
.attr("height", 300);
var axisg = svg.select("g.yaxis")
.attr("transform", function(){
return "translate(40, 20)";
})
var scale = d3.scale.linear();
scale.domain(d3.extent(data)).range([300-40, 0]);
var axis = d3.svg.axis();
axis.scale(scale).orient("left")/*.ticks(5)*/;
axisg.transition().duration(1500).ease("sin-in-out").call(axis)
.selectAll("line")
.attr("x2", 300-40)
.style("stroke", "black")
.style("stroke-width", "1px");
axisg.select("path").style("fill", "none")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<button onclick="draw(data1)">Data1</button>
<button onclick="draw(data2)">Data2</button>
<div class="chart"></div>
How do I assign id attribute to each append of circle so that I can later use the circles based on its id. For now I am able to clone the circle on drag with out any id.
Demo: https://jsbin.com/zuxetokigi/1/edit?html,output
Code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
<script>
svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
circle1 = svg.append("circle")
.attr("id", "circleToClone")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 20);
var drag = d3.behavior.drag()
.origin(function ()
{
var t = d3.select(this);
return {x: t.attr("cx"), y: t.attr("cy")};
})
.on('dragend', function (d) {
var mouseCoordinates = d3.mouse(this);
if (mouseCoordinates[0] > 120) {
//Append new element
var circle2 = d3.select("svg").append("circle")
.classed("drg", true)
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 20)
.attr("cx", mouseCoordinates[0])
.attr("cy", mouseCoordinates[1])
.style("fill", "green");
}
});
circle1.call(drag);
</script>
</body>
</html>
If you want to give every circle a unique id, you could use a function to generate a GUID/UUID ('Globally Unique Identifier') for every circle.
You could add the following function from Salvik Meltser's GUID/UUID function to your code (anywhere before the drag function):
function guid() {
function _random_letter() {
return String.fromCharCode(97+Math.floor(Math.random() * 26));
}
function _p8(s) {
var p = (Math.random().toString(16)+"000000000").substr(2,8);
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : _random_letter() + p.substr(0, 7);
}
return _p8() + _p8(true) + _p8(true) + _p8();
}
I modified Salvik's original function a little bit because HTML element IDs need to start with a letter in HTML 4 or contain at least one letter in HTML 5.
And then where you append the new circle, just use .attr("id", guid()) to generate a new id for the circle.
var circle2 = d3.select("svg").append("circle")
.attr("id", guid())
.classed("drg", true)
...
You can assign new id attribute to each element created using its index:
var circle2 = d3.select("svg").append("circle")
.classed("drg", true)
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 20)
.attr("cx", mouseCoordinates[0])
.attr("cy", mouseCoordinates[1])
.style("fill", "green");
circle2.selectAll("circle").attr("id", function(d,i) { return i; });
I having problem of zoom over map. The actual problem is when i zoom map, the location showing on map using smiley could also zoom but i don't want to zoom smiley. It could stay at same size and place. Sometime smiley get overlap so to avoid this i am trying to solve the above problem but i don't have idea how to transform attribute contains many things like images and text on map of d3.js. Please have a look at jsfiddle link and you can see that at japan 3 smiley get overlap and keep overlapped even after zooming map.
My JSfiddle link
my code is following:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke: white;
stroke-width: 0.25px;
fill: grey;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
var width = 960,
height = 500;
var data = [
{
"code":"TYO",
"city":"TOKYO",
"country":"JAPAN",
"lat":"35.68",
"lon":"139.76"
},
{
"code":"OSK",
"city":"Osaka",
"country":"JAPAN",
"lat":" 34.40",
"lon":"135.37"
},
{
"code":"HISH",
"city":"Hiroshima",
"country":"JAPAN",
"lat":"34.3853",
"lon":"132.4553"
},
{
"code":"BKK",
"city":"BANGKOK",
"country":"THAILAND",
"lat":"13.75",
"lon":"100.48"
},
{
"code":"DEL",
"city":"DELHI",
"country":"INDIA",
"lat":"29.01",
"lon":"77.38"
},
{
"code":"SEA",
"city":"SEATTLE",
"country":"USA",
"lat":"38.680632",
"lon":"-96.5001"
}
];
var projection = d3.geo.mercator()
.center([0, 5 ])
.scale(200)
.rotate([-180,0]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var path = d3.geo.path()
.projection(projection);
var g = svg.append("g");
// load and display the World
d3.json("world-110m2.json", function(error, topology) {
// load and display the cities
function drawMap(data){
var circle = g.selectAll("circle")
.data(data)
.enter()
.append("g")
circle.append("circle")
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.attr("r", 5)
.style("fill", "red");
circle.append("image")
.attr("xlink:href", "http://fc08.deviantart.net/fs71/f/2013/354/8/7/blinking_smiley__animated__by_mondspeer-d6ylwn3.gif")//http://t2.gstatic.//com/images?q=tbn:ANd9GcT6fN48PEP2-z-JbutdhqfypsYdciYTAZEziHpBJZLAfM6rxqYX";})
.attr("class", "node")
.attr("x", function(d) {
return (projection([d.lon, d.lat])[0]) - 8;
})
.attr("y", function(d) {
return (projection([d.lon, d.lat])[1])-8;
})
.attr("width",20)
.attr("height",20)
//});
}
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries)
.geometries)
.enter()
.append("path")
.attr("d", path)
drawMap(data);
});
// zoom and pan
var zoom = d3.behavior.zoom()
.on("zoom",function() {
g.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
g.selectAll("circle")
.attr("d", path.projection(projection));
g.selectAll("path")
.attr("d", path.projection(projection));
});
svg.call(zoom)
</script>
</body>
</html>
Any body help me to zoom only map image not smiley
Implement semantic zooming :)
Try use this example to change your code :) :
Semantic zoom on map with circle showing capital
JSFIDDLE : http://jsfiddle.net/xf7222dg/2/
The code below shrinks the 'circles' depending on scale
var zoom = d3.behavior.zoom()
.on("zoom",function() {
g.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
g.selectAll("circle")
.attr("r", function(){
var self = d3.select(this);
var r = 8 / d3.event.scale; // set radius according to scale
self.style("stroke-width", r < 4 ? (r < 2 ? 0.5 : 1) : 2); // scale stroke-width
return r;
});
});
Here is it working with your smileys: http://jsfiddle.net/dmn0d11f/7/
You have to change the 'width' of the nodes (images) not the radius like with the circles. So select the nodes and instead of changing 'r' change 'width' :
g.selectAll(".node")
.attr("width", function(){
var self = d3.select(this);
var r = 28 / d3.event.scale; // set radius according to scale
self.style("stroke-width", r < 4 ? (r < 2 ? 0.5 : 1) : 2); // scale stroke-width
return r;
});