-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchartUtils.ts
More file actions
95 lines (87 loc) · 2.84 KB
/
Copy pathchartUtils.ts
File metadata and controls
95 lines (87 loc) · 2.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import {
inject,
provide,
readonly,
ref,
type InjectionKey,
type Ref,
} from 'vue';
import {
CHART_HEIGHT,
CHART_WIDTH,
MIN_WAVELENGTH,
Y_0_FROM_BOTTOM,
Y_RANGE,
} from '../constants';
export const pixelZoomFromZoom = (zoom: number): number => {
// The left side is always 0.2 microns. The right side, at zoom 1, is 0.95 microns.
// The chart drawing math assumes the chart to be 750 pixels wide.
// Therefore, each pixel is assumed to be 1 nanometer (at zoom 1).
// However, layout needs have moved the chart width away from 750.
// The "pixel zoom" adjusts the zoom to compensate for the ratio of the actual width vs 750.
const pixelsPerZ1Nm = CHART_WIDTH / 750;
const pixelZoom = pixelsPerZ1Nm * zoom;
return pixelZoom;
};
export const micronsFromXLoc = (xLoc: number, zoom: number): number => {
const pixelZoom = pixelZoomFromZoom(zoom);
const microns = xLoc * (1 / pixelZoom) * (1 / 1000) + MIN_WAVELENGTH;
return microns;
};
export const xLocFromMicrons = (microns: number, zoom: number): number => {
const pixelZoom = pixelZoomFromZoom(zoom);
const xLoc = (microns - MIN_WAVELENGTH) * pixelZoom * 1000;
return xLoc;
};
// The intensity axis is inverted due to canvas coordinates increasing top to bottom.
// That's normal for document order but backwards for graphs.
export const yLocFromIntensity = (intensity: number): number => {
const yFromBottom = intensity * Y_RANGE + Y_0_FROM_BOTTOM;
return CHART_HEIGHT - yFromBottom;
};
// Page-scoped "where is the cursor"
// Enables cursor positions linked between multiple charts
interface CursorMicronsWithUpdater {
cursorMicrons: Readonly<Ref<number | null>>;
setCursorMicrons: (newCursorMicrons: number | null) => void;
}
const cursorMicronsKey = Symbol(
'cursorMicrons',
) as InjectionKey<CursorMicronsWithUpdater>;
const createCursorMicronsWithUpdater = (): CursorMicronsWithUpdater => {
const cursorMicrons = ref<number | null>(null);
const setCursorMicrons = (newCursorMicrons: number | null): void => {
cursorMicrons.value = newCursorMicrons;
};
return {
cursorMicrons: readonly(cursorMicrons),
setCursorMicrons,
};
};
export const useCursorMicrons = (): CursorMicronsWithUpdater => {
let cursorMicronsWithUpdater = inject(cursorMicronsKey, null);
if (!cursorMicronsWithUpdater) {
cursorMicronsWithUpdater = createCursorMicronsWithUpdater();
provide(cursorMicronsKey, cursorMicronsWithUpdater);
}
return cursorMicronsWithUpdater;
};
// Bootstrap font stack + Open Sans
export const canvasFontFromSize = (size: string): string => {
const fontFamily = `'Open Sans Variable',
system-ui,
-apple-system,
'Segoe UI',
Roboto,
'Helvetica Neue',
'Noto Sans',
'Liberation Sans',
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
'Noto Color Emoji'`;
const fontWeight = 600;
return `${fontWeight} ${size} ${fontFamily}`;
};