简体   繁体   中英

tickValues() in d3.js

I am building my chart the next way: see Fiddle

const margin = { top: 19, right: 16, bottom: 29, left: 16 };
const width = 800 - margin.left - margin.right;
const height = 96 - margin.top - margin.bottom;

const parseDate = d3.timeParse("%Y-%m-%d");
const formatTime = d3.timeFormat("%d.%m");

const x = d3.scaleTime().range([0, width]);
const y = d3.scaleLinear().range([height - 5, 0]);

var xAxis = d3.axisBottom(x)
      .tickFormat(function (d) {
        //console.log(d)
        return formatTime(d);
}).ticks(ticksNumber);

var yAxis = d3.axisLeft(y);

//establish the domain for x and y axes
x.domain(d3.extent(data, function (d) { return d.date; }));
y.domain(d3.extent(data, function (d) { return d.health; }));

var axisNode = svg.append('g')
    .attr('class', 'x-axis')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);

But I can`t understand couple of things:

  • As you can see on there is no data on 17.03 and 18.03 (it was weekends), so is there a way not to show the tick on xAxis if there is no data? I mean xAxis ticks should be ...15.03-16.03-19.03-20.03... No 17 and 18 on March.

    X axis tick values should be date in format DD.MM and only those which is represented in data array.

    Another words if I have 10 elements in my data array so 10 ticks should be (now 12 ticks). I think than I should use tickValues() not ticks() , but totally do not understand how to implement it in right way.

  • Also I got some date filters. And I also need to know is there a way to make next:

    All time we saw eg month chart (in jsfiddle case dates from 12.03 to 23.03), the line which connect points is green. If we "filter" eg last week (19-25 of March) - filter I mean we pass to function which build chart startDate like 19-03-2018 and endDate 25-03-2018), so on the chart this segment from 19.03 to 23.03 becomes eg red. Something like 在此处输入图片说明

I forked and adjusted your fiddle . My edits aren't perfect, but I think they answer your questions and put you on the right track.

Another words if I have 10 elements in my data array so 10 ticks should be (now 12 ticks). I think than I should use tickValues() not ticks(), but totally do not understand how to implement it in right way.

Yep! You were on the right track. tickValues() will let you specify the exact ticks.

const tickValuesForAxis = data.map(d => parseDate(d.date));

var xAxis = d3.axisBottom(x)
    .tickValues(tickValuesForAxis)
    .tickFormat(function (d) {
        return formatTime(d);
    });

Also I got some date filters. And I also need to know is there a way to make next:

All time we saw eg month chart (in jsfiddle case dates from 12.03 to 23.03), the line which connect points is green. If we "filter" eg last week (19-25 of March) - filter I mean we pass to function which build chart startDate like 19-03-2018 and endDate 25-03-2018), so on the chart this segment from 19.03 to 23.03 becomes eg red. Something like

I took a hint from this previously asked question . The basic idea here is to create separate lines, each filtered to the data you want it to be colored for.

The implementation in my forked fiddle just gives you an idea of what can be done. I think you can make it much more dynamic.

const splitDate = data[6].date;

svg.append("path")
        .attr("d", line(data.filter(d => d.date <= splitDate )))
        .attr("stroke",'#35b37e')
        .attr("stroke-width", 2)
        .attr("fill", "none");

svg.append("path")
        .attr("d", line(data.filter(d => d.date >= splitDate )))
        .attr("stroke", "red")
        .attr("stroke-width", 2)
        .attr("fill", "none");

Full JS:

let data = [
  {"date": "2018-03-12", "health": 93, "risks": 10, "incidents": 0},
  {"date": "2018-03-13", "health": 80, "risks": 5, "incidents": 2},
  {"date": "2018-03-14", "health": 40, "risks": 1, "incidents": 5},
  {"date": "2018-03-15", "health": 90, "risks": 5, "incidents": 6},
  {"date": "2018-03-16", "health": 12, "risks": 12, "incidents": 7},
  {"date": "2018-03-19", "health": 100, "risks": 11, "incidents": 1},
  {"date": "2018-03-20", "health": 93, "risks": 8, "incidents": 5},
  {"date": "2018-03-21", "health": 64, "risks": 9, "incidents": 6},
  {"date": "2018-03-22", "health": 55, "risks": 7, "incidents": 12},
  {"date": "2018-03-23", "health": 100, "risks": 9, "incidents": 12},
]

const ticksNumber = data.length;
var tickValues = data.map(function (d) { return moment(d.date, 'YYYY-MM-DD').format('DD.MM'); });

const margin = { top: 19, right: 16, bottom: 29, left: 16 };
const width = 800 - margin.left - margin.right;
const height = 96 - margin.top - margin.bottom;

const parseDate = d3.timeParse("%Y-%m-%d");
const formatTime = d3.timeFormat("%d.%m");

const tickValuesForAxis = data.map(d => parseDate(d.date));

const x = d3.scaleTime().range([0, width]);
const y = d3.scaleLinear().range([height - 5, 0]);

var xAxis = d3.axisBottom(x)
    .tickValues(tickValuesForAxis)
    .tickFormat(function (d) {
        return formatTime(d);
    });

var yAxis = d3.axisLeft(y);

let line = d3.line()
      .x(function (d) { return x(d.date); })
      .y(function (d) { return y(d.health); })
      .curve(d3.curveCardinal);

// gridlines in x axis function
function make_x_gridlines() {
      return d3.axisBottom(x)
        .ticks(ticksNumber)
}

let svg = d3.select('#viz')
      .append('svg')
      .attr('height', height + margin.top + margin.bottom)
      .append('g')
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    data.forEach(function (d) {
      d.date = parseDate(d.date);
});

//establish the domain for x and y axes
x.domain(d3.extent(data, function (d) { return d.date; }));
y.domain(d3.extent(data, function (d) { return d.health; }));

var axisNode = svg.append('g')
    .attr('class', 'x-axis')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);

axisNode.selectAll('text').each(function () {
      if (this.textContent && !tickValues.includes(this.textContent)) {
        this.classList.add("day-off");
      }
});

// add the X gridlines
svg.append("g")
    .attr("class", "grid")
    .attr('stroke', '#d2e3ed')
    .attr('stroke-opacity', 0.1)
    .attr("transform", "translate(-0.5," + height + ")")
    .call(
      make_x_gridlines()
        .tickSize(-height)
        .tickFormat("")
);


// Define the div for the tooltip
var div = d3.select('body').append("div")
      .attr("class", "tooltip")
      .style("opacity", 1)
      .style("box-shadow", "0 0 0 1px rgba(204, 204, 204, 0.24)");

/*  svg.append('path').datum(data)
      .attr('class', 'line')
      .attr('d', line)
      .attr('stroke', '#35b37e')
      .attr('stroke-width', '2')
      .attr('fill', 'none'); */

const splitDate = data[6].date;

svg.append("path")
        .attr("d", line(data.filter(d => d.date <= splitDate )))
        .attr("stroke",'#35b37e')
        .attr("stroke-width", 2)
        .attr("fill", "none");

svg.append("path")
        .attr("d", line(data.filter(d => d.date >= splitDate )))
        .attr("stroke", "red")
        .attr("stroke-width", 2)
        .attr("fill", "none");

 svg.selectAll("dot")
      .data(data)
      .enter().append("circle")
      .attr("r", 4)
      .attr('stroke', '#35b37e')
      .attr('stroke-width', '2')
      .attr('fill', '#f7f8f9')
      .attr("cx", function (d) { return x(d.date); })
      .attr("cy", function (d) { return y(d.health); })
      .on("mouseover", handleMouseOver)
      .on("mouseout", handleMouseOut)
      .style("opacity", 0);

    function handleMouseOver(d, i) {
      d3.select(this).style("opacity", 1);
      div.transition()
        .duration(200)
        .style("opacity", .9);
      div.html(moment(d.date).format("DD MMM YYYY") + "<br/>" +
        "Health: " + d.health + "<br/>" +
        "Risks: " + d.risks + "<br/>" +
        "Incidents: " + d.incidents)
        .style("left", (d3.event.pageX - 60) + "px")
        .style("top", (d3.event.pageY - 115) + "px");
    }

    function handleMouseOut(d, i) {
      d3.select(this).style("opacity", 0);
      div.transition()
        .duration(500)
        .style("opacity", 0);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM