Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(axis) - Fixes the axis overlapping, changed the way the markers/label appear to realign on ChartJS design #81

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
<!-- <script src="https://alex-nrcan.github.io/geoview/cgpv-main.js"></script> -->
<script src="https://canadian-geospatial-platform.github.io/geoview/public/cgpv-main.js"></script>

<style>
/* To help with display */
.MuiGrid2-container {
width: 600px;
}
</style>

<script>
const DATA_INPUT_LINE_1 = {
chart: 'line',
Expand Down Expand Up @@ -861,6 +868,8 @@

<!--------------- CHART IS HERE ----------------->
<div id="root2aca7b6b288c" style="position: relative; width: 800px;"></div>
<!--------------- CHART IS HERE ----------------->

<div>
<button onclick="redrawChart()" style="padding:5px;"><strong>Looks weird? Redraw!</strong></button>
<button onclick="isLoadingState(1)" style="padding:5px;"><strong>Sim. loading whole chart</strong></button>
Expand Down
342 changes: 171 additions & 171 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,171 +1,171 @@
import { GeoChart } from './chart';
import { GeoChartConfig, ChartType, ChartOptions, ChartData, GeoChartAction, DefaultDataPoint } from './types';
import { SchemaValidator } from './chart-schema-validator';

/**
* Main props for the Application
*/
export interface TypeAppProps {
schemaValidator: SchemaValidator;
}

/**
* Create a container to visualize a GeoChart in a standalone manner.
*
* @returns {JSX.Element} the element that has the GeoChart
*/
export function App(props: TypeAppProps): JSX.Element {
// Can't type the window object to a 'TypeWindow', because we don't have access to the cgpv library when this line runs.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const w = window as any;
// Fetch the cgpv module
const { cgpv } = w;
const { react, ui } = cgpv;
const { useEffect, useState, useCallback } = react;
const { Box } = ui.elements;
const { schemaValidator } = props;

// #region USE STATE SECTION ****************************************************************************************

const [inputs, setInputs] = useState() as [
GeoChartConfig<ChartType> | undefined,
React.Dispatch<React.SetStateAction<GeoChartConfig<ChartType> | undefined>>
];
const [chart, setChart] = useState() as [ChartType, React.Dispatch<React.SetStateAction<ChartType>>];
const [data, setData] = useState() as [
ChartData<ChartType, DefaultDataPoint<ChartType>, string> | undefined,
React.Dispatch<React.SetStateAction<ChartData<ChartType, DefaultDataPoint<ChartType>, string> | undefined>>
];
const [options, setOptions] = useState() as [ChartOptions | undefined, React.Dispatch<React.SetStateAction<ChartOptions> | undefined>];
const [action, setAction] = useState() as [GeoChartAction, React.Dispatch<React.SetStateAction<GeoChartAction>>];
const [language, setLanguage] = useState() as [string, React.Dispatch<React.SetStateAction<string>>];
const [isLoadingChart, setIsLoadingChart] = useState() as [boolean, React.Dispatch<React.SetStateAction<boolean>>];
const [isLoadingDatasource, setIsLoadingDatasource] = useState() as [boolean, React.Dispatch<React.SetStateAction<boolean>>];

// #endregion

// #region EVENT HANDLERS SECTION ***********************************************************************************

/**
* Handles when the Chart has to be loaded with data or options.
*/
const handleChartLoad = (e: Event): void => {
const ev = e as CustomEvent;

// If inputs provided
if (ev.detail.inputs) {
setInputs(ev.detail.inputs);
} else {
setInputs(undefined); // Clear
if (ev.detail.chart) {
setChart(ev.detail.chart);
}
if (ev.detail.options) {
setOptions(ev.detail.options);
}
if (ev.detail.data) {
setData(ev.detail.data);
}
setAction({ shouldRedraw: true });
}
};

/**
* Handles when the Chart has to be redrawn.
*/
const handleChartRedraw = (): void => {
setAction({ shouldRedraw: true });
};

/**
* Handles when the Chart has to show a loading state.
*/
const handleChartLoading = (e: Event): void => {
const ev = e as CustomEvent;

setIsLoadingChart(false);
setIsLoadingDatasource(false);
if (ev.detail.state === 1) setIsLoadingChart(true);
if (ev.detail.state === 2) setIsLoadingDatasource(true);
};

// #endregion

// #region HOOKS SECTION ********************************************************************************************

/**
* Handles when the Chart has parsed inputs.
* @param theChart ChartType The chart type
* @param theOptions ChartOptions The chart options
* @param theData ChartData The chart data
*/
const handleParsed = useCallback((theChart: ChartType, theOptions: ChartOptions, theData: ChartData): void => {
// Raise event higher
window.dispatchEvent(new CustomEvent('chart/parsed', { detail: { chart: theChart, options: theOptions, data: theData } }));
}, []);

/**
* Handles a generic error that happened in the Chart component.
* @param error The error message
* @param exception The exception that happened (if any)
*/
const handleError = useCallback((error: string, exception: unknown): void => {
// Show the error using an alert. We can't use the cgpv SnackBar as that component is attached to
// a map and we're not even running a cgpv.init() at all here.
// eslint-disable-next-line no-console
console.error(error, exception);
// eslint-disable-next-line no-alert
alert(error);
}, []);

/**
* Handles when the Chart language is changed.
*/
const handleChartLanguage = useCallback((e: Event): void => {
const ev = e as CustomEvent;
setLanguage(ev.detail.language);
}, []);

// Effect hook to add and remove event listeners.
// Using window.addEventListener is unconventional here, but this is strictly for the 'app' logic with the index.html.
// It's not something to be used by the developers when using the Chart component in their projects.
useEffect(() => {
window.addEventListener('chart/load', handleChartLoad);
window.addEventListener('chart/redraw', handleChartRedraw);
window.addEventListener('chart/language', handleChartLanguage);
window.addEventListener('chart/isLoading', handleChartLoading);
return () => {
window.removeEventListener('chart/load', handleChartLoad);
window.removeEventListener('chart/redraw', handleChartRedraw);
window.removeEventListener('chart/language', handleChartLanguage);
window.removeEventListener('chart/isLoading', handleChartLoading);
};
}, [handleChartLanguage]);

// #endregion

// #region RENDER SECTION START *************************************************************************************

// Render the Chart
return (
<Box sx={{ padding: '10px' }}>
<GeoChart
inputs={inputs}
schemaValidator={schemaValidator}
chart={chart}
data={data}
options={options}
action={action}
language={language}
isLoadingChart={isLoadingChart}
isLoadingDatasource={isLoadingDatasource}
onParsed={handleParsed}
onError={handleError}
/>
</Box>
);

// #endregion
}

export default App;
import { GeoChart } from './chart';
import { GeoChartConfig, ChartType, ChartOptions, ChartData, GeoChartAction, DefaultDataPoint } from './types';
import { SchemaValidator } from './chart-schema-validator';
/**
* Main props for the Application
*/
export interface TypeAppProps {
schemaValidator: SchemaValidator;
}
/**
* Create a container to visualize a GeoChart in a standalone manner.
*
* @returns {JSX.Element} the element that has the GeoChart
*/
export function App(props: TypeAppProps): JSX.Element {
// Can't type the window object to a 'TypeWindow', because we don't have access to the cgpv library when this line runs.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const w = window as any;
// Fetch the cgpv module
const { cgpv } = w;
const { react, ui } = cgpv;
const { useEffect, useState, useCallback } = react;
const { Box } = ui.elements;
const { schemaValidator } = props;
// #region USE STATE SECTION ****************************************************************************************
const [inputs, setInputs] = useState() as [
GeoChartConfig<ChartType> | undefined,
React.Dispatch<React.SetStateAction<GeoChartConfig<ChartType> | undefined>>
];
const [chart, setChart] = useState() as [ChartType, React.Dispatch<React.SetStateAction<ChartType>>];
const [data, setData] = useState() as [
ChartData<ChartType, DefaultDataPoint<ChartType>, string> | undefined,
React.Dispatch<React.SetStateAction<ChartData<ChartType, DefaultDataPoint<ChartType>, string> | undefined>>
];
const [options, setOptions] = useState() as [ChartOptions | undefined, React.Dispatch<React.SetStateAction<ChartOptions> | undefined>];
const [action, setAction] = useState() as [GeoChartAction, React.Dispatch<React.SetStateAction<GeoChartAction>>];
const [language, setLanguage] = useState() as [string, React.Dispatch<React.SetStateAction<string>>];
const [isLoadingChart, setIsLoadingChart] = useState() as [boolean, React.Dispatch<React.SetStateAction<boolean>>];
const [isLoadingDatasource, setIsLoadingDatasource] = useState() as [boolean, React.Dispatch<React.SetStateAction<boolean>>];
// #endregion
// #region EVENT HANDLERS SECTION ***********************************************************************************
/**
* Handles when the Chart has to be loaded with data or options.
*/
const handleChartLoad = (e: Event): void => {
const ev = e as CustomEvent;
// If inputs provided
if (ev.detail.inputs) {
setInputs(ev.detail.inputs);
} else {
setInputs(undefined); // Clear
if (ev.detail.chart) {
setChart(ev.detail.chart);
}
if (ev.detail.options) {
setOptions(ev.detail.options);
}
if (ev.detail.data) {
setData(ev.detail.data);
}
setAction({ shouldRedraw: true });
}
};
/**
* Handles when the Chart has to be redrawn.
*/
const handleChartRedraw = (): void => {
setAction({ shouldRedraw: true });
};
/**
* Handles when the Chart has to show a loading state.
*/
const handleChartLoading = (e: Event): void => {
const ev = e as CustomEvent;
setIsLoadingChart(false);
setIsLoadingDatasource(false);
if (ev.detail.state === 1) setIsLoadingChart(true);
if (ev.detail.state === 2) setIsLoadingDatasource(true);
};
// #endregion
// #region HOOKS SECTION ********************************************************************************************
/**
* Handles when the Chart has parsed inputs.
* @param theChart ChartType The chart type
* @param theOptions ChartOptions The chart options
* @param theData ChartData The chart data
*/
const handleParsed = useCallback((theChart: ChartType, theOptions: ChartOptions, theData: ChartData): void => {
// Raise event higher
window.dispatchEvent(new CustomEvent('chart/parsed', { detail: { chart: theChart, options: theOptions, data: theData } }));
}, []);
/**
* Handles a generic error that happened in the Chart component.
* @param error The error message
* @param exception The exception that happened (if any)
*/
const handleError = useCallback((error: string, exception: unknown): void => {
// Show the error using an alert. We can't use the cgpv SnackBar as that component is attached to
// a map and we're not even running a cgpv.init() at all here.
// eslint-disable-next-line no-console
console.error(error, exception);
// eslint-disable-next-line no-alert
alert(error);
}, []);
/**
* Handles when the Chart language is changed.
*/
const handleChartLanguage = useCallback((e: Event): void => {
const ev = e as CustomEvent;
setLanguage(ev.detail.language);
}, []);
// Effect hook to add and remove event listeners.
// Using window.addEventListener is unconventional here, but this is strictly for the 'app' logic with the index.html.
// It's not something to be used by the developers when using the Chart component in their projects.
useEffect(() => {
window.addEventListener('chart/load', handleChartLoad);
window.addEventListener('chart/redraw', handleChartRedraw);
window.addEventListener('chart/language', handleChartLanguage);
window.addEventListener('chart/isLoading', handleChartLoading);
return () => {
window.removeEventListener('chart/load', handleChartLoad);
window.removeEventListener('chart/redraw', handleChartRedraw);
window.removeEventListener('chart/language', handleChartLanguage);
window.removeEventListener('chart/isLoading', handleChartLoading);
};
}, [handleChartLanguage]);
// #endregion
// #region RENDER SECTION START *************************************************************************************
// Render the Chart
return (
<Box sx={{ padding: '10px' }}>
<GeoChart
inputs={inputs}
schemaValidator={schemaValidator}
chart={chart}
data={data}
options={options}
action={action}
language={language}
isLoadingChart={isLoadingChart}
isLoadingDatasource={isLoadingDatasource}
onParsed={handleParsed}
onError={handleError}
/>
</Box>
);
// #endregion
}
export default App;
2 changes: 1 addition & 1 deletion src/chart-parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,14 +624,14 @@ export function createChartJSOptions<TType extends ChartType>(

// If line and using a time series
if (chartConfig.chart === 'line' && (chartConfig.geochart.xAxis?.type === 'time' || chartConfig.geochart.xAxis?.type === 'timeseries')) {
// Generate the options object
const optionsLine = options as ChartOptions<'line'>;
optionsLine.scales = {
...optionsLine.scales,
x: {
type: chartConfig.geochart.xAxis?.type,
ticks: {
autoSkip: true,
maxTicksLimit: 20,
major: {
enabled: true,
},
Expand Down
Loading