Skip to content

Commit

Permalink
feat(line): finalize first version of LineCanvas
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte authored and Raphaël Benitte committed May 3, 2019
1 parent e42197d commit bd00815
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 146 deletions.
50 changes: 34 additions & 16 deletions packages/axes/src/compute.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,35 @@
import isNumber from 'lodash/isNumber'
import {
timeMillisecond,
utcMillisecond,
timeSecond,
utcSecond,
timeMinute,
utcMinute,
timeHour,
utcHour,
timeDay,
utcDay,
timeWeek,
utcWeek,
timeSunday,
utcSunday,
timeMonday,
utcMonday,
timeTuesday,
utcTuesday,
timeWednesday,
utcWednesday,
timeThursday,
utcThursday,
timeFriday,
utcFriday,
timeSaturday,
utcSaturday,
timeMonth,
utcMonth,
timeYear,
utcYear,
} from 'd3-time'
import { timeFormat } from 'd3-time-format'
import { format as d3Format } from 'd3-format'
Expand All @@ -42,21 +57,21 @@ export const centerScale = scale => {
}

const timeByType = {
millisecond: timeMillisecond,
second: timeSecond,
minute: timeMinute,
hour: timeHour,
day: timeDay,
week: timeWeek,
sunday: timeSunday,
monday: timeMonday,
tuesday: timeTuesday,
wednesday: timeWednesday,
thursday: timeThursday,
friday: timeFriday,
saturday: timeSaturday,
month: timeMonth,
year: timeYear,
millisecond: [timeMillisecond, utcMillisecond],
second: [timeSecond, utcSecond],
minute: [timeMinute, utcMinute],
hour: [timeHour, utcHour],
day: [timeDay, utcDay],
week: [timeWeek, utcWeek],
sunday: [timeSunday, utcSunday],
monday: [timeMonday, utcMonday],
tuesday: [timeTuesday, utcTuesday],
wednesday: [timeWednesday, utcWednesday],
thursday: [timeThursday, utcThursday],
friday: [timeFriday, utcFriday],
saturday: [timeSaturday, utcSaturday],
month: [timeMonth, utcMonth],
year: [timeYear, utcYear],
}

const timeTypes = Object.keys(timeByType)
Expand Down Expand Up @@ -84,7 +99,10 @@ export const getScaleTicks = (scale, spec) => {
// time interval
const matches = spec.match(timeIntervalRegexp)
if (matches) {
const timeType = timeByType[matches[2]]
// UTC is used as it's more predictible
// however local time could be used too
// let's see how it fits users' requirements
const timeType = timeByType[matches[2]][1]
if (matches[1] === undefined) {
return scale.ticks(timeType)
}
Expand Down
105 changes: 55 additions & 50 deletions packages/axes/tests/compute.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,84 +40,89 @@ describe('getTicks', () => {

describe('time scale', () => {
const timeScale = scaleUtc().domain([
new Date('January 01, 2000 00:00:01'),
new Date('January 01, 2001 00:00:01'),
new Date(Date.UTC(2000, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0)),
])

it('should return default ticks', () => {
expect(getScaleTicks(timeScale)).toEqual([
new Date('2000-01-01T00:00:00.000Z'),
new Date('2000-02-01T00:00:00.000Z'),
new Date('2000-03-01T00:00:00.000Z'),
new Date('2000-04-01T00:00:00.000Z'),
new Date('2000-05-01T00:00:00.000Z'),
new Date('2000-06-01T00:00:00.000Z'),
new Date('2000-07-01T00:00:00.000Z'),
new Date('2000-08-01T00:00:00.000Z'),
new Date('2000-09-01T00:00:00.000Z'),
new Date('2000-10-01T00:00:00.000Z'),
new Date('2000-11-01T00:00:00.000Z'),
new Date('2000-12-01T00:00:00.000Z'),
new Date(Date.UTC(2000, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 1, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 2, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 3, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 4, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 5, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 6, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 7, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 8, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 9, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 10, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 11, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0)),
])
})

it('should support using a count', () => {
expect(getScaleTicks(timeScale, 4)).toEqual([
new Date('2000-01-01T00:00:00.000Z'),
new Date('2000-04-01T00:00:00.000Z'),
new Date('2000-07-01T00:00:00.000Z'),
new Date('2000-10-01T00:00:00.000Z'),
new Date(Date.UTC(2000, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 3, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 6, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2000, 9, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0)),
])
})

const intervals = [
{
interval: '5 years',
domain: [
new Date('January 01, 2000 00:00:01'),
new Date('January 01, 2010 00:00:01'),
new Date(Date.UTC(2000, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
],
every: 5,
expect: [
new Date('2004-12-31T15:00:00.000Z'),
new Date('2009-12-31T15:00:00.000Z'),
new Date(Date.UTC(2000, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2005, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
],
},
{
interval: 'year',
domain: [
new Date('January 01, 2000 00:00:01'),
new Date('January 01, 2003 00:00:01'),
new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2004, 0, 1, 0, 0, 0, 0)),
],
expect: [
new Date('2000-12-31T15:00:00.000Z'),
new Date('2001-12-31T15:00:00.000Z'),
new Date('2002-12-31T15:00:00.000Z'),
new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2002, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2003, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2004, 0, 1, 0, 0, 0, 0)),
],
},
{
interval: '3 months',
domain: [
new Date('January 01, 2009 00:00:01'),
new Date('January 01, 2010 00:00:01'),
new Date(Date.UTC(2009, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
],
expect: [
new Date('2009-03-31T15:00:00.000Z'),
new Date('2009-06-30T15:00:00.000Z'),
new Date('2009-09-30T15:00:00.000Z'),
new Date('2009-12-31T15:00:00.000Z'),
new Date(Date.UTC(2009, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2009, 3, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2009, 6, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2009, 9, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
],
},
{
interval: '2 days',
domain: [
new Date('January 01, 2010 00:00:01'),
new Date('January 07, 2010 00:00:01'),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 7, 0, 0, 0, 0)),
],
expect: [
new Date('2010-01-02T15:00:00.000Z'),
new Date('2010-01-04T15:00:00.000Z'),
new Date('2010-01-06T15:00:00.000Z'),
new Date(Date.UTC(2010, 0, 1, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 3, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 5, 0, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 7, 0, 0, 0, 0)),
],
},
{
Expand All @@ -127,10 +132,10 @@ describe('getTicks', () => {
new Date(Date.UTC(2010, 1, 1, 0, 0, 0)),
],
expect: [
new Date('2010-01-05T15:00:00.000Z'),
new Date('2010-01-12T15:00:00.000Z'),
new Date('2010-01-19T15:00:00.000Z'),
new Date('2010-01-26T15:00:00.000Z'),
new Date(Date.UTC(2010, 0, 6, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 13, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 20, 0, 0, 0)),
new Date(Date.UTC(2010, 0, 27, 0, 0, 0)),
],
},
{
Expand All @@ -140,13 +145,13 @@ describe('getTicks', () => {
new Date(Date.UTC(2010, 0, 1, 9, 0, 0)),
],
expect: [
new Date('2010-01-01T06:00:00.000Z'),
new Date('2010-01-01T06:30:00.000Z'),
new Date('2010-01-01T07:00:00.000Z'),
new Date('2010-01-01T07:30:00.000Z'),
new Date('2010-01-01T08:00:00.000Z'),
new Date('2010-01-01T08:30:00.000Z'),
new Date('2010-01-01T09:00:00.000Z'),
new Date(Date.UTC(2010, 0, 1, 6, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 6, 30, 0)),
new Date(Date.UTC(2010, 0, 1, 7, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 7, 30, 0)),
new Date(Date.UTC(2010, 0, 1, 8, 0, 0)),
new Date(Date.UTC(2010, 0, 1, 8, 30, 0)),
new Date(Date.UTC(2010, 0, 1, 9, 0, 0)),
],
},
]
Expand Down
Binary file modified packages/line/doc/line-canvas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified packages/line/doc/line.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 26 additions & 24 deletions packages/line/stories/line.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -803,15 +803,15 @@ stories.add('formatting axis values', () => (
/>
))

stories.add('formatting tooltip values', () => (
stories.add('formatting values', () => (
<Line
{...commonProperties}
curve="monotoneX"
yScale={{
type: 'linear',
stacked: boolean('stacked', true),
}}
tooltipFormat={value =>
yFormat={value =>
`${Number(value).toLocaleString('ru-RU', {
minimumFractionDigits: 2,
})} ₽`
Expand All @@ -828,28 +828,30 @@ stories.add('custom tooltip', () => (
type: 'linear',
stacked: boolean('stacked', true),
}}
sliceTooltip={({ slice }) => (
<div
style={{
background: 'white',
padding: '9px 12px',
border: '1px solid #ccc',
}}
>
<div>{slice.id}</div>
{slice.data.map(d => (
<div
key={d.serie.id}
style={{
color: d.serie.color,
padding: '3px 0',
}}
>
<strong>{d.serie.id}</strong> [{d.data.y}]
</div>
))}
</div>
)}
sliceTooltip={({ slice }) => {
return (
<div
style={{
background: 'white',
padding: '9px 12px',
border: '1px solid #ccc',
}}
>
<div>x: {slice.id}</div>
{slice.points.map(point => (
<div
key={point.id}
style={{
color: point.serieColor,
padding: '3px 0',
}}
>
<strong>{point.serieId}</strong> [{point.data.yFormatted}]
</div>
))}
</div>
)
}}
/>
))

Expand Down
10 changes: 7 additions & 3 deletions packages/scales/src/timeHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { timeParse } from 'd3-time-format'
import { timeParse, utcParse } from 'd3-time-format'

export const TIME_PRECISION_MILLISECOND = 'millisecond'
export const TIME_PRECISION_SECOND = 'second'
Expand Down Expand Up @@ -52,10 +52,14 @@ export const createPrecisionMethod = precision => date => {
return date
}

export const createDateNormalizer = ({ format = 'native', precision = 'millisecond' }) => {
export const createDateNormalizer = ({
format = 'native',
precision = 'millisecond',
useUTC = true,
}) => {
const precisionFn = createPrecisionMethod(precision)
if (format === 'native') return v => precisionFn(v)

const parseTime = timeParse(format)
const parseTime = useUTC ? utcParse(format) : timeParse(format)
return v => precisionFn(parseTime(v))
}
18 changes: 12 additions & 6 deletions packages/scales/src/timeScale.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { scaleTime } from 'd3-scale'
import { scaleTime, scaleUtc } from 'd3-scale'
import PropTypes from 'prop-types'
import { createDateNormalizer, timePrecisions, TIME_PRECISION_MILLISECOND } from './timeHelpers'

export const timeScale = (
{ axis, format = 'native', precision = TIME_PRECISION_MILLISECOND, min = 'auto', max = 'auto' },
{
axis,
format = 'native',
precision = TIME_PRECISION_MILLISECOND,
min = 'auto',
max = 'auto',
useUTC = true,
},
xy,
width,
height
) => {
const values = xy[axis]
const size = axis === 'x' ? width : height

const normalize = createDateNormalizer({ format, precision })
const normalize = createDateNormalizer({ format, precision, useUTC })

let minValue = min
if (min === 'auto') {
Expand All @@ -35,9 +42,8 @@ export const timeScale = (
maxValue = normalize(values.max)
}

const scale = scaleTime()
.domain([minValue, maxValue])
.range([0, size])
const scale = useUTC ? scaleUtc : scaleTime
scale.domain([minValue, maxValue]).range([0, size])

scale.type = 'time'

Expand Down
Loading

0 comments on commit bd00815

Please sign in to comment.