为了账号安全,请及时绑定邮箱和手机立即绑定

d3.js:图表外显示的网格线

d3.js:图表外显示的网格线

慕妹3146593 2023-08-24 09:58:50
我在图表中添加了一些网格线。现在我的问题是网格线与图表不对齐。另外,右侧图表末尾添加了最后一条网格线,是否有可能防止这种情况发生,并且仅向 x 轴上的每个标签添加一条线?我尝试以某种方式将网格线添加到剪辑路径,但它不起作用。我的网格线是这样创建的:<div id="minimap"></div><!-- In the original project these divs are not     static and get generated with v-for as many times as     i have a signal in signalData --><div id="signal1"></div><div id="signal2"></div><div id="signal3"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
查看完整描述

1 回答

?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

  1. 不要.append()updateChart. 你永远不会删除你绘制的轴,只需在它们上面绘制新的轴......

  2. 只需使用以下命令将现有的轴变成带有网格线的轴即可tickSizeInner()

var signalData = {

  signal1: {

    name: "signal1",

    data: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 1, 2, 3, 5, 4, 1, 4, 2, 9, 7, 5, 7, 4, 6],

  },

  signal2: {

    name: "signal2",

    data: [6, 4, 8, 5, 4, 8, 4, 3, 5, 4, 5, 8, 7, 2, 9, 5, 4, 1, 2, 6, 0, 5, 7, 1],

  },

  signal3: {

    name: "signal3",

    data: [9, 5, 12, 3, 8, 4, 8, 6, 3, 4, 7, 8, 5, 2, 1, 8, 6, 8, 5, 8, 4, 8, 5, 1],

  },

}



var margin = {

  top: 10,

  right: 50,

  bottom: 40,

  left: 50,

};

var width = window.innerWidth - margin.left - margin.right;

var height = 230 - margin.top - margin.bottom;

var minimapHeight = 150 - margin.top - margin.bottom;


var xScale = d3

  .scaleLinear()

  .domain([

    0,

    d3.max(Object.keys(signalData), (d) => signalData[d].data.length),

  ]) // input

  .range([0, width]); // output


var brushXScale = d3

  .scaleLinear()

  .domain([

    0,

    d3.max(Object.keys(signalData), (d) => signalData[d].data.length),

  ]) // input

  .range([0, width]); // output


var zoomBrush = d3

  .brushX()

  .extent([

    [0, 0],

    [width, minimapHeight],

  ])

  .on("brush", zoomBrushed)

  .on("end", function(event) {

    if (event.selection == null) {

      resetZoom();

    }

  });


var selectBrush = d3

  .brushX()

  .extent([

    [0, 0],

    [width, height],

  ])

  .on("brush", selectBrushed)

  .on("end", function(event) {

    if (event.selection == null) {

      resetSelection();

    }

  });


function resetZoom() {

  brushXScale.domain([

    0,

    d3.max(Object.keys(signalData), (d) => signalData[d].data.length),

  ]); // input


  for (var signal in signalData) {

    updateChart(signalData[signal].data, signalData[signal].name);

  }

}


function zoomBrushed() {

  var selectionPx = d3.brushSelection(this); // === [lower, upper] in pixels


  // transform from pixels to x-values

  var selectionX = [

    xScale.invert(selectionPx[0]),

    xScale.invert(selectionPx[1]),

  ];


  // set x scale domain, then redraw the lines

  brushXScale.domain(selectionX);


  for (var signal in signalData) {

    updateChart(signalData[signal].data, signalData[signal].name);

  }

}


function resetSelection() {

  selectBrush.on("end", null);

  d3.selectAll("div[id^=signal] svg .brushcontainer").call(

    selectBrush.clear

  );

  selectBrush.on("end", function(event) {

    if (event.selection == null) {

      resetSelection();

    }

  });

}


function selectBrushed() {

  var selectionPx = d3.brushSelection(this); // === [lower, upper] in pixels


  selectBrush.on("brush", null);

  d3.selectAll("div[id^=signal] svg .brushcontainer").call(

    selectBrush.move,

    selectionPx

  );

  selectBrush.on("brush", selectBrushed);

}


//Generate the brush focus chart

generateMinimap(signalData.signal1.data);

//Generate charts dynamically as often as i have signals

for (var signal in this.signalData) {

  generateChart(signalData[signal].data, signalData[signal].name);

}


// This function is for the one time preparations

function generateChart(data, name) {

  var svg = d3

    .select("#" + name)

    .append("svg")

    .attr("width", width + margin.left + margin.right)

    .attr("height", height + margin.top + margin.bottom)

    .append("g")

    .attr(

      "transform",

      "translate(" + margin.left + "," + margin.top + ")"

    );


  //clipPath to prevent path from overflow

  svg

    .append("defs")

    .append("clipPath")

    .attr("id", "clip")

    .append("rect")

    .attr("width", width)

    .attr("height", height);


  svg.append("g").attr("class", "brushcontainer").call(selectBrush);


  svg

    .append("g")

    .attr("class", "x axis")

    .attr("transform", "translate(0," + height + ")");


  svg.append("g").attr("class", "y axis");


  svg

    .append("path")

    .attr("clip-path", "url(#clip)")

    .attr("class", "line") // Assign a class for styling

    .attr("fill", "none")

    .attr("stroke", "blue");


  updateChart(data, name);

}


// This function needs to be called to update the already prepared chart

function updateChart(data, name) {

  var svg = d3.select("#" + name + " svg");


  var yScale = d3

    .scaleLinear()

    .domain([0, d3.max(data)]) // input

    .range([height, 0]); // output


  var line = d3

    .line()

    .x((d, i) => brushXScale(i))

    .y((d) => yScale(d));


  svg.select(".x.axis").call(

    d3.axisBottom(brushXScale)

      .tickSizeOuter(0)

      .tickSizeInner(-height)

  );


  svg.select(".y.axis").call(

    d3.axisLeft(yScale)

      .tickSizeInner(-width)

      .tickSizeOuter(0)

      .ticks(5)

  );


  svg

    .select(".line")

    .datum(data) // 10. Binds data to the line

    .attr("d", line); // 11. Calls the line generator

}


function generateMinimap(data) {

  var yScale = d3

    .scaleLinear()

    .domain([0, d3.max(data)]) // input

    .range([minimapHeight, 0]); // output


  var line = d3

    .line()

    .x((d, i) => xScale(i))

    .y((d) => yScale(d));


  var svg = d3

    .select("#minimap")

    .append("svg")

    .attr("width", width + margin.left + margin.right)

    .attr("height", minimapHeight + margin.top + margin.bottom)

    .append("g")

    .attr(

      "transform",

      "translate(" + margin.left + "," + margin.top + ")"

    );


  svg.append("g").call(zoomBrush);


  svg

    .append("g")

    .attr("class", "x axis")

    .attr("transform", "translate(0," + minimapHeight + ")")

    .call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom


  svg

    .append("path")

    .datum(data) // 10. Binds data to the line

    .attr("class", "line") // Assign a class for styling

    .attr("d", line) // 11. Calls the line generator

    .attr("fill-opacity", "0.17")

    .attr("fill", "blue")

    .attr("stroke", "blue");

}

.tick line {

  stroke-dasharray: 3 3;

}

<div id="minimap"></div>

<!-- In the original project these divs are not 

    static and get generated with v-for as many times as 

    i have a signal in signalData -->

<div id="signal1"></div>

<div id="signal2"></div>

<div id="signal3"></div>



<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>


查看完整回答
反对 回复 2023-08-24
  • 1 回答
  • 0 关注
  • 169 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信