为什么我的响应式 D3 图表上的某些网格线会随机消失? [英] Why are some of the grid lines randomly disappearing on my responsive D3 chart?

查看:24
本文介绍了为什么我的响应式 D3 图表上的某些网格线会随机消失?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为我的 D3 图表创建了一个精简的JSFiddle.我使用以下解决方案使其具有响应性(使用 viewbox 和 preserveaspectratio):响应式 D3 图表

I have created a stripped down JSFiddle of my D3 chart. I have made it responsive (with viewbox and preserveaspectratio) using the solution at: responsive D3 chart

当我调整窗口大小并使其变小时,一些网格线似乎消失并重新出现.我认为这在小分辨率下看起来很糟糕(例如 320x480 手机).当窗口变小时,有没有办法保留我的网格线?

When I resize the window and make it smaller, some of the grid lines seem to be disappearing and reappearing. I presume this will look bad at small resolutions (eg. 320x480 mobile phone). Is there a way to preserve my gridlines when the window gets resized smaller?

HTML 代码:

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

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;
}

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");

//}

推荐答案

这是一种混叠效果,因为线条的渲染方式受到各种因素的影响.其中主要的三个是笔画宽度、位置和渲染模式.对于使用 shape-rendering:crispEdges,SVG 规范声明:

That is an aliasing effect which will occur because the way the lines will get rendered is influenced by various factors. The main three of them being stroke width, position and rendering mode. For using shape-rendering: crispEdges the SVG spec states:

为了获得清晰的边缘,用户代理可能会关闭所有行的抗锯齿...

To achieve crisp edges, the user agent might turn off anti-aliasing for all lines...

根据线的缩放和平移,可以计算出它出现在两个屏幕像素之间,而缩放的笔划宽度不足以为任何一个像素着色那些相邻的屏幕像素.这样,线条似乎会随机消失并再次出现.

Depending on the scaling and the translation of the line it may be calculated to appear between two screen pixels while the scaled stroke width is not broad enough to color any of those adjacent screen pixels. That way the lines seem to randomly disappear and appear again.

进一步的解释可以在为什么 SVG stroke-width : 1 使线条透明?" 或我的 回答画了一条直线,但它是弯曲的 d3".

Further explanations can be found in "Why is SVG stroke-width : 1 making lines transparent?" or in my answer to "Drew a straight line, but it is crooked d3".

对于您的代码,您可以在绘制网格线时使用 shape-rendering:geometricPrecision 而不是 crispEdges 来更改渲染行为.查看更新的 JSFiddle 以获取工作示例.

For your code you can change the rendering behaviour by using shape-rendering: geometricPrecision instead of crispEdges when drawing the grid lines. Have a look at the updated JSFiddle for a working example.

这篇关于为什么我的响应式 D3 图表上的某些网格线会随机消失?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