Skip to content

Commit

Permalink
feat(calendar): avoid unnecessary layout computing
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Benitte authored and Raphaël Benitte committed Mar 22, 2019
1 parent e0a46f5 commit 5aa0ff5
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 81 deletions.
34 changes: 7 additions & 27 deletions packages/calendar/src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@
* file that was distributed with this source code.
*/
import React from 'react'
import { Container, SvgWrapper } from '@nivo/core'
import { BoxLegendSvg } from '@nivo/legends'
import setDisplayName from 'recompose/setDisplayName'
import computeCalendar from './computeCalendar'
import { setDisplayName } from 'recompose'
import { CalendarPropTypes } from './props'
import { DIRECTION_HORIZONTAL } from './constants'
import CalendarDay from './CalendarDay'
import CalendarMonthPath from './CalendarMonthPath'
import { Container, SvgWrapper } from '@nivo/core'
import enhance from './enhance'

const Calendar = ({
data,
from,
to,

colorScale,

// dimensions
margin,
width,
height,
Expand All @@ -33,46 +27,31 @@ const Calendar = ({

direction,

// years
yearLegend,
yearSpacing,
yearLegendOffset,

// months
monthLegend,
monthBorderWidth,
monthBorderColor,
monthLegendOffset,

// days
daySpacing,
dayBorderWidth,
dayBorderColor,
emptyColor,

theme,

// interactivity
isInteractive,
tooltipFormat,
tooltip,
onClick,

legends,
}) => {
const { years, months, days } = computeCalendar({
width,
height,
from,
to,
data,
direction,
colorScale,
emptyColor,
yearSpacing,
daySpacing,
})

years,
months,
days,
}) => {
return (
<Container isInteractive={isInteractive} theme={theme}>
{({ showTooltip, hideTooltip }) => (
Expand All @@ -84,6 +63,7 @@ const Calendar = ({
x={d.x}
y={d.y}
size={d.size}
spacing={daySpacing}
color={d.color}
borderWidth={dayBorderWidth}
borderColor={dayBorderColor}
Expand Down
46 changes: 29 additions & 17 deletions packages/calendar/src/CalendarDay.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,41 @@ const CalendarDay = ({
x,
y,
size,
spacing,
color,
borderWidth,
borderColor,
onClick,
showTooltip,
hideTooltip,
}) => (
<rect
x={x}
y={y}
width={size}
height={size}
style={{
fill: color,
strokeWidth: borderWidth,
stroke: borderColor,
}}
onClick={onClick}
onMouseEnter={showTooltip}
onMouseMove={showTooltip}
onMouseLeave={hideTooltip}
/>
)
}) => {
return (
<>
<rect
x={x}
y={y}
width={size}
height={size}
style={{
fill: color,
strokeWidth: borderWidth,
stroke: borderColor,
}}
/>
<rect
fill="rgba(0, 0, 0, 0)"
x={x - spacing / 2}
y={y - spacing / 2}
width={size + spacing}
height={size + spacing}
onClick={onClick}
onMouseEnter={showTooltip}
onMouseMove={showTooltip}
onMouseLeave={hideTooltip}
/>
</>
)
}

CalendarDay.propTypes = {
onClick: PropTypes.func.isRequired,
Expand Down
1 change: 1 addition & 0 deletions packages/calendar/src/CalendarMonthPath.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const CalendarMonthPath = ({ path, borderWidth, borderColor }) => (
fill: 'none',
strokeWidth: borderWidth,
stroke: borderColor,
pointerEvents: 'none',
}}
/>
)
Expand Down
50 changes: 17 additions & 33 deletions packages/calendar/src/computeCalendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import memoize from 'lodash/memoize'
import isDate from 'lodash/isDate'
import range from 'lodash/range'
Expand Down Expand Up @@ -188,34 +187,18 @@ const cellPositionVertical = (cellSize, yearSpacing, daySpacing) => {
const dayFormat = timeFormat('%Y-%m-%d')

/**
* This layout is responsible for computing Calendar chart data/positions….
* It's used for all Calendar related chart components.
* Compute base layout, without caring about the current data.
*
* @param {number} width
* @param {number} height
* @param {string|Date} from
* @param {string|Date} to
* @param {array} data
* @param {string} direction
* @param {object} colorScale
* @param {string} emptyColor
* @param {number} yearSpacing
* @param {number} daySpacing
* @returns {object}
*/
const CalendarLayout = ({
width,
height,
from,
to,
data,
direction,
colorScale,
emptyColor,
yearSpacing,
daySpacing,
}) => {
// time related data
export const computeLayout = ({ width, height, from, to, direction, yearSpacing, daySpacing }) => {
const fromDate = isDate(from) ? from : new Date(from)
const toDate = isDate(to) ? to : new Date(to)

Expand All @@ -225,10 +208,6 @@ const CalendarLayout = ({
yearRange.map(year => timeWeeks(new Date(year, 0, 1), new Date(year + 1, 0, 1)).length)
) + 1

// ——————————————————————————————————————————————————————————————————————————————————————————————————————
// Computes years/months/days
// ——————————————————————————————————————————————————————————————————————————————————————————————————————
// compute cellSize
const cellSize = computeCellSize({
width,
height,
Expand All @@ -239,7 +218,6 @@ const CalendarLayout = ({
maxWeeks,
})

// determine day cells positioning function according to layout direction
let cellPosition
if (direction === DIRECTION_HORIZONTAL) {
cellPosition = cellPositionHorizontal(cellSize, yearSpacing, daySpacing)
Expand Down Expand Up @@ -295,22 +273,28 @@ const CalendarLayout = ({
})
})

// ——————————————————————————————————————————————————————————————————————————————————————————————————————
// Computes days/data intersection
// ——————————————————————————————————————————————————————————————————————————————————————————————————————
//const color = scalePropToD3Scale(colorScale)
return { years, months, days, cellSize }
}

days.forEach(day => {
/**
* Bind current data to computed day cells.
*
* @param {array} days
* @param {array} data
* @param {object} colorScale
* @param {string} emptyColor
* @returns {Array}
*/
export const bindDaysData = ({ days, data, colorScale, emptyColor }) => {
return days.map(day => {
day.color = emptyColor
data.forEach(dataDay => {
if (dataDay.day === day.day) {
day.value = dataDay.value
day.color = colorScale(dataDay.value)
}
})
})

return { years, months, days, cellSize }
return day
})
}

export default CalendarLayout
31 changes: 30 additions & 1 deletion packages/calendar/src/enhance.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import pure from 'recompose/pure'
import { scaleQuantize } from 'd3-scale'
import { withTheme, withDimensions } from '@nivo/core'
import { CalendarDefaultProps } from './props'
import { computeDomain } from './computeCalendar'
import { computeDomain, computeLayout, bindDaysData } from './computeCalendar'

export default Component =>
compose(
Expand All @@ -32,5 +32,34 @@ export default Component =>
return { colorScale }
}
),
withPropsOnChange(
['width', 'height', 'from', 'to', 'direction', 'yearSpacing', 'daySpacing'],
({ width, height, from, to, direction, yearSpacing, daySpacing }) => {
const { years, months, days } = computeLayout({
width,
height,
from,
to,
direction,
yearSpacing,
daySpacing,
})

return { years, months, days }
}
),
withPropsOnChange(
['days', 'data', 'colorScale', 'emptyColor'],
({ days, data, colorScale, emptyColor }) => {
return {
days: bindDaysData({
days,
data,
colorScale,
emptyColor,
}),
}
}
),
pure
)(Component)
2 changes: 2 additions & 0 deletions packages/calendar/src/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const CalendarPropTypes = {

yearLegend: PropTypes.func.isRequired,
yearSpacing: PropTypes.number.isRequired,
yearLegendPosition: PropTypes.oneOf(['before', 'after']).isRequired,
yearLegendOffset: PropTypes.number.isRequired,

monthLegend: PropTypes.func.isRequired,
Expand Down Expand Up @@ -70,6 +71,7 @@ export const CalendarDefaultProps = {

yearLegend: year => year,
yearSpacing: 30,
yearLegendPosition: 'before',
yearLegendOffset: 10,

monthLegend: (year, month, date) => monthLabelFormat(date),
Expand Down
5 changes: 3 additions & 2 deletions website/src/components/charts/calendar/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ const Tooltip = data => {
/* return custom tooltip */
}

const colors = ['#61cdbb', '#97e3d5', '#e8c1a0', '#f47560']

export default class Calendar extends Component {
state = {
data: [],
settings: {
from: '2015-03-01',
to: '2016-07-12',

emptyColor: '#eeeeee',
colors: ['#61cdbb', '#97e3d5', '#e8c1a0', '#f47560'],
colors,
minValue: 0,
maxValue: 'auto',

Expand Down
5 changes: 4 additions & 1 deletion website/src/lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ export const settingsMapper = (mapping, { exclude = [] } = {}) => (settings, opt
}
})

return Object.assign({}, omit(settings, exclude), overrides)
return {
...omit(settings, exclude),
...overrides,
}
}

export const mapInheritedColor = ({ type, ...config }) => {
Expand Down

0 comments on commit 5aa0ff5

Please sign in to comment.