Skip to content

Commit

Permalink
feat(bar): add custom renderer support
Browse files Browse the repository at this point in the history
  • Loading branch information
wyze committed Jun 28, 2021
1 parent c39e91f commit 459e74c
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 44 deletions.
126 changes: 82 additions & 44 deletions packages/bar/src/BarCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { BarCanvasLayer, BarCanvasProps, BarDatum, ComputedBarDatum } from './types'
import {
BarCanvasLayer,
BarCanvasProps,
BarDatum,
ComputedBarDatum,
ComputedBarDatumWithValue,
} from './types'
import {
Container,
Margin,
Expand Down Expand Up @@ -87,7 +93,61 @@ const InnerBarCanvas = <RawDatum extends BarDatum>({
gridYValues,

layers = canvasDefaultProps.layers as BarCanvasLayer<RawDatum>[],
// barComponent = svgDefaultProps.barComponent,
renderBar = (
ctx,
{
borderColor,
borderRadius,
borderWidth,
color,
height,
label,
labelColor,
shouldRenderLabel,
width,
x,
y,
}
) => {
ctx.fillStyle = color

if (borderWidth > 0) {
ctx.strokeStyle = borderColor
ctx.lineWidth = borderWidth
}

ctx.beginPath()

if (borderRadius > 0) {
const radius = Math.min(borderRadius, height)

ctx.moveTo(x + radius, y)
ctx.lineTo(x + width - radius, y)
ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
ctx.lineTo(x + width, y + height - radius)
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
ctx.lineTo(x + radius, y + height)
ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
ctx.lineTo(x, y + radius)
ctx.quadraticCurveTo(x, y, x + radius, y)
ctx.closePath()
} else {
ctx.rect(x, y, width, height)
}

ctx.fill()

if (borderWidth > 0) {
ctx.stroke()
}

if (shouldRenderLabel) {
ctx.textBaseline = 'middle'
ctx.textAlign = 'center'
ctx.fillStyle = labelColor
ctx.fillText(label, x + width / 2, y + height / 2)
}
},

enableLabel = canvasDefaultProps.enableLabel,
label = canvasDefaultProps.label,
Expand Down Expand Up @@ -171,6 +231,14 @@ const InnerBarCanvas = <RawDatum extends BarDatum>({
[keys, result.bars]
)

const barsWithValue = useMemo(
() =>
result.bars.filter(
(bar): bar is ComputedBarDatumWithValue<RawDatum> => bar.data.value !== null
),
[result.bars]
)

const shouldRenderLabel = useCallback(
({ width, height }: { height: number; width: number }) => {
if (!enableLabel) return false
Expand Down Expand Up @@ -294,47 +362,16 @@ const InnerBarCanvas = <RawDatum extends BarDatum>({
theme,
})
} else if (layer === 'bars') {
result.bars.forEach(bar => {
const { x, y, color, width, height } = bar

ctx.fillStyle = color

if (borderWidth > 0) {
ctx.strokeStyle = getBorderColor(bar)
ctx.lineWidth = borderWidth
}

ctx.beginPath()

if (borderRadius > 0) {
const radius = Math.min(borderRadius, height)

ctx.moveTo(x + radius, y)
ctx.lineTo(x + width - radius, y)
ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
ctx.lineTo(x + width, y + height - radius)
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
ctx.lineTo(x + radius, y + height)
ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
ctx.lineTo(x, y + radius)
ctx.quadraticCurveTo(x, y, x + radius, y)
ctx.closePath()
} else {
ctx.rect(x, y, width, height)
}

ctx.fill()

if (borderWidth > 0) {
ctx.stroke()
}

if (shouldRenderLabel({ height, width })) {
ctx.textBaseline = 'middle'
ctx.textAlign = 'center'
ctx.fillStyle = getLabelColor(bar)
ctx.fillText(getLabel(bar.data), x + width / 2, y + height / 2)
}
barsWithValue.forEach(bar => {
renderBar(ctx, {
...bar,
borderColor: getBorderColor(bar),
borderRadius,
borderWidth,
label: getLabel(bar.data),
labelColor: getLabelColor(bar),
shouldRenderLabel: shouldRenderLabel(bar),
})
})
} else if (layer === 'legends') {
legends.forEach(legend => {
Expand Down Expand Up @@ -369,6 +406,7 @@ const InnerBarCanvas = <RawDatum extends BarDatum>({
axisLeft,
axisRight,
axisTop,
barsWithValue,
borderRadius,
borderWidth,
boundAnnotations,
Expand All @@ -394,7 +432,7 @@ const InnerBarCanvas = <RawDatum extends BarDatum>({
outerHeight,
outerWidth,
pixelRatio,
result.bars,
renderBar,
result.xScale,
result.yScale,
reverse,
Expand Down
7 changes: 7 additions & 0 deletions packages/bar/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ export interface BarItemProps<RawDatum>
data: ComputedBarDatum<RawDatum>['data'] & { value: number }
}

export type RenderBarProps<RawDatum> = Omit<
BarItemProps<RawDatum>,
'style' | 'getTooltipLabel' | 'isInteractive' | 'tooltip'
>

export interface BarTooltipProps<RawDatum> extends ComputedDatum<RawDatum> {
color: string
getTooltipLabel: (datum: ComputedDatum<RawDatum>) => string | number
Expand Down Expand Up @@ -255,6 +260,8 @@ export type BarCanvasProps<RawDatum extends BarDatum> = Partial<BarCommonProps<R
axisRight: CanvasAxisProp<any>
axisTop: CanvasAxisProp<any>

renderBar: (context: CanvasRenderingContext2D, props: RenderBarProps<RawDatum>) => void

layers: BarCanvasLayer<RawDatum>[]
pixelRatio: number
}>
Expand Down
22 changes: 22 additions & 0 deletions packages/bar/stories/barCanvas.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ stories.add('custom layer', () => {
)
})

stories.add('custom bar renderer', () => (
<BarCanvas
{...commonProps}
innerPadding={4}
renderBar={(ctx, { x, y, width, height, color }) => {
ctx.beginPath()

ctx.fillStyle = color

ctx.arc(
x + width / 2,
y + height / 2,
Math.abs(Math.min(width, height) / 2),
0,
2 * Math.PI
)

ctx.fill()
}}
/>
))

stories.add('custom tooltip', () => (
<BarCanvas
{...commonProps}
Expand Down

0 comments on commit 459e74c

Please sign in to comment.