So I have this code that works fine for the format date:
formatDate(date){
var aux= utcParse("%Y-%m-%dT%H:%M:%S.%LZ")(date);
return aux;
};
The chart looks like this:
However in the x-axis, the whole datetime object is rendered. I just wanted to show the day and the month in this format "day/month".
This is what I tried:
formatDate(date){
var aux= utcParse("%Y-%m-%dT%H:%M:%S.%LZ")(date);
var formated = timeFormat("%d-%m")(aux);
return formated;
};
However when I do this the data does not render. Before it even raised an error.
Please note that I am using a time axis for x:
// Add X axis --> it is a date format
var x = scaleTime()
.domain(extent(data_render, function(d) { return d[0]; }))
.range([ 0, width ]);
This is the whole source code of the React component.
import React, { Component } from 'react';
import { scaleLinear, scaleBand, scaleTime, scaleOrdinal } from 'd3-scale';
import { select, selectAll, pointer} from 'd3-selection';
import { line, curveMonotoneX, area } from 'd3-shape';
import { extent, max } from 'd3-array';
import { transition} from 'd3-transition';
import { axisBottom, axisLeft,axisRight } from "d3-axis";
import { timeParse, timeFormat , utcParse} from 'd3-time-format';
export default class MyLineChart extends Component {
constructor(props)
{
super(props);
this.state={"isLoaded":false, "circleHover":false};
this.lineRef = React.createRef();
this.formatDate=this.formatDate.bind(this);
this.circleTooltip=this.circleTooltip.bind(this);
}
circleTooltip(circle){
circle
.append("text")
.text("circle")
}
formatDate(date){
var aux= utcParse("%Y-%m-%dT%H:%M:%S.%LZ")(date);
//var formated = timeFormat("%d-%m")(aux);
//console.log(formated);
return aux;
//return timeFormat("%d-%m")(utcParse("%Y-%m-%dT%H:%M:%S.%LZ")(date));
};
componentDidMount(){
const node = this.lineRef.current;
const { data, title, aggr} = this.props;
var data_render = [];
data.segments.forEach(
(obj) => {
data_render.push([this.formatDate(obj.end), obj[title][aggr]]);
}
)
console.log(data_render);
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = select(node)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Add X axis --> it is a date format
var x = scaleTime()
.domain(extent(data_render, function(d) { return d[0]; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(axisBottom(x));
// Add Y axis
var y = scaleLinear()
.domain([0, max(data_render, function(d) { return d[1]; })])
.range([ height, 0 ]).nice();
svg.append("g")
.attr("transform", "translate("+0+",0)")
.call(axisRight(y));
//Add the area
svg.append("path")
.datum(data_render)
.attr("fill", "#69b3a2")
.attr("fill-opacity", .3)
.attr("stroke", "none")
.attr("d", area()
.x(function(d) { return x(d[0]) })
.y0( height )
.y1(function(d) { return y(d[1]) }).curve(curveMonotoneX)
)
// Add the line
svg.append("path")
.datum(data_render)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line()
.x(function(d) { return x(d[0]) })
.y(function(d) { return y(d[1]) }).curve(curveMonotoneX)
)
// Add the circles
svg.selectAll("myCircles")
.data(data_render)
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) { return x(d[0]) })
.attr("cy", function(d) { return y(d[1]) })
.attr("r", 5).style("opacity",1)
svg.selectAll("myText")
.data(data_render)
.enter()
.append("text")
.attr("x", function(d){return x(d[0])})
.attr("y", function(d){return y(d[1])})
.text(function(d){return d[0]+' '+d[1]})
.style("font-size","6px")
.style("opacity",1);
//Add the title
svg.append("text")
.attr("x", width/2)
.attr("y", margin.top)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text(title);
this.setState({...this.state, isLoaded:true})
}
render() {
return (
<div>
<svg className="lineChart" ref={this.lineRef} />
</div>
);
}
}
How can I format the axis to just show the day and the month in the x-axis?
You want the values in data_render, like d[0], to be Date objects, which is what utcParse("%Y-%m-%dT%H:%M:%S.%LZ")(date) returns.
Then for your axis, you want something like d3.axisBottom(x).tickFormat(d3.timeFormat("%d-%m")).
Related
I am newbie in d3js, I do not know why all labels in the bar are wrong.
My code and captures are shown as below, then you can see that all labels are different from my data.
Anyone know what's going on in my text label section?
// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 40, left: 50 },
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
const dataUrl = "https://raw.githubusercontent.com/yushinglui/IV/main/time_distance_status_v2.csv"
//fetch the data
d3.csv(dataUrl)
.then((data) => {
// append the svg object to the body of the page
var svg = d3.select("#graph-2")
.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 + ")")
// List of subgroups = header of the csv files = soil condition here
var subgroups = data.columns.slice(1)
// List of groups = species here = value of the first column called group -> I show them on the X axis
var groups = d3.map(data, function (d) { return (d.startTime) })
// Add X axis
var x = d3.scaleBand()
.domain(groups)
.range([0, width])
.padding([0.2])
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickSize(0));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 20])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Another scale for subgroup position?
var xSubgroup = d3.scaleBand()
.domain(subgroups)
.range([0, x.bandwidth()])
.padding([0.05])
// color palette = one color per subgroup
var color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#98abc5', '#8a89a6'])
// Show the bars
svg.append("g")
.selectAll("g")
// Enter in data = loop group per group
.data(data)
.enter()
.append("g")
.attr("transform", function (d) { return "translate(" + x(d.startTime) + ",0)"; })
.selectAll("rect")
.data(function (d) { return subgroups.map(function (key) { return { key: key, value: d[key] }; }); })
.enter()
.append("rect")
.attr("x", function (d) { return xSubgroup(d.key); })
.attr("y", function (d) { return y(d.value); })
.attr("width", xSubgroup.bandwidth())
.attr("height", function (d) { return height - y(d.value); })
.attr("fill", function (d) { return color(d.key); })
// mouseover and mouseout animation
.on("mouseover", function (d) {
d3.select(this).style("fill", d3.rgb(color(d.key)).darker(2))
})
.on("mouseout", function (d) {
d3.select(this).style("fill", function (d) { return color(d.key); })
})
//axis labels
svg.append('text')
.attr('x', - (height / 2))
.attr('y', width - 650)
.attr('transform', 'rotate(-90)')
.attr('text-anchor', 'middle')
.style("font-size", "17px")
.text('Average Distance');
svg.append('text')
.attr('x', 300)
.attr('y', width - 240)
.attr('transform', 'rotate()')
.attr('text-anchor', 'middle')
.style("font-size", "17px")
.text('Start Time');
// legend
svg.append("circle").attr("cx", 200).attr("cy", 20).attr("r", 6).style("fill", "#98abc5")
svg.append("circle").attr("cx", 300).attr("cy", 20).attr("r", 6).style("fill", "#8a89a6")
svg.append("text").attr("x", 220).attr("y", 20).text("Present").style("font-size", "15px").attr("alignment-baseline", "middle")
svg.append("text").attr("x", 320).attr("y", 20).text("Absent").style("font-size", "15px").attr("alignment-baseline", "middle")
//text labels on bars -- all labels wrong!!
svg.append("g")
.selectAll("g")
// Enter in data = loop group per group
.data(data)
.enter()
.append("g")
.attr("transform", function (d) { return "translate(" + x(d.startTime) + ",0)"; })
.selectAll("text")
.data(function (d) { return subgroups.map(function (key) { return { key: key, value: d[key] }; }); })
.enter()
.append("text")
.text(function (d) { return y(d.value); })
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", function (d) { return xSubgroup(d.key); })
.attr("y", function (d) { return y(d.value) + 10; })
});
My reference website:
http://plnkr.co/edit/9lAiAXwet1bCOYL58lWN?p=preview&preview
https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad
Your issue is that when you're appending the text, you inadvertently called the y function, which is used to get the y-location on where to insert the text. The numbers you're getting are actually y-location values, which seems completely random.
.text(function (d) { return y(d.value); }) // here is the issue
Change it to
.text(function (d) { return d.value; })
and it should work!
I am creating a chart using d3 js and I was trying to convert a DateTime string to time. but it is returning TypeError: Cannot read property 'timeFormat' of undefined
The bellow is the full file that Created.
import {BaseElement} from '../../core/base-element';
import {utilsMixin} from '../../core/mixins/utils-mixin';
// import {LitElement} from 'lit-element';
import * as d3 from 'd3';
export const AreaChartBase = class extends utilsMixin(dataSourceMixin(BaseElement)) {
constructor() {
super();
this.title = '';
this.chartTheme = {
margin : {
top: 35,
right: 145,
bottom: 35,
left: 45
},
barsColors : '#23d160',
tickColor : '#aeaeae',
pathColor : '#aeaeae',
gridColor : '#aeaeae',
barTitleColor : "#23d160",
}
}
static get is() {
return 'area-chart';
}
static get properties() {
return {
title: String,
chartTheme: Object,
}
}
timeFormat(str){
const dateTimeString = new Date(str);
const time = dateTimeString.getTime();
const normalTime = new Date(time).toLocaleDateString("en-US");
return normalTime;
}
areaChart(selector, props, data){
// initialize the variables
const {
margin,
width,
height,
barsColors,
tickColor,
pathColor,
gridColor,
barTitleColor
} = props;
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const svg = d3.select(selector);
let chart = svg.selectAll('svg')
.data([null]);
chart = chart.enter()
.append('svg')
.merge(svg)
// .attr('width', innerWidth)
// .attr('height', innerHeight);
.attr('viewBox', `0,0, ${innerWidth}, ${innerHeight}`)
chart.append('text')
.attr('x', 0)
.attr('y', margin.top / 2)
.attr('text-anchor', 'start')
.style('font-size', '18px')
.attr('fill', '#4c6072')
.text('Area chart');
let g = chart.selectAll('g').data([null]);
g = g.enter()
.append('g')
.merge(g)
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// Add X axis --> it is a date format
const x = d3.scaleBand()
.rangeRound([0, innerWidth])
.padding(0.1);
const y = d3.scaleLinear()
.range([innerHeight - margin.bottom - 17, 0]);
x.domain(data.map(function (d) {
console.log(this.timeFormat(d[0]));
return this.timeFormat(d[0]);
}));
y.domain( d3.extent(data, function(d) { return +d[4]; }) );
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y)
.ticks(5)
.tickSizeInner(-innerWidth)
.tickSizeOuter(0)
.tickPadding(10);
let xAxisG = g.selectAll('.x axis').data([null]);
xAxisG = xAxisG.enter()
.append('g')
.attr('class', 'x axis')
.merge(xAxisG)
.attr('transform', `translate(0, ${innerHeight - margin.bottom - 17})`)
let yAxisG = g.selectAll('y axis').data([null]);
yAxisG = yAxisG.enter()
.append('g')
.attr('class', 'y axis')
.merge(yAxisG)
xAxisG.call(xAxis);
xAxisG.selectAll('.tick text')
.attr('fill', tickColor)
xAxisG.selectAll('.tick line')
.attr('stroke', pathColor);
xAxisG.select('.domain')
.attr('stroke', 'transparent');
yAxisG.call(yAxis);
yAxisG.selectAll('.tick text')
.attr('fill', tickColor)
yAxisG.selectAll('.tick line')
.attr('stroke', pathColor);
yAxisG.select('.domain')
.attr('stroke', 'transparent');
// append the svg object to the body of the page
// let svg = d3.select(selector)
// .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 + ")");
// const x = d3.scaleBand()
// .domain(data.map(function (d) {
// return d[0];
// }))
// .range([ 0, width ]);
// svg.append("g")
// .attr("transform", "translate(0," + (height+5) + ")")
// .call(d3.axisBottom(x).ticks(5).tickSizeOuter(0));
// // Add Y axis
// var y = d3.scaleLinear()
// .domain( d3.extent(data, function(d) { return +d[4]; }) )
// .range([ height, 0 ]);
// svg.append("g")
// .attr("transform", "translate(-5,0)")
// .call(d3.axisLeft(y).tickSizeOuter(0));
// Add the area
svg.append("path")
.datum(data)
.attr("fill", "#69b3a2")
.attr("fill-opacity", .3)
.attr("stroke", "none")
.attr("d", d3.area()
.x(function(d) { return x(d[0]) })
.y0( height )
.y1(function(d) { return y(+d[4]) })
)
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 2)
.attr("d", d3.line()
.x(function(d) { return x(d[0]) })
.y(function(d) { return y(+d[4]) })
)
// Add the line
svg.selectAll("myCircles")
.data(data)
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) { return x(d[0]) })
.attr("cy", function(d) { return y(parseInt(d[4])) })
.attr("r", 2)
}
initAreaChart(dsc){
const rows = dsc.rows;
const data = dsc.data;
const cont = this.qs('#chart');
this.areaChart(cont, Object.assign({}, this.chartTheme, {
width: this.qs('#container').clientWidth,
height: 400,
}), rows);
}
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties);
let self = this;
this.loader.then(dsc => {
self.initAreaChart(dsc);
});
}
dscDataName() {
return this.e.defaultValue;
}
init(pElement, loader) {
super.init(pElement, loader);
var self = this;
self.loader = this.loadData();
}
}```
if you guys can help me find a fix for the above error I will appreciate it. Thanks in advance
Try to use arrow function. Arrow functions keep context.
x.domain(data.map( (d) => {
console.log(this.timeFormat(d[0]));
return this.timeFormat(d[0]);
}));
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
I am trying to update some bar graphs when a button is clicked.
Here's the button
<button className="login_buttons" onClick={this.setRecommendations}>
Click to See Top Tracks and Recommendations
</button>
it calls this function, which does successfully update all the states, and right now the graph displays dummy data just fine.
setRecommendations(){
getAlbums().then(albums =>{
this.setState({topAlbums: albums[0]});
this.setState({album_count: albums[1]});
});
getArtists().then(artists =>{
this.setState({topArtist: artists[0]});
this.setState({artist_count: artists[1]});
});
getGenres().then(genres =>{
this.setState({topGenre: genres[0]});
this.setState({genre_count: genres[1]});
});
popularityData().then(popData =>{
this.setState({popRange: popData[0]});
this.setState({pop_count: popData[1]});
});
recommendations().then(recs => {
this.setState({recommendations: recs});
});
}
and here's my Graph component
import React from 'react';
import * as d3 from "d3";
class Graphs extends React.Component {
componentDidMount() {
this.drawChart();
}
componentDidUpdate() {
d3.select(`#${this.props.graphID}`).remove()
this.drawChart();
}
drawChart() {
const data = this.props.data;
const labels = this.props.axisLabels;
const title = this.props.title;
const margins = {top:50, right:50, bottom:50, left:50}
const h = 600 - margins.top - margins.bottom;
const w = 600 - margins.right - margins.left;
var x = d3.scaleBand()
.range([0, w])
.domain(labels);
var y = d3.scaleLinear()
.range([h, 0])
.domain([0, d3.max(data)]);
const svg = d3.select(`#${this.props.graphID}`)
.append("svg")
.attr("width", w + margins.right + margins.left)
.attr("height", h + margins.top + margins.bottom)
.append("g")
.attr("transform", `translate(${margins.left}, ${margins.top})`);
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("y", (d) => y(d))
.attr("x", (d, i) => (x.bandwidth()*i + 10))
.attr("height", (d) => h - y(d))
.attr("width", x.bandwidth() - 10)
.attr("fill", "blue");
svg.append("g")
.attr("transform", `translate(0, ${h})`)
.call(d3.axisBottom(x))
svg.append("g")
.call(d3.axisLeft(y));
svg.append("text")
.attr("x", (w/2))
.attr("y", 0 - (margins.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("fill", "white")
.style("text-decoration", "underline")
.text(title);
}
render(){
return <div id={this.props.graphID} />
}
}
export default Graphs
And when I click the button, the Graphs that have dummy data in them now do actually disappear so componentsWillUpdate is called but it is not redrawing the graphs, and I do not understand why because compnentsDoMount calls this.drawChart() alright.
Don't remove the container:
d3.select(`#${this.props.graphID}`).remove()
Remove what's in it:
d3.select(`#${this.props.graphID}`).selectAll('*').remove()
I'm making a line chart in React using D3, and I'm trying to show a tooltip when hovering inside the chart with data from the current data point. The chart renders correctly, but as soon as I'm hovering inside it, I get the error node.getBoundingClientRect is not a function.
I'm following this example, which doesn't use React, so could it have something to do with how react handle things?
This is what my component looks like:
class LineChart extends Component {
wrapper = React.createRef();
componentDidMount() {
const {data} = this.props
let svg = d3.select("body svg.mySvg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
const parseTime = d3.timeParse("%Y")
const bisectDate = d3.bisector(function(d) { return d.year; }).left;
const x = d3.scaleTime().range([0, width]);
const y = d3.scaleLinear().range([height, 0]);
const line = d3.line()
.x(function(d) { return x(d.year); })
.y(function(d) { return y(d.value); });
let g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function(d) {
d.year = parseTime(d.year);
d.value = +d.value;
});
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.style("color", "#fff")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.style("color", "#fff")
.call(d3.axisLeft(y).ticks(7).tickFormat(function(d) { return d; }))
g.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
let focus = g.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 7.5);
focus.append("text")
.attr("x", 15)
.attr("dy", ".31em");
svg.append("rect")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", () => {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.year > d1.year - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
focus.select("text").text(function() { return d.value; });
focus.select(".x-hover-line").attr("y2", height - y(d.value));
focus.select(".y-hover-line").attr("x2", width + width);
});
}
render() {
const { width, height } = this.props
return (
<svg innerRef={ this.wrapper } height={ height } width={ width } className="mySvg"></svg>
)
}
}
I render the LineChart component inside a parent component like this:
<LineChart
width={ 1000 }
height={ 350 }
margin={ 50 }
data={[
{ year: 2011, value: 3 },
{ year: 2012, value: 20 },
{ year: 2013, value: 2 },
{ year: 2014, value: 12 },
{ year: 2015, value: 8 },
{ year: 2016, value: 14 },
{ year: 2017, value: 8 }
]}
/>
The error:
The problem is in the .on("mousemove", () => {}) line. You are using a fat arrow function, which does not have its own this, effectively using the upper scope this instead. When using "classic" function definition (as you do for "mouseover"), this keeps the correct value for this (the node which was the target of "mousemove").
svg.append("rect")
...
.on("mousemove", function () {
// this is the node which was target of "mouseover" event
})
I set up a demo.
I am drawing charts with d3 4.2.2 in my Angular2 project. I created a multi series line chart and added zoom and drag properties. Now the chart is zooming on mouse scroll event but it zoom only X-axis and Y-axis. And it can be dragged only X-axis & Y-axis but chart cannot be dragged. When I do zooming or dragging those events are applying only to the two axis es but not for the chart. Following is what I am doing with my code.
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var zoom = d3.zoom()
.scaleExtent([1, 5])
.translateExtent([[0, -100], [width + 90, height + 100]])
.on("zoom", zoomed);
var svg = d3.select(this.htmlElement).append("svg")
.attr("class", "line-graph")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("pointer-events", "all")
.call(zoom);
var view = svg.append("rect")
.attr("class", "view")
.attr("x", 0.5)
.attr("y", 0.5)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("fill", "#EEEEEE")
.style("stroke", "#000")
.style("stroke-width", "0px");
// parse the date / time
var parseDate = d3.timeParse("%Y-%m-%d");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
// define the line
var line = d3.line()
.x( (d) => {
return x(d.date);
})
.y( (d) => {
return y(d.lookbookcount);
});
z.domain(d3.keys(data[0]).filter(function (key) {
return key !== "date";
}));
// format the data
data.forEach( (d)=> {
d.date = parseDate(d.date);
});
var lookBookData = z.domain().map(function (name) {
return {
name: name,
values: data.map( (d) => {
return {date: d.date, lookbookcount: d[name], name: name};
})
};
});
x.domain(d3.extent(data, (d) => {
return d.date;
}));
y.domain([
d3.min([0]),
d3.max(lookBookData, (c) => {
return d3.max(c.values,
(d) => {
return d.lookbookcount;
});
})
]);
z.domain(lookBookData.map( (c) => {
return c.name;
}));
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
.tickFormat(d3.timeFormat("%d/%m"));
var yAxis = d3.axisLeft(y)
.ticks(10);
// Add the X Axis
var gX = svg.append("g")
.style("font", "14px open-sans")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
var gY = svg.append("g")
.style("font", "14px open-sans")
.attr("class", "axis axis--x")
.call(yAxis)
.style("cursor", "ns-resize");
// Add Axis labels
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.text("Sales / Searches");
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("dx", ".71em")
.attr("transform", "translate(" + width + "," + (height +
(margin.bottom)) + ")")
.text("Departure Date");
var chartdata = svg.selectAll(".chartdata")
.data(lookBookData)
.enter().append("g")
.attr("class", "chartdata");
chartdata.append("path")
.classed("line", true)
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("fill", "none")
.style("stroke", function (d) {
return z(d.name);
})
.style("stroke-width", "2px");
chartdata.append("text")
.datum(function (d) {
return {
name: d.name, value: d.values[d.values.length - 1]
};
})
.attr("transform", function (d) {
return "translate(" +
x(d.value.date) + "," + y(d.value.lookbookcount) + ")";
})
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "14px open-sans")
.text(function (d) {
return d.name;
});
// add the dots with tooltips
chartdata.selectAll(".circle")
.data(function (d) {
return d.values;
})
.enter().append("circle")
.attr("class", "circle")
.attr("r", 4)
.attr("cx", function (d) {
console.log(d);
return x(d.date);
})
.attr("cy", function (d) {
return y(d.lookbookcount);
})
.style("fill", function (d) { // Add the colours dynamically
return z(d.name);
});
function zoomed() {
view.attr("transform", d3.event.transform);
gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
}
function resetted() {
svg.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity);
}
Any suggestions would be highly appreciated.
Thank you