Skip to content

Commit

Permalink
Merge pull request #132 from Anchor-Protocol/fix/chart-theme-convert
Browse files Browse the repository at this point in the history
Fix: chart theme error at theme switching
  • Loading branch information
Seo Yeon, Lee authored Jun 1, 2021
2 parents 999347f + bdbf213 commit 24abb85
Show file tree
Hide file tree
Showing 5 changed files with 570 additions and 546 deletions.
362 changes: 182 additions & 180 deletions landing/src/pages/market/components/ANCPriceChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,207 +6,209 @@ import {
} from '@terra-dev/styled-neumorphism';
import big from 'big.js';
import { Chart } from 'chart.js';
import React, { useEffect, useRef } from 'react';
import styled, { useTheme } from 'styled-components';
import React, { Component, createRef } from 'react';
import styled, { DefaultTheme } from 'styled-components';
import { ChartTooltip } from './ChartTooltip';
import { mediumDay, xTimestampAixs } from './internal/axisUtils';

export interface ANCPriceChartProps {
data: MarketAncHistory[] | null | undefined;
data: MarketAncHistory[];
theme: DefaultTheme;
}

export function ANCPriceChart({ data }: ANCPriceChartProps) {
const theme = useTheme();

const canvasRef = useRef<HTMLCanvasElement | null>(null);
const tooltipRef = useRef<HTMLDivElement | null>(null);
const chartRef = useRef<Chart | null>(null);

const dataRef = useRef(data);

useEffect(() => {
dataRef.current = data;
}, [data]);

useEffect(() => {
if (chartRef.current) {
if (data) {
const chart = chartRef.current;
chart.data.labels = xTimestampAixs(
data.map(({ timestamp }) => timestamp),
);
chart.data.datasets[0].data = data.map(({ anc_price }) =>
big(anc_price).toNumber(),
);
chart.update();
export class ANCPriceChart extends Component<ANCPriceChartProps> {
private canvasRef = createRef<HTMLCanvasElement>();
private tooltipRef = createRef<HTMLDivElement>();
private chart!: Chart;

render() {
return (
<Container>
<canvas ref={this.canvasRef} />
<ChartTooltip ref={this.tooltipRef}>
<hr />
<section>
<div />
</section>
</ChartTooltip>
</Container>
);
}

componentWillUnmount() {
this.chart.destroy();
}

shouldComponentUpdate(nextProps: Readonly<ANCPriceChartProps>): boolean {
return (
this.props.data !== nextProps.data || this.props.theme !== nextProps.theme
);
}

componentDidMount() {
this.createChart();
}

componentDidUpdate(prevProps: Readonly<ANCPriceChartProps>) {
if (prevProps.data !== this.props.data) {
this.chart.data.labels = xTimestampAixs(
this.props.data.map(({ timestamp }) => timestamp),
);
this.chart.data.datasets[0].data = this.props.data.map(({ anc_price }) =>
big(anc_price).toNumber(),
);
}

if (prevProps.theme !== this.props.theme) {
if (this.chart.options.scales?.x?.ticks) {
this.chart.options.scales.x.ticks.color = this.props.theme.dimTextColor;
}
} else {
chartRef.current = new Chart(canvasRef.current!, {
type: 'line',
plugins: [
{
id: 'custom-y-axis-draw',
afterDraw(chart) {
const ctx = chart.ctx;
ctx.save();
ctx.globalCompositeOperation = 'destination-over';

const xScale = chart.scales.x;
const yScale = chart.scales.y;

let i: number = yScale.ticks.length;

while (--i >= 0) {
const y = yScale.getPixelForTick(i);
ctx.strokeStyle = rulerShadowColor({
intensity: theme.intensity,
color: theme.backgroundColor,
});
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(xScale.left, y);
ctx.lineTo(xScale.right, y);
ctx.stroke();
ctx.strokeStyle = rulerLightColor({
intensity: theme.intensity,
color: theme.backgroundColor,
});
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(xScale.left, y + 1);
ctx.lineTo(xScale.right, y + 1);
ctx.stroke();
if (this.chart.options.scales?.y?.ticks) {
this.chart.options.scales.y.ticks.color = this.props.theme.dimTextColor;
}
this.chart.data.datasets[0].borderColor =
this.props.theme.colors.positive;
}

this.chart.update();
}

private createChart = () => {
this.chart = new Chart(this.canvasRef.current!, {
type: 'line',
plugins: [
{
id: 'custom-y-axis-draw',
afterDraw: (chart) => {
const ctx = chart.ctx;
ctx.save();
ctx.globalCompositeOperation = 'destination-over';

const xScale = chart.scales.x;
const yScale = chart.scales.y;

let i: number = yScale.ticks.length;

while (--i >= 0) {
const y = yScale.getPixelForTick(i);
ctx.strokeStyle = rulerShadowColor({
intensity: this.props.theme.intensity,
color: this.props.theme.backgroundColor,
});
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(xScale.left, y);
ctx.lineTo(xScale.right, y);
ctx.stroke();
ctx.strokeStyle = rulerLightColor({
intensity: this.props.theme.intensity,
color: this.props.theme.backgroundColor,
});
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(xScale.left, y + 1);
ctx.lineTo(xScale.right, y + 1);
ctx.stroke();
}
ctx.restore();
},
},
],
options: {
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,

external: ({ chart, tooltip }) => {
let element = this.tooltipRef.current!;

if (tooltip.opacity === 0) {
element.style.opacity = '0';
return;
}

const div1 = element.querySelector('div:nth-child(1)');
const hr = element.querySelector('hr');

if (div1) {
try {
const i = tooltip.dataPoints[0].dataIndex;
const isLast = i === this.props.data.length - 1;
const item = this.props.data[i];
const price = formatUSTWithPostfixUnits(item.anc_price);
const date = isLast ? 'Now' : mediumDay(item.timestamp);
div1.innerHTML = `${price} UST <span>${date}</span>`;
} catch {}
}
ctx.restore();

if (hr) {
hr.style.top = chart.scales.y.paddingTop + 'px';
hr.style.height = chart.scales.y.height + 'px';
}

element.style.opacity = '1';
element.style.transform = `translateX(${tooltip.caretX}px)`;
},
},
],
options: {
maintainAspectRatio: false,
plugins: {
legend: {
},
interaction: {
intersect: false,
mode: 'index',
},
scales: {
x: {
grid: {
display: false,
},
tooltip: {
enabled: false,

external({ chart, tooltip }) {
let element = tooltipRef.current!;

if (tooltip.opacity === 0) {
element.style.opacity = '0';
return;
}

const div1 = element.querySelector('div:nth-child(1)');
const hr = element.querySelector('hr');

if (div1) {
try {
const i = tooltip.dataPoints[0].dataIndex;
const isLast = i === dataRef.current!.length - 1;
const item = dataRef.current![i];
const price = formatUSTWithPostfixUnits(item.anc_price);
const date = isLast ? 'Now' : mediumDay(item.timestamp);
div1.innerHTML = `${price} UST <span>${date}</span>`;
} catch {}
}

if (hr) {
hr.style.top = chart.scales.y.paddingTop + 'px';
hr.style.height = chart.scales.y.height + 'px';
}

element.style.opacity = '1';
element.style.transform = `translateX(${tooltip.caretX}px)`;
ticks: {
autoSkip: false,
maxRotation: 0,
font: {
size: 11,
},
color: this.props.theme.dimTextColor,
},
},
interaction: {
intersect: false,
mode: 'index',
},
scales: {
x: {
grid: {
display: false,
},
ticks: {
autoSkip: false,
maxRotation: 0,
font: {
size: 11,
},
color: theme.dimTextColor,
},
y: {
grace: '25%',
grid: {
display: false,
drawBorder: false,
},
y: {
grace: '25%',
grid: {
display: false,
drawBorder: false,
},
ticks: {
font: {
size: 11,
},
color: theme.dimTextColor,
ticks: {
font: {
size: 11,
},
},
},
elements: {
point: {
radius: 0,
color: this.props.theme.dimTextColor,
},
},
},
data: {
labels: data
? xTimestampAixs(data.map(({ timestamp }) => timestamp))
: [],
datasets: [
{
data:
data?.map(({ anc_price }) => big(anc_price).toNumber()) ?? [],
borderColor: theme.colors.positive,
borderWidth: 2,
},
],
elements: {
point: {
radius: 0,
},
},
});
}

if (process.env.NODE_ENV === 'development') {
return () => {
chartRef.current?.destroy();
chartRef.current = null;
};
}
}, [
data,
theme.backgroundColor,
theme.colors.positive,
theme.dimTextColor,
theme.intensity,
]);

useEffect(() => {
return () => {
chartRef.current?.destroy();
};
}, []);

return (
<Container>
<canvas ref={canvasRef} />
<ChartTooltip ref={tooltipRef}>
<hr />
<section>
<div />
</section>
</ChartTooltip>
</Container>
);
},
data: {
labels: xTimestampAixs(
this.props.data.map(({ timestamp }) => timestamp),
),
datasets: [
{
data: this.props.data.map(({ anc_price }) =>
big(anc_price).toNumber(),
),
borderColor: this.props.theme.colors.positive,
borderWidth: 2,
},
],
},
});
};
}

const Container = styled.div`
Expand Down
Loading

1 comment on commit 24abb85

@vercel
Copy link

@vercel vercel bot commented on 24abb85 Jun 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.