poderosamente (pero molesto) D3.js veces te obliga a repetir a sí mismo para visualizaciones simples. Si le dice que desea crear un elemento con atributos derivados de los datos de una determinada manera, y luego desea transferir esos atributos a nuevos datos, debe contarle nuevamente cómo derivar los valores (en caso de que desee) hacer algo diferente, como un diseño visual diferente). Como dice @Andrew, debes decirle qué hacer cuando transiciones.
Puede solucionar este 'problema' siguiendo este patrón:
var foo = d3.select('foo');
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar');
items.exit().remove();
items
.attr('foo',function(d){ return d });
}
En 2.0 cuando se append()
nuevos artículos en enter()
que se agregan automáticamente a la selección original enlazado a datos, por lo que las llamadas a attr()
y lo que luego se aplicará a ellos. Esto le permite usar el mismo código para establecer valores iniciales y actualizar valores.
Dado que no desea volver a crear el contenedor SVG en cada actualización, debe crearlo fuera de la función redraw
.
Si desea realizar transiciones:
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar')
.attr('opacity',0)
.attr('foo',initialPreAnimationValue);
items.exit().transition().duration(500)
.attr('opacity',0)
.remove();
items.transition.duration(500)
.attr('opacity',1)
.attr('foo',function(d){ return d });
}
Tenga en cuenta que los socios anteriores objetos con los datos de índice. Si desea eliminar un punto de datos intermedios para atenuar ese punto de datos antes de eliminarlo (en lugar de eliminar el último elemento y transformar cada otro elemento para que se parezca a ese), debe especificar un valor de cadena único (sin índice) para asociar cada artículo con:
var data = [
{id:1, c:'red', x:150},
{id:3, c:'#3cf', x:127},
{id:2, c:'green', x:240},
{id:4, c:'red', x:340}
];
myItems.data(data,function(d){ return d.id; });
Usted puede ver un ejemplo de esto y jugar con él en directo en my D3.js playground.
Primero, vea qué sucede cuando comenta una de las líneas de datos y luego vuelva a colocarla. A continuación, elimine el parámetro ƒ('id')
de la llamada al data()
en la línea 4 y vuelva a intentar comentar y en las líneas de datos.
Editar: Como alternativa, como se ha comentado por el mbostock ilustre, puede utilizar selection.call()
junto con una función reutilizable como una manera de secar su código:
var foo = d3.select('foo');
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar').call(setEmAll);
items.exit().remove();
items.call(setEmAll);
}
function setEmAll(myItems){
myItems
.attr('foo',function(d){ return d*2 })
.attr('bar',function(d){ return Math.sqrt(d)+17 });
}
Como puede observarse, .call()
invoca una función y pasa a lo largo de la selección como argumento, para que pueda realizar la misma configuración en su selección en múltiples ubicaciones.
Awesome answer, thanks. Todavía estoy tratando de entender la mayoría de estas cosas, ¡pero será una gran ayuda! – Richard
Respuesta reflexiva. También podría escribir su función 'redraw' de una manera que sea compatible con [selection.call] (https://github.com/mbostock/d3/wiki/Selections#wiki-call). Relacionado: [Towards Reusable Charts] (http://bost.ocks.org/mike/chart/). – mbostock
@mbostock Ooh, eso es muy útil; No había visto '.call()' antes. Solo soy un principiante de D3.js que ayuda donde puedo. Editaré para incluir esa información (y dar un pase completo a través de los documentos para tratar de incluir todas las posibilidades en mi cabeza). – Phrogz