Skip to content

Commit

Permalink
Merge pull request #32 from gemini-hlsw/labels-plot-fix
Browse files Browse the repository at this point in the history
Labels plot fix
  • Loading branch information
stroncod authored Feb 29, 2024
2 parents 488a4e9 + d41fd98 commit 979c5bb
Showing 1 changed file with 118 additions and 75 deletions.
193 changes: 118 additions & 75 deletions src/components/SchedulerPlot/SchedulerPlot.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,85 @@
import React, { useContext, useEffect, useRef, useState } from 'react';
import moment from 'moment-timezone';
import Highcharts, { SeriesArearangeOptions } from 'highcharts';
import HighchartsReact, { HighchartsReactRefObject } from 'highcharts-react-official';
import HighchartMore from 'highcharts/highcharts-more';
HighchartMore(Highcharts)
import React, { useContext, useEffect, useRef, useState } from "react";
import Highcharts, { SVGRenderer, SeriesArearangeOptions } from "highcharts";
import HighchartsReact, {
HighchartsReactRefObject,
} from "highcharts-react-official";
import HighchartMore from "highcharts/highcharts-more";
HighchartMore(Highcharts);

import "./SchedulerPlot.scss"
import { ThemeContext } from '../../theme/ThemeProvider';
import "./SchedulerPlot.scss";
import { ThemeContext } from "../../theme/ThemeProvider";

interface Visit {
startDate: Date,
endDate: Date,
yPoints: number[],
label: string,
instrument: string
startDate: Date;
endDate: Date;
yPoints: number[];
label: string;
instrument: string;
}

interface AltAzPlotProps {
data: Visit[];
eveTwilight: string,
mornTwilight: string,
site: string
eveTwilight: string;
mornTwilight: string;
site: string;
}

