Skip to content

Commit

Permalink
Bars
Browse files Browse the repository at this point in the history
  • Loading branch information
rodion committed Jan 1, 2019
1 parent a50aba2 commit 5bfba81
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 5 deletions.
64 changes: 64 additions & 0 deletions src/components/bar-chart/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react'
import { sum } from '../../utils'

export default ({
bar,
index,
height,
barWidth,
barSpace,
centerBarIndex,
onBarSelect,
highest,
startIndex
}) => {
const barTotalWidth = barWidth + barSpace
const realIndex = index + startIndex
const x = barTotalWidth * index + barSpace

const valueToHeight = value => (value * height) / highest

const Subbar = ({ value, color, valueBefore }) => {
const rectHeight = valueToHeight(value)
const y = height - valueToHeight(valueBefore) - rectHeight

return (
<rect
opacity={realIndex === centerBarIndex ? 1 : 0.6}
x={x}
y={y}
width={barWidth}
height={height}
fill={color}
/>
)
}

const Selectable = () => (
<rect
onTouchEnd={e => {
onBarSelect(realIndex)
e.preventDefault()
}}
onClick={() => onBarSelect(realIndex)}
cursor={'pointer'}
x={x - barSpace / 2}
width={barTotalWidth}
y={0}
height={height}
fill={'transparent'}
/>
)

return (
<g>
{bar.map(({ value, color }, index) => {
const valueBefore = sum(bar.slice(0, index))
const props = { value, color, valueBefore, key: index }

return <Subbar {...props}/>
})}
{onBarSelect && <Selectable/>}
</g>
)
}
66 changes: 61 additions & 5 deletions src/components/bar-chart/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { DEFAULT_THEME } from '../../constants';

import DataContainer from './data-container'
import Scroller from './scroller'
import Bar from './bar'
import { sum } from '../../utils'

const RootContainer = styled.div`
height: 100%;
Expand All @@ -12,7 +14,7 @@ const RootContainer = styled.div`
flex-direction: column;
`

const BarsView = styled.div`
const BarsView = styled.svg`
height: 100%;
width: 100%;
`
Expand All @@ -34,11 +36,12 @@ export default class BarChart extends React.Component {
height: 0,
width: 0,
offset: 0,
oldOffset: 0
oldOffset: 0,
scrolling: false
}
}
render() {
const { theme, showScroller, barWidth, barSpace, bars } = this.props
const { theme, showScroller, barWidth, barSpace, bars, centerBarIndex, onBarSelect } = this.props
const { width, offset, oldOffset, height } = this.state

const barTotalWidth = barWidth + barSpace
Expand All @@ -52,7 +55,6 @@ export default class BarChart extends React.Component {
}

const startIndex = getStartIndex()
console.log(width, height)
const Content = () => {
if (!width) return null
const dataConainerProps = { barTotalWidth, width, offset, oldOffset, totalWidth, startIndex }
Expand All @@ -64,12 +66,31 @@ export default class BarChart extends React.Component {
</LabelsContainer>
)
}
const lastIndex = Math.ceil((totalWidth + oldOffset + (offset < oldOffset ? oldOffset - offset : 0)) / barTotalWidth)
const slicedBars = bars.slice(startIndex, lastIndex)
const highest = bars.map(b => b.items).reduce((acc, bar) => {
const height = sum(bar)
return height > acc ? height : acc
}, 0)

const Bars = () => {
if (!height) return null
const barCommonProps = { startIndex, height, barWidth, barSpace, centerBarIndex, onBarSelect, highest}
return slicedBars.map(({ items }, index) =>(
<Bar
{...barCommonProps}
bar={items}
index={index}
key={index}
/>
))
}

return (
<React.Fragment>
<DataContainer {...dataConainerProps}>
<BarsView ref={el => this.barsContainer = el}>

<Bars/>
</BarsView>
<Labels/>
</DataContainer>
Expand Down Expand Up @@ -109,4 +130,39 @@ export default class BarChart extends React.Component {
componentWillUnmount() {
window.removeEventListener('resize', this.onResize)
}

static getDerivedStateFromProps(nextProps, prevState) {
const { width, offset, scrolling } = prevState
if (!width) return null

const { centerBarIndex, barWidth, barSpace, bars } = nextProps
const bar = barWidth + barSpace
const totalWidth = bars.length * bar + barSpace
const getNewOffsets = () => {
if (centerBarIndex !== undefined && !scrolling) {
if (totalWidth < width) {
return {
oldOffset: 0,
offset: 0
}
}
const offsetToCenter = totalWidth - bar * centerBarIndex - (width + bar) / 2
const getOffset = () => {
if (offsetToCenter < 0) return 0
if (offsetToCenter + width > totalWidth) return totalWidth - width
return offsetToCenter
}

return {
offset: getOffset(),
oldOffset: offset
}
}
}
return {
...prevState,
...getNewOffsets(),
totalWidth
}
}
}

0 comments on commit 5bfba81

Please sign in to comment.