添加 d3 时间轴开头的额外刻度
Posted
技术标签:
【中文标题】添加 d3 时间轴开头的额外刻度【英文标题】:Add extra tick of the beginning of a d3 time axis 【发布时间】:2017-09-14 10:54:16 【问题描述】:我一直在研究 x 轴,它将根据在别处设置的间隔变量格式化轴上的刻度。这是一个字符串('decade'、'lustrum'、'years'、days' 等)。我让它工作它通常可以完成工作。以下是 19198 年 8 月 8 日至 2017 年 8 月 24 日之间的日期范围示例,间隔为 5 年。有一个没有刻度标签的次要(次要)轴也根据间隔变化/我还为我们的房屋风格添加了一些格式。 示例
我遇到的问题是我想在主轴的开头添加一个额外的刻度,以便它与我们总是标记初始日期的房子风格相匹配。我使用了 .nice() 但这也会在末尾添加一个刻度,它也默认为轴上的下一个舍入增量,所以如果图表开始于 2009 年并且我有十年的间隔,那么 .nice 将强制回到 2000 年的图表,这是不好的
我想要实现的是这个 his:
我认为这就像访问轴刻度数组并将 domain()[0] 值移到零位置一样简单。但这似乎不起作用。当我将它们分配给测试变量时,我实际上似乎并没有访问它们。我得到的是每两年一次的日期刻度。
任何指点将不胜感激,谢谢
这是我的代码:
function xaxisDate()
let mindate = new Date(1970, 1, 1);
let maxdate = new Date(2017, 6, 1);
let scale = d3.scaleTime()
.domain([mindate, maxdate])
.range([0, 220]);
let frameName;
let interval = 'lustrum';
let minorAxis = true;
let tickSize = 10;
let minorTickSize = 5;
let fullYear = false;
let align = 'bottom';
let xLabel;
let xLabelMinor;
function axis(parent)
//scale.nice(getTicks(interval))
function getAxis(alignment)
return
top: d3.axisTop(),
bottom: d3.axisBottom(),
[alignment];
const xAxis = getAxis(align)
.tickSize(tickSize)
.ticks(getTicks(interval))
.tickFormat(tickFormat(interval))
.scale(scale)
test = scale.ticks()
console.log('before',test);
// console.log('domain',scale.domain()[0])
// scale.ticks().unshift(scale.domain()[0]);
// console.log('after',scale.ticks())
// xAxis.tickValues()
const xMinor = d3.axisBottom()
.tickSize(minorTickSize)
.ticks(getTicksMinor(interval))
.tickFormat('')
.scale(scale);
xLabel = parent.append('g')
.attr('class', 'axis xAxis axis baseline')
.call(xAxis);
if (minorAxis)
xLabelMinor = parent.append('g')
.attr('class', (d) =>
const plotHeight = d3.select('.chart-plot').node().getBBox().height;
if (plotHeight === tickSize)
return 'axis xAxis';
return 'axis xAxis axis baseline';
)
.call(xMinor);
if (frameName)
xLabel.selectAll('.axis.xAxis text')
.attr('id', frameName + 'xLabel');
xLabel.selectAll('.axis.xAxis line')
.attr('id', frameName + 'xTick');
if (minorAxis)
xLabelMinor.selectAll('.axis.xAxis line')
.attr('id', frameName + 'xTick');
xLabel.selectAll('.domain').remove();
function getTicks(interval)
console.log('interval',interval)
return
'century' : d3.timeYear.every(100),
'jubilee': d3.timeYear.every(50),
'decade': d3.timeYear.every(10),
'lustrum': d3.timeYear.every(5),
'years': d3.timeYear.every(1),
'quarters': d3.timeMonth.every(3),
'months': d3.timeMonth.every(1),
'weeks': d3.timeWeek.every(1),
'days': d3.timeDay.every(1),
'hours': d3.timeHour.every(1)
[interval];
function getTicksMinor(interval)
const test = d3.timeYear.every(1);
console.log('test', test)
return
'century': d3.timeYear.every(10),
'jubilee': d3.timeYear.every(10),
'decade': d3.timeYear.every(1),
'lustrum': d3.timeYear.every(1),
'years': d3.timeMonth.every(1),
'quarters': d3.timeMonth.every(1),
'months': d3.timeDay.every(1),
'weeks': d3.timeDay.every(1),
'days': d3.timeHour.every(1),
'hours': d3.timeMinute.every(1)
[interval];
function tickFormat(interval)
let formatFullYear = d3.timeFormat('%Y'),
formatYear = d3.timeFormat('%y'),
formatMonth = d3.timeFormat('%b'),
formatWeek = d3.timeFormat('%W'),
formatDay = d3.timeFormat('%d'),
formatHour = d3.timeFormat('%H:%M');
return
'century': d3.timeFormat('%Y'),
'jubilee': function(d, i)
const format = checkCentury(d, i);
return format;
,
'decade': function(d, i)
const format = checkCentury(d, i);
return format;
,
'lustrum':function(d, i)
const format = checkCentury(d, i);
return format;
,
'years': function(d, i)
const format = checkCentury(d, i);
return format;
,
'quarters':function(d, i)
const format = getQuarters(d, i);
return format;
,
'months': function(d, i)
const format = checkMonth(d, i);
return format;
,
'weeks':function(d, i)
const format = getWeek(d, i);
return format;
,
'days':function(d, i)
const format = getDays(d, i);
return format;
,
'hours': function(d, i)
const format = getHours(d, i);
return format;
,
[interval];
function getHours(d, i)
if (d.getHours() === 1 || i === 0)
return formatHour(d) + ' ' + formatDay(d);
return formatHour(d);
function getDays(d, i)
if (d.getDate() === 1 || i === 0)
return formatDay(d) + ' ' + formatMonth(d);
return formatDay(d);
function getWeek(d, i)
if (d.getDate() < 9)
return formatWeek(d) + ' ' + formatMonth(d);
return formatWeek(d);
function getQuarters(d, i)
if (d.getMonth() < 3 && i < 4)
return 'Q1 ' + formatFullYear(d);
if (d.getMonth() < 3)
return 'Q1';
if (d.getMonth() >= 3 && d.getMonth() < 6)
return 'Q2';
if (d.getMonth() >= 6 && d.getMonth() < 9)
return 'Q3';
if (d.getMonth() >= 9 && d.getMonth() < 12)
return 'Q4';
function checkMonth(d, i)
if (d.getMonth() === 0 || i === 0)
const newYear = d3.timeFormat('%b %Y');
return newYear(d);
return formatMonth(d);
function checkCentury(d, i)
if (fullYear || (+formatFullYear(d) % 100 === 0) || (i === 0))
return formatFullYear(d);
return formatYear(d);
axis.align = (d) =>
align = d;
return axis;
;
axis.frameName = (d) =>
if (d === undefined) return frameName;
frameName = d;
return axis;
;
axis.scale = (d) =>
scale = d;
return axis;
;
axis.domain = (d) =>
scale.domain(d);
return axis;
;
axis.range = (d) =>
scale.range(d);
return axis;
;
axis.fullYear = (d) =>
if (d === undefined) return fullYear;
fullYear = d;
return axis;
;
axis.interval = (d) =>
interval = d;
return axis;
;
axis.tickSize = (d) =>
if (!d) return tickSize;
tickSize = d;
return axis;
;
axis.minorTickSize = (d) =>
if (!d) return minorTickSize;
minorTickSize = d;
return axis;
;
axis.minorAxis = (d) =>
if (d === undefined) return minorAxis;
minorAxis = d;
return axis;
;
axis.xLabel = (d) =>
if (d === undefined) return xLabel;
xLabel = d;
return axis;
;
axis.xLabelMinor = (d) =>
if (d === undefined) return xLabelMinor;
xLabelMinor = d;
return axis;
;
return axis;
【问题讨论】:
【参考方案1】:答案在于tickValues。然后您需要返回刻度数组的值,并且我认为将域 [0] 值取消转换到其中。设置 xAxis 后,您需要插入以下内容:
let newTicks = scale.ticks(getTicks(interval))
newTicks.unshift(scale.domain()[0]);
xAxis.tickValues(newTicks)
【讨论】:
以上是关于添加 d3 时间轴开头的额外刻度的主要内容,如果未能解决你的问题,请参考以下文章