const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight, site }) => {
const getOffset = (timeZone = 'UTC', date = new Date()) => {
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
const tzDate = new Date(date.toLocaleString('en-US', { timeZone }));
const AltAzPlot: React.FC<AltAzPlotProps> = ({
data,
eveTwilight,
mornTwilight,
site,
}) => {
const getOffset = (timeZone = "UTC", date = new Date()) => {
const utcDate = new Date(date.toLocaleString("en-US", { timeZone: "UTC" }));
const tzDate = new Date(date.toLocaleString("en-US", { timeZone }));
return (tzDate.getTime() - utcDate.getTime()) / 6e4;
}
const INITIAL_TIMEZONE = site === "GN" ? getOffset("Pacific/Honolulu") : getOffset("America/Santiago")
};
const INITIAL_TIMEZONE =
site === "GN"
? getOffset("Pacific/Honolulu")
: getOffset("America/Santiago");

function getTzTime(date: Date) {
return date.getTime() + (INITIAL_TIMEZONE) * 60 * 1000
return date.getTime() + INITIAL_TIMEZONE * 60 * 1000;
}

// Get theme context to modify chart values
const { theme } = useContext(ThemeContext);
const textColor = theme === 'light' ? '#000' : '#ECEAEA';
const gridLineColor = theme === 'light' ? '#e6e6e6' : '#444';
const textColor = theme === "light" ? "#000" : "#ECEAEA";
const gridLineColor = theme === "light" ? "#e6e6e6" : "#444";

// ref for post-render use
const chartRef = useRef<HighchartsReactRefObject>(null);
const labelRef = useRef(null);

// Array of colors from Highcharts
const colorsOption = Highcharts.getOptions().colors;
const colors = colorsOption
? colorsOption.filter((color): color is Highcharts.ColorString => typeof color === 'string')
? colorsOption.filter(
(color): color is Highcharts.ColorString => typeof color === "string"
)
: [];

const instruments = ['GMOS-N', 'GMOS-S', 'GNIRS', 'NIRI', 'Flamingos2', 'GSAOI', 'GPI', 'IGRINS', 'NIFS']
const instruments = [
"GMOS-N",
"GMOS-S",
"GNIRS",
"NIRI",
"Flamingos2",
"GSAOI",
"GPI",
"IGRINS",
"NIFS",
];

type ColorMap = {
[key: string]: Highcharts.ColorString;
};
const createMap = (keys: string[], colors: Highcharts.ColorString[]): ColorMap => {
const createMap = (
keys: string[],
colors: Highcharts.ColorString[]
): ColorMap => {
let map: ColorMap = {};

for (let i = 0; i < keys.length; i++) {
Expand All @@ -64,57 +89,66 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
return map;
};
const colorMap = createMap(instruments, colors);
const eveTwiDate = new Date(eveTwilight)
const mornTwiDate = new Date(mornTwilight)
const eveTwiDate = new Date(eveTwilight);
const mornTwiDate = new Date(mornTwilight);

const seriesData: Array<SeriesArearangeOptions> = data.map((d: any, index: number) => {
const yMinArray = d.yPoints.map((y: number) => 0);
return {
name: d.instrument,
type: "arearange",
data: d.yPoints.map((y: any, i: number) => {
return {
x: getTzTime(d.startDate) + i * 60 * 1000,
low: yMinArray[i],
high: y,
};
}),
lineWidth: 1,
color: colorMap[d.instrument],
fillOpacity: 0.3,
zIndex: 0,
marker: {
enabled: false,
},
events: {
legendItemClick: function () {
return false; // Prevents the default action, which is toggling visibility
}
},
showInLegend: true, // Hide this series in the legend
};
});
const seriesData: Array<SeriesArearangeOptions> = data.map(
(d: any, index: number) => {
const yMinArray = d.yPoints.map((y: number) => 0);
return {
name: d.instrument,
type: "arearange",
data: d.yPoints.map((y: any, i: number) => {
return {
x: getTzTime(d.startDate) + i * 60 * 1000,
low: yMinArray[i],
high: y,
};
}),
lineWidth: 1,
color: colorMap[d.instrument],
fillOpacity: 0.3,
zIndex: 0,
marker: {
enabled: false,
},
events: {
legendItemClick: function () {
return false; // Prevents the default action, which is toggling visibility
},
},
showInLegend: true, // Hide this series in the legend
};
}
);

// Create a set to keep track of names we've seen
let seenNames = new Set();

// Modify the series to set showInLegend to false for duplicates
for (let serie of seriesData) {
if (seenNames.has(serie.name)) {
serie.showInLegend = false; // Don't show in legend if it's a duplicate
serie.showInLegend = false; // Don't show in legend if it's a duplicate
} else {
seenNames.add(serie.name); // Add the name to the set if we haven't seen it
seenNames.add(serie.name); // Add the name to the set if we haven't seen it
}
}

useEffect(() => {
if (!labelRef.current) {
labelRef.current = [];
}

if (chartRef.current) {
const chart = chartRef.current.chart;

chart.update({
series: seriesData,
});

// Remove old labels
labelRef.current.forEach((lbl: SVGRenderer) => lbl.destroy());

// Render custom labels for each section
data.forEach((d, index) => {
const x = (getTzTime(d.startDate) + getTzTime(d.endDate)) / 2;
Expand All @@ -123,7 +157,8 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
const xPos = chart.xAxis[0].toPixels(x, false);
const yPos = chart.yAxis[0].toPixels(y, false);

chart.renderer.text(d.label, xPos, yPos)
let lbl = chart.renderer
.text(d.label, xPos, yPos)
.attr({
rotation: -90,
textAlign: "center",
Expand All @@ -133,9 +168,11 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
color: textColor, // Change the color of the custom label
})
.add();

labelRef.current.push(lbl);
});
}
}, seriesData);
}, [seriesData]);

const options: Highcharts.Options = {
time: {
Expand All @@ -156,7 +193,7 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
return point;
}
return false; // No tooltip for individual points
}
},
},
title: {
text: undefined,
Expand All @@ -174,19 +211,22 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
min: getTzTime(eveTwiDate),
max: getTzTime(mornTwiDate),
tickPositioner: function () {
var positions = []
var interval = 1 * 60 * 60 * 1000
var positions = [];
var interval = 1 * 60 * 60 * 1000;

for (var i = getTzTime(eveTwiDate); i <= getTzTime(mornTwiDate); i += interval) {
for (
var i = getTzTime(eveTwiDate);
i <= getTzTime(mornTwiDate);
i += interval
) {
positions.push(i);
}
return positions;
}

},
},
yAxis: {
title: {
text: null
text: null,
},
labels: {
style: {
Expand All @@ -199,9 +239,9 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
},
legend: {
enabled: true,
align: 'right',
verticalAlign: 'top',
layout: 'vertical',
align: "right",
verticalAlign: "top",
layout: "vertical",
itemStyle: {
color: textColor,
},
Expand All @@ -210,11 +250,14 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight,
};

return (
<div className='scheduler-plot'>

<HighchartsReact highcharts={Highcharts} options={options} ref={chartRef} />
<div className="scheduler-plot">
<HighchartsReact
highcharts={Highcharts}
options={options}
ref={chartRef}
/>
</div>
);
};

export default AltAzPlot;
export default AltAzPlot;

0 comments on commit 979c5bb

Please sign in to comment.