wykrestest
Version:
Candlestick Chart made with Konva, React and Jotai
89 lines (88 loc) • 3.5 kB
JavaScript
import { useRef } from 'react';
import { atom } from 'jotai';
import { highLowFunc, winSizeFunc, maxXFunc, winPosFunc } from './utils/utils';
import { checkBoundry } from './utils/utils';
export const mainStageAtom = atom(() => useRef(null));
export const gapAtom = atom(4);
export const dragAtom = atom(false); //used in chart and main as link..can be prop but w/e
export const maxXAtom = atom(0);
export const winSizeAtom = atom(200);
export const winCountAtom = atom((get) => get(dataLengthAtom) / get(winSizeAtom));
export const winHLAtom = atom({ high: 0, low: 0, diff: 0 });
//-------------------------------------DIMS
export const heightAtom = atom(500);
export const widthAtom = atom(500);
const padding = atom(30);
export const dimsAtom = atom(get => {
return {
height: get(heightAtom),
width: get(widthAtom),
heightSub: get(heightAtom) - get(padding),
widthSub: get(widthAtom) - get(padding),
};
}, (_, set, arg) => {
set(heightAtom, arg.height);
set(widthAtom, arg.width);
});
//-------------------------------------
//---------------------------dataStore------------------
export const dataAtom = atom([{ high: 0, low: 0, open: 0, close: 0, api_date: '' }]);
export const dataLengthAtom = atom((get) => get(dataAtom).length);
export const dataHLAtom = atom((get) => highLowFunc(get(dataAtom)));
export const dataStoreAtom = atom((get) => {
return {
data: get(dataAtom),
dataLength: get(dataLengthAtom),
dataHL: get(dataHLAtom)
};
}, (get, set, arg) => {
const newMaxX = maxXFunc(arg.length, get(winSizeAtom), get(gapAtom), get(scaleXAtom));
set(dataAtom, arg);
set(xAtom, newMaxX);
set(maxXAtom, newMaxX);
});
//-------------------------------------------------------
//-------------------------------Konva Positions ---------------
export const xAtom = atom(0, (get, set, arg) => {
const winPos = winPosFunc(arg, get(gapAtom), get(scaleXAtom));
const subData = get(dataAtom).slice(winPos, winPos + get(winSizeAtom));
const winHL = highLowFunc(subData);
set(xAtom, arg);
set(winHLAtom, winHL);
});
//not a huge fan but it works...we can probably move the event part and the newX part out if we want to
//but idk how much cleaner/easier to understand that would make it...had issues with jumpyness since react set was slow i think
export const scaleXAtom = atom(1, (get, set, e) => {
//random
const getX = (newScaleX) => {
const mp = get(mainStageAtom).current.getPointerPosition();
const pointTo = (mp.x - get(xAtom)) / get(scaleXAtom);
const newX = (mp.x - (pointTo * newScaleX));
return { x: newX, y: get(yAtom) };
};
//mid/end
const zoom = (newScaleX) => {
const pos = getX(newScaleX);
const ws = winSizeFunc(get(widthAtom) - get(padding), get(gapAtom), newScaleX);
const maxX = maxXFunc(get(dataLengthAtom), ws, get(gapAtom), newScaleX);
const newPos = checkBoundry(pos, maxX);
set(scaleXAtom, newScaleX);
set(maxXAtom, maxX);
set(winSizeAtom, ws);
set(xAtom, newPos.x);
};
//pt1
if (e.evt.wheelDelta > 0) {
if (get(scaleXAtom) < 2) {
zoom(get(scaleXAtom) + .25);
}
}
else {
if (get(scaleXAtom) > .5) {
zoom(get(scaleXAtom) - .25);
}
}
});
export const yAtom = atom(0);
export const scaleYAtom = atom(1);
//---------------------------------------------------------------