graphs framework examples d3.js svg responsive aliasing

d3.js - framework - install d3



¿Por qué algunas de las líneas de la cuadrícula desaparecen de forma aleatoria en mi carta receptiva D3? (1)

Creé un JSFiddle simplificado de mi gráfico D3. Lo hice receptivo (con viewbox y preserveaspectratio) usando la solución en: gráfico D3 receptivo

Cuando cambio el tamaño de la ventana y la hago más pequeña, algunas de las líneas de la grilla parecen desaparecer y reaparecer. Supongo que esto se verá mal en resoluciones pequeñas (por ejemplo, teléfono móvil 320x480). ¿Hay alguna forma de preservar mis líneas de cuadrícula cuando la ventana se vuelve más pequeña?

Código HTML:

<!--//d3 chart//--> <div class="centre-div"></div>

Código CSS:

.centre-div { margin: 0 auto; max-width: 550px; } /* D3 chart css */ .axis path, .axis line { fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 11px; }

Código JS:

//function createScatterplot() { //Width and height var margin = { top: 15, right: 2, bottom: 2, left: 2 }; //define width and height as the inner dimensions of the chart area. var width = 550 - margin.left - margin.right; var height = 550 - margin.top - margin.bottom; var padding = 10; //define svg as a G element that translates the origin to the top-left corner of the chart area. //add <svg> to the last <div class="centre-div"> tag on the html page //this allows me to reuse the createScatterplot() function to draw multiple charts var svg = d3.select(d3.selectAll(".centre-div")[0].pop()).append("svg") //.attr("width", width + margin.left + margin.right) //.attr("height", height + margin.top + margin.bottom) //make svg responsive .attr("width", "100%") .attr("height", "100%") .attr("viewBox", "0 0 550 550") .attr("preserveAspectRatio", "xMidYMid meet") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //With this convention, all subsequent code can ignore margins. //http://bl.ocks.org/mbostock/3019563 //Static dataset var dataset = [ [5, -2, "A"], [-4, -9, "B"], [2, 5, "C"], [1, -3, "D"], [-3, 5, "E"], [4, 1, "F"], [4, 4, "G"], [5, 7, "H"], [-5, -2, "I"], [0, 8, "J"], [-6, -5, "K"] ]; //Create scale functions var xScale = d3.scale.linear() .domain([-10, 11]) .range([padding, width - padding * 2]); var yScale = d3.scale.linear() .domain([-10, 11]) .range([height - padding, padding]); //different scale for gridlines, so last tick has no line var xScale2 = d3.scale.linear() .domain([-10, 10]) .range([padding, width - padding * 2]); var yScale2 = d3.scale.linear() .domain([-10, 10]) .range([height - padding, padding]); //add arrowheads defs = svg.append("defs") defs.append("marker") .attr({ "id": "arrow", "viewBox": "-5 -5 10 10", "refX": 0, "refY": 0, "markerWidth": 7, //marker size "markerHeight": 7, //marker size "orient": "auto" }) .append("path") .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z") .attr("fill", "#000"); //Define X axis var xAxis = d3.svg.axis() .scale(xScale) .orient("bottom") .ticks(22) //Define Y axis var yAxis = d3.svg.axis() .scale(yScale) .orient("left") .ticks(22) //create scatterplot crosses svg.selectAll("line.diag1") .data(dataset) .enter() .append("line") .attr({ "class": "diag1", "x1": function(d) { return xScale(d[0]) - 4; }, "y1": function(d) { return yScale(d[1]) - 4; }, "x2": function(d) { return xScale(d[0]) + 4; }, "y2": function(d) { return yScale(d[1]) + 4; }, "stroke": "#006CCA", "opacity": "1", "stroke-width": "2px" }); svg.selectAll("line.diag2") .data(dataset) .enter() .append("line") .attr({ "class": "diag2", "x1": function(d) { return xScale(d[0]) + 4; }, "y1": function(d) { return yScale(d[1]) - 4; }, "x2": function(d) { return xScale(d[0]) - 4; }, "y2": function(d) { return yScale(d[1]) + 4; }, "stroke": "#006CCA", "opacity": "1", "stroke-width": "2px" }); //Create X axis svg.append("g") .attr("class", "axis") .style("stroke-width", 2) .attr("transform", "translate(0," + 11 * (height) / 21 + ")") .call(xAxis) //add x label .append("text") .attr("class", "label") .attr("x", width) .attr("y", 15) .attr("font-style", "italic") .attr("font-weight", "bold") .style("text-anchor", "end") .text("x"); //Create Y axis svg.append("g") .attr("class", "axis") .style("stroke-width", 2) .attr("transform", "translate(" + 10 * (width - padding) / 21 + ",0)") .call(yAxis) //add y label .append("text") .attr("class", "label") .attr("x", -10) .attr("y", -5) .attr("font-style", "italic") .attr("font-weight", "bold") .style("text-anchor", "end") .text("y"); //add arrowheads to axis ends //add line on top of x-axis and arrowhead svg.append("line") .attr({ "x1": 0, "y1": 11 * height / 21, "x2": width - padding * 1.5, "y2": 11 * height / 21, "stroke": "black", "stroke-width": "2px", "marker-end": "url(#arrow)" }); //add line on top of y-axis and arrowhead svg.append("line") .attr({ "x1": 10 * (width - padding) / 21, "y1": height, "x2": 10 * (width - padding) / 21, "y2": 0.4 * padding, "stroke": "black", "stroke-width": "2px", "marker-end": "url(#arrow)" }); //Assuming that you have Mike Bostock''s standard margins defined and you have defined a linear scale for the y-axis the following code will create horizontal gridlines without using tickSize(). //https://stackoverflow.com/questions/15580300/proper-way-to-draw-gridlines //create horizontal grid lines var gridwidth = 19 * width / 20; var gridheight = 19 * height / 20; svg.selectAll("line.horizontalGrid").data(yScale2.ticks(20)).enter() .append("line") .attr({ "class": "horizontalGrid", "x1": 0, "x2": gridwidth, "y1": function(d) { return yScale(d); }, "y2": function(d) { return yScale(d); }, "fill": "none", "shape-rendering": "crispEdges", "stroke": "black", "stroke-width": "1px", "opacity": "0.3" }); //create vertical gridlines svg.selectAll("line.verticalGrid").data(xScale2.ticks(20)).enter() .append("line") .attr({ "class": "verticalGrid", "y1": height - gridheight, "y2": height, "x1": function(d) { return xScale(d); }, "x2": function(d) { return xScale(d); }, "fill": "none", "shape-rendering": "crispEdges", "stroke": "black", "stroke-width": "1px", "opacity": "0.3" }); //remove last ticks and zero ticks svg.selectAll(".tick") .filter(function(d) { return d === 11; }) .remove(); svg.selectAll(".tick") .filter(function(d) { return d === 0; }) .remove(); //add a custom origin identifier svg.append("text") .attr({ "class": "origintext", "x": 455 * width / 1000, "y": 552 * height / 1000, "text-anchor": "end", "font-size": "65%" }) .text("0"); //add labels to points plotted svg.selectAll("textlabels") .data(dataset) .enter() .append("text") .text(function(d) { return d[2]; }) .attr("x", function(d) { return xScale(d[0]) + 5; }) .attr("y", function(d) { return yScale(d[1]) - 5; }) .attr("font-weight", "bold") .attr("font-size", "12px") .attr("fill", "black"); //}


Ese es un efecto de aliasing que ocurrirá porque la manera en que se renderizarán las líneas está influenciada por varios factores. Los tres principales son el ancho de carrera, la posición y el modo de representación. Para usar shape-rendering: crispEdges los estados de especificación SVG:

Para lograr bordes nítidos, el agente de usuario puede desactivar el anti-aliasing para todas las líneas ...

Dependiendo de la escala y la traducción de la línea, puede calcularse que aparezca entre dos píxeles de pantalla, mientras que el ancho de trazo escalado no es lo suficientemente amplio como para colorear cualquiera de esos píxeles de pantalla adyacentes. De esa manera las líneas parecen desaparecer al azar y aparecer de nuevo.

Se pueden encontrar explicaciones adicionales en "¿Por qué SVG stroke-width: 1 hace que las líneas sean transparentes?" o en mi respuesta a "dibujó una línea recta, pero está torcido d3" .

Para su código, puede cambiar el comportamiento de la representación mediante la representación de shape-rendering: geometricPrecision lugar de crispEdges al dibujar las líneas de la cuadrícula. Echa un vistazo al JSFiddle actualizado para ver un ejemplo de trabajo.