d3 exit selection comes up empty even with unique id value
I'm trying to make my own version of a spinning globe with markers, similar to Patrick Stotz' here. Though my goal is not cities, I'm using that for now and have a smaller version of this geoJSON file for data (with the same structure). The problem is I clearly don't understand how to correctly get an exit selection because it's always empty, even though I've updated the geoJSON file to have a unique id for each feature.
The main difference I'm trying to introduce is to plot 100 cities at a time, then remove those markers and plot the next 100 with some simple transition effects. I do this with a d3.timer
function and slicing the data array.
The problem is my exit
selection is always empty, even after I've added a unique id following the advice from this question.
Here's the first part of the js that setups the global variables, the globe and countries (very similar to Patrick's original):
var width = 820;
var height = 620;
var rScale = d3.scale.sqrt();
var amountPerPixel = 12500;
var max_population = ;
var index = 0;
// Configuration for the spinning effect
var time = Date.now();
var rotate = [0, 0];
var velocity = [0.025, -0];
// set projection type and paremetes
var projection = d3.geo.orthographic()
.scale(300)
.translate([(width / 2) + 100, height / 2])
.clipAngle(90)
.precision(0.3);
// create path variable, empty svg element and group container
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("svg");
var g = svg.append("g");
// drawing dark grey spehere as landmass
g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path)
.attr("fill", "#0D0D0D");
var countries = svg.append("g").selectAll("path.countries");
var cities = svg.append("g").selectAll("path.cities");
// draw country lines
d3.json("countries.geojson", function(error, data) {
countries.data(data.features)
.enter().append("path")
.attr("class", "countries")
.attr("d", path)
});
The following three functions load the cities data, handle some basic functions like a scale for size and radius, plot the initial data and spin the globe (also similar to Patrick's original with some changes):
d3.json("cities.geojson", function(error, data) {
// Handle errors getting and parsing the data
if (error) { console.log(error); return error; }
// setting the circle size (not radius!) according to the number of inhabitants per city
amount_array = ;
for (i = 0; i < data.features.length; i++) {
data.features[i].properties.id = i;
amount_array.push(data.features[i].properties.population);
}
max_amount = amount_array.sort(d3.descending)[0]
var rMin = 0;
var rMax = Math.sqrt(max_amount / (amountPerPixel * Math.PI));
rScale.domain([0, max_amount]);
rScale.range([rMin, rMax]);
path.pointRadius(function(d) {
return d.properties ? rScale(d.properties.population) : 1;
});
initialData = data.features.slice(index,index+100);
// Drawing transparent circle markers for cities
cities.data(initialData, function(d) { return d.properties.id; })
.enter().append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
// start spinning!
spinning_globe();
// update new data points
update_points(data);
});
function update_points(data) {
d3.timer(function() {
index += 100;
newData = data.features.slice(index,index+100)
var newCities = cities.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
newCities.exit().remove();
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
if(newData.length == 0) stop();
}, 1000);
};
function spinning_globe(){
d3.timer(function() {
// get current time
var dt = Date.now() - time;
// get the new position from modified projection function
projection.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);
// update cities position = redraw
svg.selectAll("path.countries").attr("d",path);
svg.selectAll("path.cities").attr("d", path);
});
};
I've tried a brute force method for removing the current city markers (svg.selectAll("path.cities").remove()
) but the timing doesn't work out right.
The end result is that everything works right -- the glob spins, the cities light up -- but no cities are ever removed. What am I doing wrong?
javascript d3.js data-visualization
add a comment |
I'm trying to make my own version of a spinning globe with markers, similar to Patrick Stotz' here. Though my goal is not cities, I'm using that for now and have a smaller version of this geoJSON file for data (with the same structure). The problem is I clearly don't understand how to correctly get an exit selection because it's always empty, even though I've updated the geoJSON file to have a unique id for each feature.
The main difference I'm trying to introduce is to plot 100 cities at a time, then remove those markers and plot the next 100 with some simple transition effects. I do this with a d3.timer
function and slicing the data array.
The problem is my exit
selection is always empty, even after I've added a unique id following the advice from this question.
Here's the first part of the js that setups the global variables, the globe and countries (very similar to Patrick's original):
var width = 820;
var height = 620;
var rScale = d3.scale.sqrt();
var amountPerPixel = 12500;
var max_population = ;
var index = 0;
// Configuration for the spinning effect
var time = Date.now();
var rotate = [0, 0];
var velocity = [0.025, -0];
// set projection type and paremetes
var projection = d3.geo.orthographic()
.scale(300)
.translate([(width / 2) + 100, height / 2])
.clipAngle(90)
.precision(0.3);
// create path variable, empty svg element and group container
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("svg");
var g = svg.append("g");
// drawing dark grey spehere as landmass
g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path)
.attr("fill", "#0D0D0D");
var countries = svg.append("g").selectAll("path.countries");
var cities = svg.append("g").selectAll("path.cities");
// draw country lines
d3.json("countries.geojson", function(error, data) {
countries.data(data.features)
.enter().append("path")
.attr("class", "countries")
.attr("d", path)
});
The following three functions load the cities data, handle some basic functions like a scale for size and radius, plot the initial data and spin the globe (also similar to Patrick's original with some changes):
d3.json("cities.geojson", function(error, data) {
// Handle errors getting and parsing the data
if (error) { console.log(error); return error; }
// setting the circle size (not radius!) according to the number of inhabitants per city
amount_array = ;
for (i = 0; i < data.features.length; i++) {
data.features[i].properties.id = i;
amount_array.push(data.features[i].properties.population);
}
max_amount = amount_array.sort(d3.descending)[0]
var rMin = 0;
var rMax = Math.sqrt(max_amount / (amountPerPixel * Math.PI));
rScale.domain([0, max_amount]);
rScale.range([rMin, rMax]);
path.pointRadius(function(d) {
return d.properties ? rScale(d.properties.population) : 1;
});
initialData = data.features.slice(index,index+100);
// Drawing transparent circle markers for cities
cities.data(initialData, function(d) { return d.properties.id; })
.enter().append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
// start spinning!
spinning_globe();
// update new data points
update_points(data);
});
function update_points(data) {
d3.timer(function() {
index += 100;
newData = data.features.slice(index,index+100)
var newCities = cities.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
newCities.exit().remove();
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
if(newData.length == 0) stop();
}, 1000);
};
function spinning_globe(){
d3.timer(function() {
// get current time
var dt = Date.now() - time;
// get the new position from modified projection function
projection.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);
// update cities position = redraw
svg.selectAll("path.countries").attr("d",path);
svg.selectAll("path.cities").attr("d", path);
});
};
I've tried a brute force method for removing the current city markers (svg.selectAll("path.cities").remove()
) but the timing doesn't work out right.
The end result is that everything works right -- the glob spins, the cities light up -- but no cities are ever removed. What am I doing wrong?
javascript d3.js data-visualization
1
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59
add a comment |
I'm trying to make my own version of a spinning globe with markers, similar to Patrick Stotz' here. Though my goal is not cities, I'm using that for now and have a smaller version of this geoJSON file for data (with the same structure). The problem is I clearly don't understand how to correctly get an exit selection because it's always empty, even though I've updated the geoJSON file to have a unique id for each feature.
The main difference I'm trying to introduce is to plot 100 cities at a time, then remove those markers and plot the next 100 with some simple transition effects. I do this with a d3.timer
function and slicing the data array.
The problem is my exit
selection is always empty, even after I've added a unique id following the advice from this question.
Here's the first part of the js that setups the global variables, the globe and countries (very similar to Patrick's original):
var width = 820;
var height = 620;
var rScale = d3.scale.sqrt();
var amountPerPixel = 12500;
var max_population = ;
var index = 0;
// Configuration for the spinning effect
var time = Date.now();
var rotate = [0, 0];
var velocity = [0.025, -0];
// set projection type and paremetes
var projection = d3.geo.orthographic()
.scale(300)
.translate([(width / 2) + 100, height / 2])
.clipAngle(90)
.precision(0.3);
// create path variable, empty svg element and group container
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("svg");
var g = svg.append("g");
// drawing dark grey spehere as landmass
g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path)
.attr("fill", "#0D0D0D");
var countries = svg.append("g").selectAll("path.countries");
var cities = svg.append("g").selectAll("path.cities");
// draw country lines
d3.json("countries.geojson", function(error, data) {
countries.data(data.features)
.enter().append("path")
.attr("class", "countries")
.attr("d", path)
});
The following three functions load the cities data, handle some basic functions like a scale for size and radius, plot the initial data and spin the globe (also similar to Patrick's original with some changes):
d3.json("cities.geojson", function(error, data) {
// Handle errors getting and parsing the data
if (error) { console.log(error); return error; }
// setting the circle size (not radius!) according to the number of inhabitants per city
amount_array = ;
for (i = 0; i < data.features.length; i++) {
data.features[i].properties.id = i;
amount_array.push(data.features[i].properties.population);
}
max_amount = amount_array.sort(d3.descending)[0]
var rMin = 0;
var rMax = Math.sqrt(max_amount / (amountPerPixel * Math.PI));
rScale.domain([0, max_amount]);
rScale.range([rMin, rMax]);
path.pointRadius(function(d) {
return d.properties ? rScale(d.properties.population) : 1;
});
initialData = data.features.slice(index,index+100);
// Drawing transparent circle markers for cities
cities.data(initialData, function(d) { return d.properties.id; })
.enter().append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
// start spinning!
spinning_globe();
// update new data points
update_points(data);
});
function update_points(data) {
d3.timer(function() {
index += 100;
newData = data.features.slice(index,index+100)
var newCities = cities.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
newCities.exit().remove();
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
if(newData.length == 0) stop();
}, 1000);
};
function spinning_globe(){
d3.timer(function() {
// get current time
var dt = Date.now() - time;
// get the new position from modified projection function
projection.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);
// update cities position = redraw
svg.selectAll("path.countries").attr("d",path);
svg.selectAll("path.cities").attr("d", path);
});
};
I've tried a brute force method for removing the current city markers (svg.selectAll("path.cities").remove()
) but the timing doesn't work out right.
The end result is that everything works right -- the glob spins, the cities light up -- but no cities are ever removed. What am I doing wrong?
javascript d3.js data-visualization
I'm trying to make my own version of a spinning globe with markers, similar to Patrick Stotz' here. Though my goal is not cities, I'm using that for now and have a smaller version of this geoJSON file for data (with the same structure). The problem is I clearly don't understand how to correctly get an exit selection because it's always empty, even though I've updated the geoJSON file to have a unique id for each feature.
The main difference I'm trying to introduce is to plot 100 cities at a time, then remove those markers and plot the next 100 with some simple transition effects. I do this with a d3.timer
function and slicing the data array.
The problem is my exit
selection is always empty, even after I've added a unique id following the advice from this question.
Here's the first part of the js that setups the global variables, the globe and countries (very similar to Patrick's original):
var width = 820;
var height = 620;
var rScale = d3.scale.sqrt();
var amountPerPixel = 12500;
var max_population = ;
var index = 0;
// Configuration for the spinning effect
var time = Date.now();
var rotate = [0, 0];
var velocity = [0.025, -0];
// set projection type and paremetes
var projection = d3.geo.orthographic()
.scale(300)
.translate([(width / 2) + 100, height / 2])
.clipAngle(90)
.precision(0.3);
// create path variable, empty svg element and group container
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("svg");
var g = svg.append("g");
// drawing dark grey spehere as landmass
g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path)
.attr("fill", "#0D0D0D");
var countries = svg.append("g").selectAll("path.countries");
var cities = svg.append("g").selectAll("path.cities");
// draw country lines
d3.json("countries.geojson", function(error, data) {
countries.data(data.features)
.enter().append("path")
.attr("class", "countries")
.attr("d", path)
});
The following three functions load the cities data, handle some basic functions like a scale for size and radius, plot the initial data and spin the globe (also similar to Patrick's original with some changes):
d3.json("cities.geojson", function(error, data) {
// Handle errors getting and parsing the data
if (error) { console.log(error); return error; }
// setting the circle size (not radius!) according to the number of inhabitants per city
amount_array = ;
for (i = 0; i < data.features.length; i++) {
data.features[i].properties.id = i;
amount_array.push(data.features[i].properties.population);
}
max_amount = amount_array.sort(d3.descending)[0]
var rMin = 0;
var rMax = Math.sqrt(max_amount / (amountPerPixel * Math.PI));
rScale.domain([0, max_amount]);
rScale.range([rMin, rMax]);
path.pointRadius(function(d) {
return d.properties ? rScale(d.properties.population) : 1;
});
initialData = data.features.slice(index,index+100);
// Drawing transparent circle markers for cities
cities.data(initialData, function(d) { return d.properties.id; })
.enter().append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
// start spinning!
spinning_globe();
// update new data points
update_points(data);
});
function update_points(data) {
d3.timer(function() {
index += 100;
newData = data.features.slice(index,index+100)
var newCities = cities.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
newCities.exit().remove();
svg.selectAll("path.cities").transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
if(newData.length == 0) stop();
}, 1000);
};
function spinning_globe(){
d3.timer(function() {
// get current time
var dt = Date.now() - time;
// get the new position from modified projection function
projection.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);
// update cities position = redraw
svg.selectAll("path.countries").attr("d",path);
svg.selectAll("path.cities").attr("d", path);
});
};
I've tried a brute force method for removing the current city markers (svg.selectAll("path.cities").remove()
) but the timing doesn't work out right.
The end result is that everything works right -- the glob spins, the cities light up -- but no cities are ever removed. What am I doing wrong?
javascript d3.js data-visualization
javascript d3.js data-visualization
asked Nov 22 at 17:27
tchaymore
1,825123878
1,825123878
1
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59
add a comment |
1
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59
1
1
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59
add a comment |
2 Answers
2
active
oldest
votes
Perhaps the problem is that you do not reassign cities
variable after update. If my understanding is correct, the first time update_points
is called, everything should go as expected. But when it will be called the second time, cities
selection still refers to the first 100 cities, which have been deleted.
The solution is to assign cities = newCities.enter()...
.
The idiomatic way is to assign cities = newCities.enter() .... .merge(newCities) ...
, but is is not required in your case, since the next 100 cities do not intersect previous cities and update section is empty.
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
add a comment |
you want to work with changing selections and bind data so do not keep record of the (now) "old" selection.
// init
var cities = svg.append("g");
// init-draw
cities.selectAll(".cities")
.data(initialData, function(d) { return d.properties.id; })
.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
// update
var newCities = cities.selectAll(".cities")
.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1)
.merge(newCities);
.transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();
The init-draw and the update are near identical so combine them into one, call the update for the init-draw.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53435839%2fd3-exit-selection-comes-up-empty-even-with-unique-id-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Perhaps the problem is that you do not reassign cities
variable after update. If my understanding is correct, the first time update_points
is called, everything should go as expected. But when it will be called the second time, cities
selection still refers to the first 100 cities, which have been deleted.
The solution is to assign cities = newCities.enter()...
.
The idiomatic way is to assign cities = newCities.enter() .... .merge(newCities) ...
, but is is not required in your case, since the next 100 cities do not intersect previous cities and update section is empty.
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
add a comment |
Perhaps the problem is that you do not reassign cities
variable after update. If my understanding is correct, the first time update_points
is called, everything should go as expected. But when it will be called the second time, cities
selection still refers to the first 100 cities, which have been deleted.
The solution is to assign cities = newCities.enter()...
.
The idiomatic way is to assign cities = newCities.enter() .... .merge(newCities) ...
, but is is not required in your case, since the next 100 cities do not intersect previous cities and update section is empty.
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
add a comment |
Perhaps the problem is that you do not reassign cities
variable after update. If my understanding is correct, the first time update_points
is called, everything should go as expected. But when it will be called the second time, cities
selection still refers to the first 100 cities, which have been deleted.
The solution is to assign cities = newCities.enter()...
.
The idiomatic way is to assign cities = newCities.enter() .... .merge(newCities) ...
, but is is not required in your case, since the next 100 cities do not intersect previous cities and update section is empty.
Perhaps the problem is that you do not reassign cities
variable after update. If my understanding is correct, the first time update_points
is called, everything should go as expected. But when it will be called the second time, cities
selection still refers to the first 100 cities, which have been deleted.
The solution is to assign cities = newCities.enter()...
.
The idiomatic way is to assign cities = newCities.enter() .... .merge(newCities) ...
, but is is not required in your case, since the next 100 cities do not intersect previous cities and update section is empty.
answered Nov 22 at 17:46
Yaroslav Sergienko
40016
40016
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
add a comment |
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
This is great, helped a lot. I've got the selections to exit now, and it also helped switching to d3.interval(). Now I just need to get the transitions to work correctly. Thanks!
– tchaymore
Nov 22 at 20:35
add a comment |
you want to work with changing selections and bind data so do not keep record of the (now) "old" selection.
// init
var cities = svg.append("g");
// init-draw
cities.selectAll(".cities")
.data(initialData, function(d) { return d.properties.id; })
.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
// update
var newCities = cities.selectAll(".cities")
.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1)
.merge(newCities);
.transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();
The init-draw and the update are near identical so combine them into one, call the update for the init-draw.
add a comment |
you want to work with changing selections and bind data so do not keep record of the (now) "old" selection.
// init
var cities = svg.append("g");
// init-draw
cities.selectAll(".cities")
.data(initialData, function(d) { return d.properties.id; })
.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
// update
var newCities = cities.selectAll(".cities")
.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1)
.merge(newCities);
.transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();
The init-draw and the update are near identical so combine them into one, call the update for the init-draw.
add a comment |
you want to work with changing selections and bind data so do not keep record of the (now) "old" selection.
// init
var cities = svg.append("g");
// init-draw
cities.selectAll(".cities")
.data(initialData, function(d) { return d.properties.id; })
.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
// update
var newCities = cities.selectAll(".cities")
.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1)
.merge(newCities);
.transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();
The init-draw and the update are near identical so combine them into one, call the update for the init-draw.
you want to work with changing selections and bind data so do not keep record of the (now) "old" selection.
// init
var cities = svg.append("g");
// init-draw
cities.selectAll(".cities")
.data(initialData, function(d) { return d.properties.id; })
.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1);
// update
var newCities = cities.selectAll(".cities")
.data(newData, function(d) { return d.properties.id; });
newCities.enter()
.append("path")
.attr("id", function(d) {return d.properties.id;})
.attr("class", "cities")
.attr("d", path)
.attr("fill", "#ffba00")
.attr("fill-opacity", 0.1)
.merge(newCities);
.transition()
.duration(250)
.ease("quad")
.attr("fill-opacity", 0.75);
newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();
The init-draw and the update are near identical so combine them into one, call the update for the init-draw.
answered Nov 22 at 21:34
rioV8
4,0112311
4,0112311
add a comment |
add a comment |
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53435839%2fd3-exit-selection-comes-up-empty-even-with-unique-id-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
Exit collection is empty if you dont have enough DOM nodes to bind your data to to begin with. If you selection has 20 nodes, your data has 10 elements, exit collection will have 10 nodes, if your selection has 10 nodes, your data has 20 nodes, exit collection will be empty
– Almost Handsome
Nov 22 at 17:59