mirror of https://github.com/certusone/oyster.git
feat: chart.js changes
This commit is contained in:
parent
94762b0763
commit
f40a37582f
|
@ -2301,6 +2301,14 @@
|
|||
"base-x": "^3.0.6"
|
||||
}
|
||||
},
|
||||
"@types/chart.js": {
|
||||
"version": "2.9.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.29.tgz",
|
||||
"integrity": "sha512-WOZMitUU3gHDM0oQsCsVivX+oDsIki93szcTmmUPBm39cCvAELBjokjSDVOoA3xiIEbb+jp17z/3S2tIqruwOQ==",
|
||||
"requires": {
|
||||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"@types/color-name": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
|
@ -4320,6 +4328,11 @@
|
|||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"chartjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmjs.org/chartjs/-/chartjs-0.3.24.tgz",
|
||||
"integrity": "sha1-Ot3rWuNgaz6J40bCfVLKFYQW6T0="
|
||||
},
|
||||
"chartjs-color": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"@types/chart.js": "^2.9.29",
|
||||
"@types/echarts": "^4.9.0",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"antd": "^4.6.6",
|
||||
|
@ -27,7 +28,6 @@
|
|||
"jazzicon": "^1.5.0",
|
||||
"lodash": "^4.17.20",
|
||||
"react": "^16.13.1",
|
||||
"react-chartjs-2": "^2.11.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-github-btn": "^1.2.0",
|
||||
"react-intl": "^5.10.2",
|
||||
|
|
|
@ -108,7 +108,7 @@ export const AppLayout = (props: any) => {
|
|||
<Menu.Item key="6" icon={< LineChartOutlined/>}>
|
||||
<Link
|
||||
to={{
|
||||
pathname: "/marginTrading",
|
||||
pathname: "/margin",
|
||||
}}
|
||||
>
|
||||
{LABELS.MARGIN_TRADING}
|
||||
|
|
|
@ -233,7 +233,7 @@ export const useEnrichedPools = (pools: PoolInfo[]) => {
|
|||
const poolKeys = pools.map((p) => p.pubkeys.account.toBase58()).join(',');
|
||||
|
||||
useEffect(() => {
|
||||
if (!marketEmitter || !subscribeToMarket || pools.length == 0) {
|
||||
if (!marketEmitter || !subscribeToMarket || pools.length === 0) {
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
|
|
|
@ -47,9 +47,9 @@ export function Routes() {
|
|||
<Route path='/repay/:reserve' children={<RepayReserveView />} />
|
||||
<Route exact path='/liquidate' children={<LiquidateView />} />
|
||||
<Route path='/liquidate/:id' children={<LiquidateReserveView />} />
|
||||
<Route exact path='/marginTrading' children={<MarginTrading />} />
|
||||
<Route exact path='/margin' children={<MarginTrading />} />
|
||||
|
||||
<Route path='/marginTrading/:id' children={<NewPosition />} />
|
||||
<Route path='/margin/:id' children={<NewPosition />} />
|
||||
<Route exact path='/faucet' children={<FaucetView />} />
|
||||
</Switch>
|
||||
</AppLayout>
|
||||
|
|
|
@ -16,7 +16,7 @@ export const MarginTradeItem = (props: { reserve: LendingReserve; address: Publi
|
|||
const apr = calculateBorrowAPY(props.reserve);
|
||||
|
||||
return (
|
||||
<Link to={`/marginTrading/${props.address.toBase58()}`}>
|
||||
<Link to={`/margin/${props.address.toBase58()}`}>
|
||||
<div className='choose-margin-item'>
|
||||
<span style={{ display: 'flex' }}>
|
||||
<TokenIcon mintAddress={props.reserve.liquidityMint} />
|
||||
|
|
|
@ -57,7 +57,7 @@ export default function Breakdown({ item }: { item: Position }) {
|
|||
<div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center' }}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title='Leverage'
|
||||
title='Borrowed'
|
||||
value={brokeragePart * exchangeRate}
|
||||
precision={2}
|
||||
valueStyle={{ color: brokerageColor }}
|
||||
|
@ -66,7 +66,7 @@ export default function Breakdown({ item }: { item: Position }) {
|
|||
</Card>
|
||||
<Card>
|
||||
<Statistic
|
||||
title='My Collateral Value'
|
||||
title='My Collateral'
|
||||
value={myPart}
|
||||
precision={2}
|
||||
valueStyle={{ color: myColor }}
|
||||
|
@ -101,14 +101,6 @@ export default function Breakdown({ item }: { item: Position }) {
|
|||
}}
|
||||
style={{ marginBottom: '20px' }}
|
||||
/>
|
||||
<span style={{ float: 'right', fontSize: '9px' }}>
|
||||
<a
|
||||
href='https://github.com/bZxNetwork/fulcrum_ui/blob/development/packages/fulcrum-website/assets/js/trading.js'
|
||||
target='blank'
|
||||
>
|
||||
credit
|
||||
</a>
|
||||
</span>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import Chart, { ChartPluginsOptions } from "chart.js";
|
||||
import { Position } from './interfaces';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
// Special thanks to
|
||||
// https://github.com/bZxNetwork/fulcrum_ui/blob/development/packages/fulcrum-website/assets/js/trading.js
|
||||
|
@ -61,24 +60,11 @@ const baseData = [
|
|||
{ x: 50, y: 65 },
|
||||
];
|
||||
|
||||
function getChartData({ item, priceChange }: { item: Position; priceChange: number }) {
|
||||
function getChartData() {
|
||||
//the only way to create an immutable copy of array with objects inside.
|
||||
const baseDashed = JSON.parse(JSON.stringify(baseData.slice(Math.floor(baseData.length) / 2)));
|
||||
const baseDashed = getBaseDashed();
|
||||
const baseSolid = JSON.parse(JSON.stringify(baseData.slice(0, Math.floor(baseData.length) / 2 + 1)));
|
||||
|
||||
const leverage = item.leverage;
|
||||
|
||||
baseDashed.forEach((item: { y: number; x: number }, index: number) => {
|
||||
if (index !== 0) item.y += (item.y * priceChange) / 100;
|
||||
});
|
||||
var leverageData = baseDashed.map((item: { x: number; y: number }, index: number) => {
|
||||
if (index === 0) {
|
||||
return { x: item.x, y: item.y };
|
||||
}
|
||||
const gain = (priceChange * leverage) / 100;
|
||||
return { x: item.x, y: item.y * (1 + gain) };
|
||||
});
|
||||
|
||||
return {
|
||||
datasets: [
|
||||
{
|
||||
|
@ -90,10 +76,10 @@ function getChartData({ item, priceChange }: { item: Position; priceChange: numb
|
|||
},
|
||||
{
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: priceChange >= 0 ? 'rgb(51, 223, 204)' : 'rgb(255,79,79)',
|
||||
|
||||
borderWidth: 4,
|
||||
radius: 0,
|
||||
data: leverageData,
|
||||
data: baseDashed,
|
||||
borderDash: [15, 3],
|
||||
label: 'LEVERAGE',
|
||||
},
|
||||
|
@ -110,139 +96,167 @@ function getChartData({ item, priceChange }: { item: Position; priceChange: numb
|
|||
};
|
||||
}
|
||||
|
||||
const labelPlugin: ChartPluginsOptions = {};
|
||||
|
||||
const getBaseDashed = () => {
|
||||
return JSON.parse(JSON.stringify(baseData.slice(Math.floor(baseData.length) / 2))) as { x: number, y: number }[];
|
||||
}
|
||||
|
||||
function updateChartData({
|
||||
item,
|
||||
priceChange,
|
||||
chartRef,
|
||||
chart,
|
||||
}: {
|
||||
item: Position;
|
||||
priceChange: number;
|
||||
chartRef: React.RefObject<any>;
|
||||
chart: Chart;
|
||||
}) {
|
||||
const data = getChartData({ item, priceChange });
|
||||
chartRef.current.chartInstance.data = data;
|
||||
chartRef.current.chartInstance.canvas.parentNode.style.width = '100%';
|
||||
chartRef.current.chartInstance.canvas.parentNode.style.height = 'auto';
|
||||
chartRef.current.chartInstance.update();
|
||||
if (!chart?.data.datasets || chart?.data.datasets.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
labelPlugin.afterDraw = (instance: Chart) => {
|
||||
drawLabels(instance, item.leverage, priceChange)
|
||||
};
|
||||
|
||||
const baseDashed = getBaseDashed();
|
||||
const leverage = item.leverage;
|
||||
var leverageData = baseDashed.map((item: { x: number; y: number }, index: number) => {
|
||||
if (index === 0) {
|
||||
return { x: item.x, y: item.y };
|
||||
}
|
||||
const gain = (priceChange * leverage) / 100;
|
||||
return { x: item.x, y: item.y * (1 + gain) };
|
||||
});
|
||||
|
||||
chart.data.datasets[1].data = leverageData;
|
||||
chart.data.datasets[1].borderColor = priceChange >= 0 ? 'rgb(51, 223, 204)' : 'rgb(255,79,79)';
|
||||
|
||||
baseDashed.forEach((item: { y: number; x: number }, index: number) => {
|
||||
if (index !== 0) item.y += (item.y * priceChange) / 100;
|
||||
});
|
||||
|
||||
chart.data.datasets[2].data = baseDashed;
|
||||
|
||||
// chart.chartInstance.canvas.parentNode.style.width = '100%';
|
||||
// chart.chartInstance.canvas.parentNode.style.height = 'auto';
|
||||
chart?.update()
|
||||
}
|
||||
|
||||
function drawLabels(t: any, ctx: any, leverage: number, priceChange: number) {
|
||||
function drawLabels(chart: Chart, leverage: number, priceChange: number) {
|
||||
if (!chart.config || !chart.config.data || !chart.config.data.datasets || !chart.canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = chart.ctx;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.font = 'normal normal bold 15px /1.5 Muli';
|
||||
ctx.textBaseline = 'bottom';
|
||||
|
||||
const chartInstance = t.chart;
|
||||
const datasets = chartInstance.config.data.datasets;
|
||||
datasets.forEach(function (ds: { label: any; borderColor: any }, index: number) {
|
||||
const datasets = chart.config.data.datasets;
|
||||
const element = (chart?.canvas?.parentNode as HTMLElement);
|
||||
datasets.forEach((ds, index) => {
|
||||
const label = ds.label;
|
||||
ctx.fillStyle = ds.borderColor;
|
||||
ctx.fillStyle = ds.borderColor as string;
|
||||
|
||||
const meta = chartInstance.controller.getDatasetMeta(index);
|
||||
const meta = chart.getDatasetMeta(index);
|
||||
const len = meta.data.length - 1;
|
||||
const pointPostition = Math.floor(len / 2) - Math.floor(0.2 * len);
|
||||
const x = meta.data[pointPostition]._model.x;
|
||||
const xOffset = x;
|
||||
const y = meta.data[pointPostition]._model.y;
|
||||
let yOffset;
|
||||
|
||||
if (label === 'HOLD') {
|
||||
yOffset = leverage * priceChange > 0 ? y * 1.2 : y * 0.8;
|
||||
} else {
|
||||
yOffset = leverage * priceChange > 0 ? y * 0.8 : y * 1.2;
|
||||
}
|
||||
|
||||
if (yOffset > chartInstance.canvas.parentNode.offsetHeight) {
|
||||
if (yOffset > element.offsetHeight) {
|
||||
// yOffset = 295;
|
||||
chartInstance.canvas.parentNode.style.height = `${yOffset * 1.3}px`;
|
||||
element.style.height = `${yOffset * 1.3}px`;
|
||||
}
|
||||
if (yOffset < 0) yOffset = 5;
|
||||
if (label) ctx.fillText(label, xOffset, yOffset);
|
||||
});
|
||||
ctx.restore();
|
||||
}
|
||||
const debouncedUpdateChartData = debounce(updateChartData, 200);
|
||||
|
||||
export default function GainsChart({ item, priceChange }: { item: Position; priceChange: number }) {
|
||||
const chartRef = useRef<any>();
|
||||
const [booted, setBooted] = useState<boolean>(false);
|
||||
const [canvas, setCanvas] = useState<any>();
|
||||
useEffect(() => {
|
||||
if (chartRef.current.chartInstance) debouncedUpdateChartData({ item, priceChange, chartRef });
|
||||
}, [priceChange, item.leverage]);
|
||||
const chartRef = useRef<Chart>();
|
||||
const canvasRef = useRef<HTMLCanvasElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (chartRef.current && !booted && canvas) {
|
||||
//@ts-ignore
|
||||
const originalController = window.Chart.controllers.line;
|
||||
//@ts-ignore
|
||||
window.Chart.controllers.line = Chart.controllers.line.extend({
|
||||
draw: function () {
|
||||
originalController.prototype.draw.call(this, arguments);
|
||||
drawLabels(this, canvas.getContext('2d'), item.leverage, priceChange);
|
||||
},
|
||||
});
|
||||
setBooted(true);
|
||||
if (!canvasRef.current || chartRef.current) {
|
||||
return;
|
||||
}
|
||||
}, [chartRef, canvas]);
|
||||
|
||||
const chart = useMemo(
|
||||
() => (
|
||||
<Line
|
||||
ref={chartRef}
|
||||
data={(canvas: any) => {
|
||||
setCanvas(canvas);
|
||||
return getChartData({ item, priceChange });
|
||||
}}
|
||||
options={{
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
scaleShowLabels: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 30,
|
||||
bottom: 80,
|
||||
chartRef.current = new Chart(canvasRef.current, {
|
||||
type: 'line',
|
||||
data: getChartData(),
|
||||
plugins: [
|
||||
labelPlugin
|
||||
],
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
scaleShowLabels: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 30,
|
||||
bottom: 80,
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
render: 'title',
|
||||
fontColor: ['green', 'white', 'red'],
|
||||
precision: 2,
|
||||
},
|
||||
animation: {
|
||||
easing: 'easeOutExpo',
|
||||
duration: 500,
|
||||
},
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
display: false,
|
||||
gridLines: {
|
||||
display: false,
|
||||
},
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
render: 'title',
|
||||
fontColor: ['green', 'white', 'red'],
|
||||
precision: 2,
|
||||
},
|
||||
animation: {
|
||||
easing: 'easeOutExpo',
|
||||
duration: 500,
|
||||
},
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
gridLines: {
|
||||
display: false,
|
||||
gridLines: {
|
||||
display: false,
|
||||
},
|
||||
type: 'linear',
|
||||
position: 'bottom',
|
||||
},
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: false,
|
||||
gridLines: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
);
|
||||
},
|
||||
],
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
} as any
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (chartRef.current) {
|
||||
updateChartData({ item, priceChange, chart: chartRef.current });
|
||||
}
|
||||
}, [priceChange, item]);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'stretch', justifyContent: 'center' }}>
|
||||
{chart}
|
||||
<canvas ref={canvasRef as any} />
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
|
|
|
@ -13,7 +13,7 @@ export const NewPosition = () => {
|
|||
const lendingReserve = useLendingReserve(id);
|
||||
const [newPosition, setNewPosition] = useState<Position>({
|
||||
id: null,
|
||||
leverage: 1,
|
||||
leverage: 5,
|
||||
collateral: {},
|
||||
asset: {},
|
||||
});
|
||||
|
|
|
@ -72,5 +72,5 @@ export function useLeverage({
|
|||
return;
|
||||
}
|
||||
setNewPosition({ ...newPosition, error: '' });
|
||||
}, [collType, desiredType, desiredValue, leverage, enrichedPools, collValue, collateralDeposit?.info.amount]);
|
||||
}, [collType, desiredType, desiredValue, leverage, enrichedPools, collValue, collateralDeposit]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue