diff --git a/website/src/data/components/time-range/mapper.js b/website/src/data/components/time-range/mapper.js
new file mode 100644
index 000000000..1804d37bc
--- /dev/null
+++ b/website/src/data/components/time-range/mapper.js
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the nivo project.
+ *
+ * Copyright 2016-present, Raphaël Benitte.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+import React from 'react'
+import styled from 'styled-components'
+import { settingsMapper } from '../../../lib/settings'
+
+const TooltipWrapper = styled.div`
+ display: grid;
+ background: #333;
+ padding: 10px;
+ border-radius: 4px;
+ grid-template-columns: 100px 1fr;
+ grid-column-gap: 12px;
+`
+const TooltipKey = styled.span`
+ font-weight: 600;
+`
+
+const CustomTooltip = day => {
+ return (
+
+ day
+ {day.day}
+ value
+ {day.value}
+ coordinates.x
+ {day.coordinates.x}
+ coordinates.y
+ {day.coordinates.y}
+ height
+ {day.height}
+ width
+ {day.width}
+
+ )
+}
+
+export default settingsMapper(
+ {
+ tooltip: (value, values) => {
+ if (!values['custom tooltip example']) return undefined
+
+ return CustomTooltip
+ },
+ },
+ {
+ exclude: ['custom tooltip example'],
+ }
+)
diff --git a/website/src/data/components/time-range/meta.yml b/website/src/data/components/time-range/meta.yml
new file mode 100644
index 000000000..ce61bfd46
--- /dev/null
+++ b/website/src/data/components/time-range/meta.yml
@@ -0,0 +1,13 @@
+flavors:
+ - flavor: svg
+ path: /time-range/
+
+TimeRange:
+ package: '@nivo/calendar'
+ tags:
+ - svg
+ - isomorphic
+ stories: []
+ description: |
+ The TimeRange chart is similar to the [Calendar](self:/calendar) chart, but
+ it allows you to specify dates less than a year.
diff --git a/website/src/data/components/time-range/props.js b/website/src/data/components/time-range/props.js
new file mode 100644
index 000000000..007c13f5d
--- /dev/null
+++ b/website/src/data/components/time-range/props.js
@@ -0,0 +1,371 @@
+/*
+ * This file is part of the nivo project.
+ *
+ * Copyright 2016-present, Raphaël Benitte.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+import { boxAlignments } from '@nivo/core'
+import { timeRangeDefaultProps as defaults } from '@nivo/calendar'
+import { themeProperty, getLegendsProps, groupProperties } from '../../../lib/componentProperties'
+
+const props = [
+ {
+ key: 'data',
+ group: 'Base',
+ help: 'Chart data.',
+ description: `
+ Chart data, which must conform to this structure:
+ \`\`\`
+ Array<{
+ day: string, // format must be YYYY-MM-DD
+ value: number
+ }>
+ \`\`\`
+ You can also add arbitrary data to this structure
+ to be used in tooltips or event handlers.
+ `,
+ type: 'object[]',
+ required: true,
+ },
+ {
+ key: 'from',
+ group: 'Base',
+ help: 'start date',
+ type: 'string | Date',
+ required: true,
+ },
+ {
+ key: 'to',
+ group: 'Base',
+ help: 'end date',
+ type: 'string | Date',
+ required: true,
+ },
+ {
+ key: 'width',
+ enableControlForFlavors: ['api'],
+ help: 'Chart width.',
+ description: `
+ not required if using responsive alternative of
+ the component \`\`.
+ `,
+ type: 'number',
+ required: true,
+ controlType: 'range',
+ group: 'Base',
+ controlOptions: {
+ unit: 'px',
+ min: 100,
+ max: 1000,
+ step: 5,
+ },
+ },
+ {
+ key: 'height',
+ enableControlForFlavors: ['api'],
+ help: 'Chart height.',
+ description: `
+ not required if using responsive alternative of
+ the component \`\`.
+ `,
+ type: 'number',
+ required: true,
+ controlType: 'range',
+ group: 'Base',
+ controlOptions: {
+ unit: 'px',
+ min: 100,
+ max: 1000,
+ step: 5,
+ },
+ },
+ {
+ key: 'direction',
+ help: 'defines calendar layout direction.',
+ type: 'string',
+ required: false,
+ defaultValue: defaults.direction,
+ controlType: 'radio',
+ group: 'Base',
+ controlOptions: {
+ choices: [
+ { label: 'horizontal', value: 'horizontal' },
+ { label: 'vertical', value: 'vertical' },
+ ],
+ },
+ },
+ {
+ key: 'margin',
+ help: 'Chart margin.',
+ type: 'object',
+ required: false,
+ controlType: 'margin',
+ group: 'Base',
+ },
+ {
+ key: 'align',
+ help: 'defines how calendar should be aligned inside chart container.',
+ type: 'string',
+ required: false,
+ defaultValue: defaults.align,
+ controlType: 'boxAnchor',
+ group: 'Base',
+ controlOptions: {
+ choices: boxAlignments.map(align => ({
+ label: align,
+ value: align,
+ })),
+ },
+ },
+ {
+ key: 'minValue',
+ help: 'Minimum value.',
+ description: `
+ Minimum value. If 'auto', will pick the lowest value
+ in the provided data set.
+ Should be overriden if your data set does not contain
+ desired lower bound value.
+ `,
+ required: false,
+ defaultValue: defaults.minValue,
+ type: `number | 'auto'`,
+ controlType: 'switchableRange',
+ group: 'Base',
+ controlOptions: {
+ disabledValue: 'auto',
+ defaultValue: 0,
+ min: -300,
+ max: 300,
+ },
+ },
+ {
+ key: 'maxValue',
+ help: 'Maximum value.',
+ description: `
+ Maximum value. If 'auto', will pick the highest value
+ in the provided data set.
+ Should be overriden if your data set does not contain
+ desired higher bound value.
+ `,
+ required: false,
+ defaultValue: defaults.maxValue,
+ type: `number | 'auto'`,
+ controlType: 'switchableRange',
+ group: 'Base',
+ controlOptions: {
+ disabledValue: 'auto',
+ defaultValue: 100,
+ min: 0,
+ max: 600,
+ },
+ },
+ themeProperty,
+ {
+ key: 'colors',
+ group: 'Style',
+ help: 'Cell colors.',
+ description: `
+ An array of colors to be used in conjunction with
+ \`domain\` to compute days' color.
+ It applies to days having a value defined, otherwise,
+ \`emptyColor\` will be used.
+ `,
+ type: 'string[]',
+ required: false,
+ defaultValue: defaults.colors,
+ },
+ // Months
+ {
+ key: 'monthLegend',
+ help: `can be used to customize months label, returns abbreviated month name (english) by default. This can be used to use a different language`,
+ type: '(year: number, month: number, date: Date) => string | number',
+ required: false,
+ group: 'Months',
+ },
+ {
+ key: 'monthLegendPosition',
+ help: 'defines month legends position.',
+ type: `'before' | 'after'`,
+ required: false,
+ defaultValue: defaults.monthLegendPosition,
+ controlType: 'radio',
+ group: 'Months',
+ controlOptions: {
+ choices: [
+ { label: 'before', value: 'before' },
+ { label: 'after', value: 'after' },
+ ],
+ },
+ },
+ {
+ key: 'monthLegendOffset',
+ help: 'define offset from month edge to its label.',
+ type: 'number',
+ required: false,
+ defaultValue: defaults.monthLegendOffset,
+ controlType: 'range',
+ group: 'Months',
+ controlOptions: {
+ unit: 'px',
+ min: 0,
+ max: 36,
+ },
+ },
+ // Weekday
+ {
+ key: 'weekdayLegendOffset',
+ help: 'define offset from weekday edge to its label.',
+ type: 'number',
+ required: false,
+ defaultValue: defaults.weekdayLegendOffset,
+ controlType: 'range',
+ group: 'Weekday',
+ controlOptions: {
+ unit: 'px',
+ min: 0,
+ max: 100,
+ },
+ },
+ // Days
+ {
+ key: 'square',
+ help: 'force day cell into square shape',
+ type: 'boolean',
+ required: false,
+ defaultValue: defaults.square,
+ controlType: 'switch',
+ group: 'Days',
+ },
+ {
+ key: 'dayRadius',
+ help: 'define border radius of each day cell.',
+ type: 'number',
+ required: false,
+ defaultValue: defaults.dayRadius,
+ controlType: 'range',
+ group: 'Days',
+ controlOptions: {
+ unit: 'px',
+ min: 0,
+ max: 20,
+ },
+ },
+ {
+ key: 'daySpacing',
+ help: 'define spacing between each day cell.',
+ type: 'number',
+ required: false,
+ defaultValue: defaults.daySpacing,
+ controlType: 'range',
+ group: 'Days',
+ controlOptions: {
+ unit: 'px',
+ min: 0,
+ max: 20,
+ },
+ },
+ {
+ key: 'dayBorderWidth',
+ help: 'width of days border.',
+ type: 'number',
+ required: false,
+ defaultValue: defaults.dayBorderWidth,
+ controlType: 'lineWidth',
+ group: 'Days',
+ },
+ {
+ key: 'dayBorderColor',
+ help: 'color to use for days border.',
+ type: 'string',
+ required: false,
+ defaultValue: defaults.dayBorderColor,
+ controlType: 'colorPicker',
+ group: 'Days',
+ },
+ {
+ key: 'isInteractive',
+ help: 'Enable/disable interactivity.',
+ type: 'boolean',
+ required: false,
+ defaultValue: defaults.isInteractive,
+ controlType: 'switch',
+ group: 'Interactivity',
+ },
+ {
+ key: 'onClick',
+ group: 'Interactivity',
+ help: 'onClick handler, it receives clicked day data and mouse event.',
+ type: '(day, event) => void',
+ required: false,
+ },
+ {
+ key: 'tooltip',
+ group: 'Interactivity',
+ type: 'Function',
+ required: false,
+ help: 'Custom tooltip component.',
+ description: `
+ A function allowing complete tooltip customisation, it must return a valid HTML
+ element and will receive the following data:
+ \`\`\`
+ {
+ day: string,
+ date: {Date},
+ value: number,
+ color: string,
+ coordinates: {
+ x: number,
+ y: number,
+ },
+ height: number
+ width: number
+ }
+ \`\`\`
+ You can also customize the tooltip style
+ using the \`theme.tooltip\` object.
+ `,
+ },
+ {
+ key: 'custom tooltip example',
+ help: 'Showcase custom tooltip.',
+ type: 'boolean',
+ controlType: 'switch',
+ group: 'Interactivity',
+ },
+ {
+ key: 'legends',
+ flavors: ['svg'],
+ type: 'LegendProps[]',
+ help: `Optional chart's legends.`,
+ group: 'Legends',
+ controlType: 'array',
+ controlOptions: {
+ props: getLegendsProps(['svg']),
+ shouldCreate: true,
+ addLabel: 'add legend',
+ shouldRemove: true,
+ getItemTitle: (index, legend) =>
+ `legend[${index}]: ${legend.anchor}, ${legend.direction}`,
+ defaults: {
+ anchor: 'bottom-right',
+ direction: 'row',
+ justify: false,
+ itemCount: 4,
+ itemWidth: 42,
+ itemHeight: 36,
+ itemsSpacing: 14,
+ itemDirection: 'right-to-left',
+ translateX: -85,
+ translateY: -240,
+ symbolSize: 20,
+ onClick: data => {
+ alert(JSON.stringify(data, null, ' '))
+ },
+ },
+ },
+ },
+]
+
+export const groups = groupProperties(props)
diff --git a/website/src/data/nav.js b/website/src/data/nav.js
index 8ed22cecc..c6e7147fe 100644
--- a/website/src/data/nav.js
+++ b/website/src/data/nav.js
@@ -21,6 +21,7 @@ import scatterplot from './components/scatterplot/meta.yml'
import stream from './components/stream/meta.yml'
import sunburst from './components/sunburst/meta.yml'
import swarmplot from './components/swarmplot/meta.yml'
+import timeRange from './components/time-range/meta.yml'
import treemap from './components/treemap/meta.yml'
import voronoi from './components/voronoi/meta.yml'
import waffle from './components/waffle/meta.yml'
@@ -158,6 +159,12 @@ export const components = [
icon: 'swarmplot',
tags: swarmplot.SwarmPlot.tags,
},
+ {
+ label: 'TimeRange',
+ path: '/time-range/',
+ icon: 'calendar',
+ tags: timeRange.TimeRange.tags,
+ },
{
label: 'TreeMap',
path: '/treemap/',
diff --git a/website/src/pages/time-range/index.js b/website/src/pages/time-range/index.js
new file mode 100644
index 000000000..3c9d8431e
--- /dev/null
+++ b/website/src/pages/time-range/index.js
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the nivo project.
+ *
+ * Copyright 2016-present, Raphaël Benitte.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+import React from 'react'
+import { ResponsiveTimeRange, timeRangeDefaultProps } from '@nivo/calendar'
+import { generateOrderedDayCounts } from '@nivo/generators'
+import ComponentTemplate from '../../components/components/ComponentTemplate'
+import meta from '../../data/components/time-range/meta.yml'
+import mapper from '../../data/components/time-range/mapper'
+import { groups } from '../../data/components/time-range/props'
+
+const Tooltip = data => {
+ /* return custom tooltip */
+}
+
+const from = new Date(2018, 3, 1)
+const to = new Date(2018, 7, 12)
+const generateData = () => generateOrderedDayCounts(from, to)
+
+const initialProperties = {
+ from: '2018-04-01',
+ to: '2018-08-12',
+
+ align: 'center',
+ emptyColor: '#eeeeee',
+ colors: ['#61cdbb', '#97e3d5', '#e8c1a0', '#f47560'],
+ minValue: 0,
+ maxValue: 'auto',
+
+ margin: {
+ top: 40,
+ right: 40,
+ bottom: 100,
+ left: 40,
+ },
+ direction: 'horizontal',
+
+ monthLegendPosition: 'before',
+ monthLegendOffset: 10,
+
+ weekdayLegendOffset: 75,
+
+ square: true,
+ dayRadius: 0,
+ daySpacing: 0,
+ dayBorderWidth: 2,
+ dayBorderColor: '#ffffff',
+
+ isInteractive: true,
+ 'custom tooltip example': false,
+ tooltip: null,
+
+ legends: [
+ {
+ anchor: 'bottom-right',
+ direction: 'row',
+ justify: false,
+ itemCount: 4,
+ itemWidth: 42,
+ itemHeight: 36,
+ itemsSpacing: 14,
+ itemDirection: 'right-to-left',
+ translateX: -85,
+ translateY: -240,
+ symbolSize: 20,
+ },
+ ],
+}
+
+const TimeRange = () => {
+ console.log('m', mapper)
+ return (
+ ({
+ ...properties,
+ tooltip: properties.tooltip ? Tooltip : undefined,
+ })}
+ generateData={generateData}
+ >
+ {(properties, data, theme, logAction) => {
+ return (
+ {
+ logAction({
+ type: 'click',
+ label: `[day] ${day.day}: ${day.value}`,
+ color: day.color,
+ data: day,
+ })
+ }}
+ />
+ )
+ }}
+
+ )
+}
+
+export default TimeRange