Вот мое сокращение:
var CreateChart = (function() {
var chtChartConstrictor = document.getElementById("chtChartConstrictor");
var myChart;
var drawChart = function(options) {
// Set dimensions and margins of the graph
var margin = {
top: 20,
right: 0,
bottom: 0,
left: 0,
};
var chtChartConstrictorMetrics = chtChartConstrictor.getBoundingClientRect();
var width = chtChartConstrictorMetrics.width;
var height = chtChartConstrictorMetrics.height;
var parseTime = d3.timeParse("%Y-%m-%d");
var formatTime = d3.timeFormat("%Y-%m-%d");
// format the data
options.line1.forEach(function(d) {
d.date = parseTime(d.date);
d.close = +d.close;
});
// parse the date / time
if (options.chartType === "line") {
// set the ranges
let x = d3.scaleTime().range([0, width]).domain(
d3.extent(options.line1, function(d) {
return d.date;
})
);
let y = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]).domain([
0,
d3.max(options.line1, function(d) {
return d.close;
}),
]);
// define the area
var area = d3
.area()
.x(function(d) {
return x(d.date);
})
.y0(height)
.y1(function(d) {
return y(d.close);
});
// define the line
var valueline = d3
.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
var svg = d3
.select("#chtChartConstrictor")
.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 + ")");
svg.append("path").attr("class", "cht-LineChart_Line").attr("d", valueline(options.line1));
// add the area
svg.append("path").data(options.line1).attr("class", "cht-LineChart_Fill").attr("d", area(options.line1));
// add the X Axis
svg.append("g").attr("class", "cht-LineChart_XAxis").attr("transform", "translate(0," + (height - 40) + ")").call(customXAxis);
function customXAxis(g) {
g.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%Y-%m-%d")));
g.select(".domain").remove();
g.selectAll("line").remove();
g.selectAll("text").attr("class", "cht-LineChart_XAxisNumber");
}
// add the Y Axis
svg.append("g").attr("class", "cht-LineChart_YAxis").attr("transform", "translate(-5,0)").call(customYAxis);
function customYAxis(g) {
g.call(d3.axisRight(y));
g.select(".domain").remove();
g.selectAll("line").remove();
g.select(".cht-LineChart_YAxis text:first-of-type").remove();
g.selectAll("text").attr("class", "cht-LineChart_YAxisNumber");
}
// Gridline
var gridlines = d3.axisLeft().tickFormat("").tickSize(-width).scale(y);
svg.append("g").attr("class", "cht-LineChart_GridLineContainer").call(gridlines);
svg.selectAll(".cht-LineChart_GridLineContainer line").attr("class", "cht-LineChart_GridLine");
// Tidy up the generation by removing the text and path as we don't use them
svg.selectAll(".cht-LineChart_GridLineContainer text").remove();
svg.selectAll(".cht-LineChart_GridLineContainer path").remove();
}
};
var destroyChart = function() {};
var publicAPI = {
DrawChart: drawChart,
DestroyChart: destroyChart,
};
return publicAPI;
})();
CreateChart.DrawChart({
chartType: "line",
line1: [
{ date: "2016-12-25", close: 43 },
{ date: "2016-12-26", close: 57 },
{ date: "2016-12-27", close: 55 },
{ date: "2016-12-28", close: 44 },
{ date: "2016-12-29", close: 45 },
{ date: "2016-12-30", close: 30 },
{ date: "2016-12-31", close: 36 },
],
line2: [],
});
#chtChartConstrictor {
height: 320px;
width: 100%;
}
.cht-LineChart_Line {
fill: transparent;
stroke: #f90;
stroke-width: 2px;
}
.cht-LineChart_Fill {
fill: rgba(73,255,255,.5);
}
.cht-LineChart_GridLine {
stroke-dasharray: 4px 4px;
stroke: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<div id="chtChartConstrictor"></div>
Я не могу понять, почему я получаю несколько повторяющихся тиков (дат) на оси X? Может ли кто-нибудь отправить меня на правильный путь? Я бы хотел отметить тик для каждого из точек данных и ничего больше.
В D3 ось, построенная с использованием шкалы времени, автоматически генерирует свои тики. То есть генератор оси решает, сколько тиков он будет создавать: они не соответствуют точкам данных.
При этом тики, которые вы видите, не дублируются: они фактически соответствуют разным моментам времени... однако, поскольку некоторые из них принадлежат к одному дню, эти тики, похоже, дублируются. Но это не так.
Есть несколько способов исправить это. Один из самых простых - использовать tickValues
(как вы предлагаете в заголовке вопроса), чтобы передавать только даты в вашем массиве данных:
.tickValues(options.line1.map(function(d){
return d.date
}))
Вот ваш код с этим изменением:
var CreateChart = (function() {
var chtChartConstrictor = document.getElementById("chtChartConstrictor");
var myChart;
var drawChart = function(options) {
// Set dimensions and margins of the graph
var margin = {
top: 20,
right: 0,
bottom: 0,
left: 0,
};
var chtChartConstrictorMetrics = chtChartConstrictor.getBoundingClientRect();
var width = chtChartConstrictorMetrics.width;
var height = chtChartConstrictorMetrics.height;
var parseTime = d3.timeParse("%Y-%m-%d");
var formatTime = d3.timeFormat("%Y-%m-%d");
// format the data
options.line1.forEach(function(d) {
d.date = parseTime(d.date);
d.close = +d.close;
});
// parse the date / time
if (options.chartType === "line") {
// set the ranges
let x = d3.scaleTime().range([0, width]).domain(
d3.extent(options.line1, function(d) {
return d.date;
})
);
let y = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]).domain([
0,
d3.max(options.line1, function(d) {
return d.close;
}),
]);
// define the area
var area = d3
.area()
.x(function(d) {
return x(d.date);
})
.y0(height)
.y1(function(d) {
return y(d.close);
});
// define the line
var valueline = d3
.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
var svg = d3
.select("#chtChartConstrictor")
.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 + ")");
svg.append("path").attr("class", "cht-LineChart_Line").attr("d", valueline(options.line1));
// add the area
svg.append("path").data(options.line1).attr("class", "cht-LineChart_Fill").attr("d", area(options.line1));
// add the X Axis
svg.append("g").attr("class", "cht-LineChart_XAxis").attr("transform", "translate(0," + (height - 40) + ")").call(customXAxis);
function customXAxis(g) {
g.call(d3.axisBottom(x)
.tickValues(options.line1.map(function(d){return d.date}))
.tickFormat(d3.timeFormat("%Y-%m-%d")));
g.select(".domain").remove();
g.selectAll("line").remove();
g.selectAll("text").attr("class", "cht-LineChart_XAxisNumber");
}
// add the Y Axis
svg.append("g").attr("class", "cht-LineChart_YAxis").attr("transform", "translate(-5,0)").call(customYAxis);
function customYAxis(g) {
g.call(d3.axisRight(y));
g.select(".domain").remove();
g.selectAll("line").remove();
g.select(".cht-LineChart_YAxis text:first-of-type").remove();
g.selectAll("text").attr("class", "cht-LineChart_YAxisNumber");
}
// Gridline
var gridlines = d3.axisLeft().tickFormat("").tickSize(-width).scale(y);
svg.append("g").attr("class", "cht-LineChart_GridLineContainer").call(gridlines);
svg.selectAll(".cht-LineChart_GridLineContainer line").attr("class", "cht-LineChart_GridLine");
// Tidy up the generation by removing the text and path as we don't use them
svg.selectAll(".cht-LineChart_GridLineContainer text").remove();
svg.selectAll(".cht-LineChart_GridLineContainer path").remove();
}
};
var destroyChart = function() {};
var publicAPI = {
DrawChart: drawChart,
DestroyChart: destroyChart,
};
return publicAPI;
})();
CreateChart.DrawChart({
chartType: "line",
line1: [
{ date: "2016-12-25", close: 43 },
{ date: "2016-12-26", close: 57 },
{ date: "2016-12-27", close: 55 },
{ date: "2016-12-28", close: 44 },
{ date: "2016-12-29", close: 45 },
{ date: "2016-12-30", close: 30 },
{ date: "2016-12-31", close: 36 },
],
line2: [],
});
#chtChartConstrictor {
height: 320px;
width: 100%;
}
.cht-LineChart_Line {
fill: transparent;
stroke: #f90;
stroke-width: 2px;
}
.cht-LineChart_Fill {
fill: rgba(73,255,255,.5);
}
.cht-LineChart_GridLine {
stroke-dasharray: 4px 4px;
stroke: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<div id="chtChartConstrictor"></div>
Следует иметь в виду, что это решение имеет свои проблемы: если ваши даты не равномерно распределены (например, [01-Dec, 02-Dec, 03-Dec, 06-Dec, 07-Dec]
), тики не будут равномерно распределены, что визуально неприятно.