I have some rookie question. I am trying to rescale scatter plot elements (circles along with X axis) based on button click - to create 'zoom in' activity. I am lowering X axis domain for that.
It works very well with Xaxis, however its harder with circles. I must remove all of them and draw them again (the place marked in the code). This makes the process slow when lot of elements involved and also doesn't allow transition which is applied for axis scaling.
Is it possible just to change attributes of circles that i won't need to remove and redraw everything again?
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
// Define Canvas size
var width = 500;
var height = 500;
// Generate Toy Data
var randomX = d3.randomUniform(0, 880);
var randomY = d3.randomUniform(0, 800);
data_x = [];
data_y = [];
for (i = 0; i < 10000; i++) {
nume = Math.floor((Math.random() * 100));
data_x.push(nume);
data_y.push(nume);
}
// Scaling Coeffs
var coeffX = 1;
var coeffY = 1;
var coeffR = 1;
var coordX = (Math.max.apply(null, data_x)/coeffX);
var coordy = (Math.max.apply(null, data_y)/coeffY);
var x = d3.scaleLinear()
.domain([0, coordX])
.range([ 0, width]).nice();
var y = d3.scaleLinear()
.domain([0, coordy])
.range([height, 0]).nice();
var yAxis = d3.axisLeft(y).ticks(5);
var xAxis = d3.axisBottom(x).ticks(5)
//Create SVG element
var canvas = d3.select("body")
.append("svg")
.attr("width", width+50)
.attr("height", height+50)
.append("g");
// --------------- Draw Elements ---------------------
var circles = canvas.selectAll("circlepoint")
.data(data_x)
.enter()
.append("g");
circles.append("circle")
.attr("cx",function(d, i){
var tempe = data_x[i];
return x(tempe);
})
.attr("cy", function(d, i){
var tempe = data_y[i];
return y(tempe);
})
.attr("r", function(){
return 3;
})
.style("stroke", "steelblue")
.style("fill", "none")
.attr("transform", "translate(40, -20)");
var xsCont = canvas.append("g")
.attr("transform", "translate(40, " + (height-20) +")")
.attr("class","xaxis")
.call(xAxis);
var ysCont = canvas.append("g")
.attr("transform", "translate(40, -20)")
.call(yAxis);
function rescaleAxisX(tempCoeffX, tempCoeffR){
coordX = (Math.max.apply(null, data_x)/tempCoeffX);
x.domain([0, Math.max.apply(null, data_x)/tempCoeffX])
// -------- This part works well-------
canvas.select(".xaxis")
.transition().duration(750)
.call(xAxis);
// -------- End -------------
// -------- This one doesn't as expected-------
circles.remove();
circles = canvas.selectAll("circlepoint")
.data(data_x)
.enter()
.append("g");
circles.append("circle")
.attr("cx",function(d, i){
var tempe = data_x[i];
return x(tempe);
})
.attr("cy", function(d, i){
var tempe = data_y[i];
return y(tempe);
})
.attr("r", function(d, i){
return tempCoeffR;
})
.style("stroke", "steelblue")
.style("fill", "none")
.attr("transform", "translate(40, -20)");
}
// -------- End -------
// Zoom in button
var buttonZoomPlusX = d3.select("body")
.append("input")
.attr("type","button")
.attr("class","button")
.attr("value", "+")
.on("click", function(){
coeffX = coeffX + 1;
coeffR = coeffR + 1;
rescaleAxisX(coeffX, coeffR);
})
</script>
</body>
</html>
Here is implemented Fiddle https://jsfiddle.net/sma76ntq/
Thanks a lot in advance
Well it was rookie mistake as always. Two things were missing: 1. Appending some class to circles in order not too select everything on canvas if there were more circles drawn
circles.append("circle")
.attr("cx",function(d, i){
var tempe = data_x[i];
return x(tempe);
})
.attr("cy", function(d, i){
var tempe = data_y[i];
return y(tempe);
//return y(d.y);
})
.attr("r", function(){
return 3;
})
.attr("class","eles")
.style("stroke", "steelblue")
.style("fill", "none")
.attr("transform", "translate(40, -20)");
on redrawn just select classes and change attributes.
canvas.selectAll(".eles").data(data_x)
.transition()
.duration(750)
.attr("cx",function(d, i){
var tempe = data_x[i];
return x(tempe);
})
.attr("cy", function(d, i){
var tempe = data_y[i];
return y(tempe);
});
Working Fiddle here: https://jsfiddle.net/v7q14nbm/1/