javascript - ejemplo - getelementbyid properties
Obteniendo un mejor rendimiento en el método repetido en d3 (2)
Una característica subestimada de D3 es el concepto de variables locales que se introdujeron con la versión 4. Estas variables le permiten almacenar información en un nodo (esa es la razón por la que se llama local ) independientemente de los datos que podrían haberse vinculado a ese nodo. No tiene que hinchar sus datos para almacenar información adicional.
Los locales D3 le permiten definir el estado local independientemente de los datos.
Probablemente la mayor ventaja de usar variables locales sobre otros enfoques es el hecho de que encaja sin problemas en el enfoque clásico D3; no hay necesidad de introducir otro ciclo manteniendo el código limpio.
Usar variables locales para simplemente almacenar un valor precalculado es probablemente el caso de uso más simple que uno pueda imaginar. Por otro lado, ilustra perfectamente de qué se tratan las variables locales de D3: almacene información compleja, que puede requerir un gran esfuerzo de creación, localmente en un nodo, y recupérela para usarla más adelante en su código.
Copiando descaradamente y adaptando el código de la respuesta de Gerardo, la solución se puede implementar así:
var svg = d3.select("svg");
var data = d3.range(100, 1000, 100);
var roots = d3.local(); // This is the instance where our square roots will be stored
var ellipses = svg.selectAll(null)
.data(data)
.enter()
.append("ellipse")
.attr("fill", "gainsboro")
.attr("stroke", "darkslateblue")
.attr("cx", function(d) {
return roots.set(this, Math.sqrt(d)) * 3; // Calculate and store the square root
})
.attr("cy", function(d) {
return roots.get(this) * 3; // Retrieve the previously stored root
})
.attr("rx", function(d) {
return roots.get(this) + 3; // Retrieve the previously stored root
})
.attr("ry", function(d) {
return roots.get(this) + 4; // Retrieve the previously stored root
});
<script src="//d3js.org/d3.v4.min.js"></script>
<svg></svg>
Por ejemplo, necesito calcular un Math.sqrt de mis datos para cada attr, ¿cómo puedo calcular solo una vez el Math.sqrt (d)?
var circle = svgContainer.data(dataJson).append("ellipse")
.attr("cx", function(d) {
return Math.sqrt(d) + 1
})
.attr("cy", function(d) {
return Math.sqrt(d) + 2
})
.attr("rx", function(d) {
return Math.sqrt(d) + 3
})
.attr("ry", function(d) {
return Math.sqrt(d) + 4
});
Tiene algún modo elegante / performativo? Estoy pensando de esta manera:
var aux;
var circle = svgContainer.data(dataJson).append("ellipse")
.attr("cx", function(d) {
aux = Math.sqrt(d);
return aux + 1
})
.attr("cy", function(d) {
return aux + 2
})
.attr("rx", function(d) {
return aux + 3
})
.attr("ry", function(d) {
return aux + 4
});
Probablemente, la forma más idiomática de hacer esto en D3 es usar selection.each , que:
Invoca la función especificada para cada elemento seleccionado, en orden, pasando el dato actual (d), el índice actual (i) y el grupo actual (nodos), con esto como el elemento DOM actual (nodos [i]).
Entonces, en tu caso:
circle.each(function(d){
//calculates the value just once for each datum:
var squareRoot = Math.sqrt(d)
//now use that value in the DOM element, which is ''this'':
d3.select(this).attr("cx", squareRoot)
.attr("cy", squareRoot)
//etc...
});
Aquí hay una demostración:
var svg = d3.select("svg");
var data = d3.range(100, 1000, 100);
var ellipses = svg.selectAll(null)
.data(data)
.enter()
.append("ellipse")
.attr("fill", "gainsboro")
.attr("stroke", "darkslateblue")
.each(function(d) {
var squareRoot = Math.sqrt(d);
d3.select(this)
.attr("cx", function(d) {
return squareRoot * 3
})
.attr("cy", function(d) {
return squareRoot * 3
})
.attr("rx", function(d) {
return squareRoot + 3
})
.attr("ry", function(d) {
return squareRoot + 4
});
})
<script src="//d3js.org/d3.v4.min.js"></script>
<svg></svg>
Otro enfoque común en los códigos D3 es establecer una nueva propiedad de datos en el primer método attr
y recuperarlo más tarde:
.attr("cx", function(d) {
//set a new property here
d.squareRoot = Math.sqrt(d.value);
return d.squareRoot * 3
})
.attr("cy", function(d) {
//retrieve it here
return d.squareRoot * 3
})
//etc...
De esta forma, también realiza el cálculo solo una vez por elemento.
Aquí está la demostración:
var svg = d3.select("svg");
var data = d3.range(100, 1000, 100).map(function(d) {
return {
value: d
}
});
var ellipses = svg.selectAll(null)
.data(data)
.enter()
.append("ellipse")
.attr("fill", "gainsboro")
.attr("stroke", "darkslateblue")
.attr("cx", function(d) {
d.squareRoot = Math.sqrt(d.value);
return d.squareRoot * 3
})
.attr("cy", function(d) {
return d.squareRoot * 3
})
.attr("rx", function(d) {
return d.squareRoot + 3
})
.attr("ry", function(d) {
return d.squareRoot + 4
});
<script src="//d3js.org/d3.v4.min.js"></script>
<svg></svg>
PD : por cierto, su solución con var aux
no funcionará. Pruébalo y verás.