Skip to content

Commit 077411a

Browse files
committed
Add interval.range, and time.scale.nice.
This commit provides a standard interface for time intervals: interval.floor(date) interval.ceil(date) interval.offset(date, k) interval.range(start, stop, step) All local-time intervals (such as d3.time.day) have a UTC-equivalent interval, available as interval.utc (such as d3.time.day.utc). Fixes d3#463. Note that for the time.scale, an interval function is required to nice (such as d3.time.day). In the future, we might relax that to allow a count of ticks, similar to the ticks method, but in that case we'd also need the ability to floor to a given tick number (e.g., every other week) and likewise for ceil. This seems like a reasonable first implementation.
1 parent 82cd725 commit 077411a

28 files changed

Lines changed: 383 additions & 337 deletions

Makefile

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,13 @@ d3.time.js: \
190190
src/time/format-utc.js \
191191
src/time/format-iso.js \
192192
src/time/interval.js \
193-
src/time/range.js \
194193
src/time/second.js \
195-
src/time/seconds.js \
196194
src/time/minute.js \
197-
src/time/minutes.js \
198195
src/time/hour.js \
199-
src/time/hours.js \
200196
src/time/day.js \
201-
src/time/days.js \
202197
src/time/week.js \
203-
src/time/weeks.js \
204198
src/time/month.js \
205-
src/time/months.js \
206199
src/time/year.js \
207-
src/time/years.js \
208200
src/time/scale.js \
209201
src/time/scale-utc.js
210202

d3.v2.js

Lines changed: 90 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -8905,128 +8905,139 @@ d3_time_formatIsoNative.parse = function(string) {
89058905
};
89068906

89078907
d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
8908-
function d3_time_interval(floor, step) {
8908+
function d3_time_interval(local, step, number) {
89098909

89108910
function offset(date, offset) {
89118911
step(date, offset);
89128912
return date;
89138913
}
89148914

89158915
function ceil(date) {
8916-
return offset(floor(new d3_time(date - 1)), 1);
8916+
return offset(local(new d3_time(date - 1)), 1);
89178917
}
89188918

8919-
floor.floor = floor;
8920-
floor.ceil = ceil;
8921-
floor.offset = offset;
8922-
8923-
floor.floor.utc = floor.utc = d3_time_interval_utc(floor);
8924-
floor.ceil.utc = d3_time_interval_utc(ceil);
8925-
floor.offset.utc = d3_time_interval_utc(offset);
8926-
8927-
return floor;
8928-
}
8929-
8930-
function d3_time_interval_utc(method) {
8931-
var utc = new d3_time_utc();
8932-
return function(date, offset) {
8933-
try {
8934-
d3_time = d3_time_utc;
8935-
utc._ = date;
8936-
return method(utc, offset)._;
8937-
} finally {
8938-
d3_time = Date;
8939-
}
8940-
};
8941-
}
8942-
function d3_time_range(interval, number) {
8943-
var utc = new d3_time_utc();
8944-
89458919
function range(t0, t1, dt) {
8946-
var time = interval.ceil(t0), times = [];
8920+
var time = ceil(t0), times = [];
89478921
if (dt > 1) {
89488922
while (time < t1) {
8949-
var date = new d3_time(+time);
8950-
if (!(number(date) % dt)) times.push(date);
8951-
interval.offset(time, 1);
8923+
if (!(number(time) % dt)) times.push(new Date(+time));
8924+
step(time, 1);
89528925
}
89538926
} else {
8954-
while (time < t1) times.push(new d3_time(+time)), interval.offset(time, 1);
8927+
while (time < t1) times.push(new Date(+time)), step(time, 1);
89558928
}
89568929
return times;
89578930
}
89588931

8959-
range.utc = function(t0, t1, dt) {
8932+
function range_utc(t0, t1, dt) {
89608933
try {
89618934
d3_time = d3_time_utc;
8935+
var utc = new d3_time_utc();
89628936
utc._ = t0;
8963-
return range(utc, t1, dt).map(function(d) { return d._; });
8937+
return range(utc, t1, dt);
89648938
} finally {
89658939
d3_time = Date;
89668940
}
8967-
};
8941+
}
89688942

8969-
return range;
8943+
local.floor = local;
8944+
local.ceil = ceil;
8945+
local.offset = offset;
8946+
local.range = range;
8947+
8948+
var utc = local.utc = d3_time_interval_utc(local);
8949+
utc.floor = utc;
8950+
utc.ceil = d3_time_interval_utc(ceil);
8951+
utc.offset = d3_time_interval_utc(offset);
8952+
utc.range = range_utc;
8953+
8954+
return local;
8955+
}
8956+
8957+
function d3_time_interval_utc(method) {
8958+
return function(date, offset) {
8959+
try {
8960+
d3_time = d3_time_utc;
8961+
var utc = new d3_time_utc();
8962+
utc._ = date;
8963+
return method(utc, offset)._;
8964+
} finally {
8965+
d3_time = Date;
8966+
}
8967+
};
89708968
}
89718969
d3.time.second = d3_time_interval(function(date) {
89728970
return new d3_time(Math.floor(date / 1e3) * 1e3);
89738971
}, function(date, offset) {
89748972
date.setTime(date.getTime() + Math.floor(offset) * 1e3); // DST breaks setSeconds
8975-
});
8976-
d3.time.seconds = d3_time_range(d3.time.second, function(date) {
8973+
}, function(date) {
89778974
return date.getSeconds();
89788975
});
8976+
8977+
d3.time.seconds = d3.time.second.range;
8978+
d3.time.seconds.utc = d3.time.second.utc.range;
89798979
d3.time.minute = d3_time_interval(function(date) {
89808980
return new d3_time(Math.floor(date / 6e4) * 6e4);
89818981
}, function(date, offset) {
89828982
date.setTime(date.getTime() + Math.floor(offset) * 6e4); // DST breaks setMinutes
8983-
});
8984-
d3.time.minutes = d3_time_range(d3.time.minute, function(date) {
8983+
}, function(date) {
89858984
return date.getMinutes();
89868985
});
8986+
8987+
d3.time.minutes = d3.time.minute.range;
8988+
d3.time.minutes.utc = d3.time.minute.utc.range;
89878989
d3.time.hour = d3_time_interval(function(date) {
89888990
var timezone = date.getTimezoneOffset() / 60;
89898991
return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
89908992
}, function(date, offset) {
89918993
date.setTime(date.getTime() + Math.floor(offset) * 36e5); // DST breaks setHours
8992-
});
8993-
d3.time.hours = d3_time_range(d3.time.hour, function(date) {
8994+
}, function(date) {
89948995
return date.getHours();
89958996
});
8997+
8998+
d3.time.hours = d3.time.hour.range;
8999+
d3.time.hours.utc = d3.time.hour.utc.range;
89969000
d3.time.day = d3_time_interval(function(date) {
89979001
return new d3_time(date.getFullYear(), date.getMonth(), date.getDate());
89989002
}, function(date, offset) {
89999003
date.setDate(date.getDate() + offset);
9000-
});
9001-
d3.time.days = d3_time_range(d3.time.day, function(date) {
9004+
}, function(date) {
90029005
return date.getDate() - 1;
90039006
});
9007+
9008+
d3.time.days = d3.time.day.range;
9009+
d3.time.days.utc = d3.time.day.utc.range;
90049010
d3.time.week = d3_time_interval(function(date) {
90059011
(date = d3.time.day(date)).setDate(date.getDate() - date.getDay());
90069012
return date;
90079013
}, function(date, offset) {
90089014
date.setDate(date.getDate() + Math.floor(offset) * 7);
9009-
});
9010-
d3.time.weeks = d3_time_range(d3.time.week, function(date) {
9015+
}, function(date) {
90119016
return Math.floor((date - new d3_time(date.getFullYear(), 0, 1)) / 6048e5);
90129017
});
9018+
9019+
d3.time.weeks = d3.time.week.range;
9020+
d3.time.weeks.utc = d3.time.week.utc.range;
90139021
d3.time.month = d3_time_interval(function(date) {
90149022
return new d3_time(date.getFullYear(), date.getMonth(), 1);
90159023
}, function(date, offset) {
90169024
date.setMonth(date.getMonth() + offset);
9017-
});
9018-
d3.time.months = d3_time_range(d3.time.month, function(date) {
9025+
}, function(date) {
90199026
return date.getMonth();
90209027
});
9028+
9029+
d3.time.months = d3.time.month.range;
9030+
d3.time.months.utc = d3.time.month.utc.range;
90219031
d3.time.year = d3_time_interval(function(date) {
90229032
return new d3_time(date.getFullYear(), 0, 1);
90239033
}, function(date, offset) {
90249034
date.setFullYear(date.getFullYear() + offset);
9025-
});
9026-
d3.time.years = d3_time_range(d3.time.year, function(date) {
9035+
}, function(date) {
90279036
return date.getFullYear();
90289037
});
9029-
// TODO nice
9038+
9039+
d3.time.years = d3.time.year.range;
9040+
d3.time.years.utc = d3.time.year.utc.range;
90309041
function d3_time_scale(linear, methods, format) {
90319042

90329043
function scale(x) {
@@ -9043,6 +9054,11 @@ function d3_time_scale(linear, methods, format) {
90439054
return scale;
90449055
};
90459056

9057+
scale.nice = function(m) {
9058+
var extent = d3_time_scaleExtent(scale.domain());
9059+
return scale.domain([m.floor(extent[0]), m.ceil(extent[1])]);
9060+
};
9061+
90469062
scale.ticks = function(m, k) {
90479063
var extent = d3_time_scaleExtent(scale.domain());
90489064
if (typeof m !== "function") {
@@ -9054,7 +9070,7 @@ function d3_time_scale(linear, methods, format) {
90549070
if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
90559071
m = methods[i];
90569072
k = m[1];
9057-
m = m[0];
9073+
m = m[0].range;
90589074
}
90599075
return m(extent[0], new Date(+extent[1] + 1), k); // inclusive upper bound
90609076
};
@@ -9124,24 +9140,24 @@ var d3_time_scaleSteps = [
91249140
];
91259141

91269142
var d3_time_scaleLocalMethods = [
9127-
[d3.time.seconds, 1],
9128-
[d3.time.seconds, 5],
9129-
[d3.time.seconds, 15],
9130-
[d3.time.seconds, 30],
9131-
[d3.time.minutes, 1],
9132-
[d3.time.minutes, 5],
9133-
[d3.time.minutes, 15],
9134-
[d3.time.minutes, 30],
9135-
[d3.time.hours, 1],
9136-
[d3.time.hours, 3],
9137-
[d3.time.hours, 6],
9138-
[d3.time.hours, 12],
9139-
[d3.time.days, 1],
9140-
[d3.time.days, 2],
9141-
[d3.time.weeks, 1],
9142-
[d3.time.months, 1],
9143-
[d3.time.months, 3],
9144-
[d3.time.years, 1]
9143+
[d3.time.second, 1],
9144+
[d3.time.second, 5],
9145+
[d3.time.second, 15],
9146+
[d3.time.second, 30],
9147+
[d3.time.minute, 1],
9148+
[d3.time.minute, 5],
9149+
[d3.time.minute, 15],
9150+
[d3.time.minute, 30],
9151+
[d3.time.hour, 1],
9152+
[d3.time.hour, 3],
9153+
[d3.time.hour, 6],
9154+
[d3.time.hour, 12],
9155+
[d3.time.day, 1],
9156+
[d3.time.day, 2],
9157+
[d3.time.week, 1],
9158+
[d3.time.month, 1],
9159+
[d3.time.month, 3],
9160+
[d3.time.year, 1]
91459161
];
91469162

91479163
var d3_time_scaleLocalFormats = [
@@ -9165,26 +9181,9 @@ d3_time_scaleLocalMethods.year = function(extent, m) {
91659181
d3.time.scale = function() {
91669182
return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
91679183
};
9168-
var d3_time_scaleUTCMethods = [
9169-
[d3.time.seconds.utc, 1],
9170-
[d3.time.seconds.utc, 5],
9171-
[d3.time.seconds.utc, 15],
9172-
[d3.time.seconds.utc, 30],
9173-
[d3.time.minutes.utc, 1],
9174-
[d3.time.minutes.utc, 5],
9175-
[d3.time.minutes.utc, 15],
9176-
[d3.time.minutes.utc, 30],
9177-
[d3.time.hours.utc, 1],
9178-
[d3.time.hours.utc, 3],
9179-
[d3.time.hours.utc, 6],
9180-
[d3.time.hours.utc, 12],
9181-
[d3.time.days.utc, 1],
9182-
[d3.time.days.utc, 2],
9183-
[d3.time.weeks.utc, 1],
9184-
[d3.time.months.utc, 1],
9185-
[d3.time.months.utc, 3],
9186-
[d3.time.years.utc, 1]
9187-
];
9184+
var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
9185+
return [m[0].utc, m[1]];
9186+
});
91889187

91899188
var d3_time_scaleUTCFormats = [
91909189
[d3.time.format.utc("%Y"), function(d) { return true; }],

d3.v2.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/time/day.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ d3.time.day = d3_time_interval(function(date) {
22
return new d3_time(date.getFullYear(), date.getMonth(), date.getDate());
33
}, function(date, offset) {
44
date.setDate(date.getDate() + offset);
5+
}, function(date) {
6+
return date.getDate() - 1;
57
});
8+
9+
d3.time.days = d3.time.day.range;
10+
d3.time.days.utc = d3.time.day.utc.range;

src/time/days.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/time/hour.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@ d3.time.hour = d3_time_interval(function(date) {
33
return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
44
}, function(date, offset) {
55
date.setTime(date.getTime() + Math.floor(offset) * 36e5); // DST breaks setHours
6+
}, function(date) {
7+
return date.getHours();
68
});
9+
10+
d3.time.hours = d3.time.hour.range;
11+
d3.time.hours.utc = d3.time.hour.utc.range;

src/time/hours.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)