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

jsdoc: Add jsdoc for loadData API #204

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
69 changes: 32 additions & 37 deletions src/lib/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,31 +43,29 @@ export function registerEvents(store: Store, ticker: Ticker) {
}

function registerClickEvents() {
if (store.getState().options.mouseControls) {
const svg = root.querySelector('svg') as SVGSVGElement;
svg.addEventListener('click', (clickEvent) => {
// ignore clicks to group legends
const target = clickEvent.target as HTMLElement;
if (!target || target.classList.contains('legend')) return;

getClicks(clickEvent, function (event: any) {
const clicks = event.detail;
if (clicks === 3) {
ticker.skipBack();
} else if (clicks === 2) {
ticker.skipForward();
} else {
ticker.toggle();
}
});
if (!store.getState().options.mouseControls) return;
const svg = root.querySelector('svg') as SVGSVGElement;
svg.addEventListener('click', (clickEvent) => {
// ignore clicks to group legends
const target = clickEvent.target as HTMLElement;
if (!target || target.classList.contains('legend')) return;

getClicks(clickEvent, function (event: any) {
const clicks = event.detail;
if (clicks === 3) {
ticker.skipBack();
} else if (clicks === 2) {
ticker.skipForward();
} else {
ticker.toggle();
}
});
}
});
}

function registerKeyboardEvents() {
if (store.getState().options.keyboardControls) {
addEventHandler(document, '', 'keyup', handleKeyboardEvents);
}
if (!store.getState().options.keyboardControls) return;
addEventHandler(document, '', 'keyup', handleKeyboardEvents);
}

function handleKeyboardEvents(e: KeyboardEvent) {
Expand Down Expand Up @@ -109,21 +107,21 @@ export function registerEvents(store: Store, ticker: Ticker) {
}

function addEventHandler(
root: HTMLElement | HTMLDocument,
root: HTMLElement | Document,
className: string,
eventType: Event['eventType'],
handler: (e?: any) => void,
) {
const element = getElement(root, className);
if (element) {
element.addEventListener(eventType, handler);
events.push({
element,
userDefined: false,
eventType,
handler,
});
}
if (!element) return;

element.addEventListener(eventType, handler);
events.push({
element,
userDefined: false,
eventType,
handler,
});
}

function addApiEventHandler(eventType: EventType, handler: () => void) {
Expand Down Expand Up @@ -156,12 +154,9 @@ export function getTickDetails(store: Store): TickDetails {
function dispatchDOMEvent(store: Store, eventType: EventType) {
const element = store.getState().container.element;
if (!element) return;
element.dispatchEvent(
new CustomEvent(eventType, {
bubbles: true,
detail: getTickDetails(store),
} as DOMCustomEvent),
);

const customEvent = { bubbles: true, detail: getTickDetails(store) };
element.dispatchEvent(new CustomEvent(eventType, customEvent as DOMCustomEvent));
}

export function DOMEventSubscriber(store: Store) {
Expand Down
21 changes: 21 additions & 0 deletions src/lib/load-data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
import { json, csv, tsv, xml } from './d3';
import type { Options, Data, WideData } from './index';

/**
* Loads data.
*
* @description This function loads data from the given URL based on the detected data type.
* The data type can be explicitly specified or automatically detected from the URL extension.
* The supported data types are 'json', 'csv', 'tsv', and 'xml'.
*
* @param {string} url - The URL from which to load data.
* @param {Options['dataType']} [type='auto'] - The data type must be one of ['json', 'csv', 'tsv', 'xml']. Defaults to 'auto'.
*
* @returns {Promise<Data[]> | Promise<WideData[]>} A promise that resolves to the loaded data.
*
* @throws {Error} Throws an error if the data type is unsupported or if data loading fails.
*
* @example
* loadData('data.csv', 'auto')
* .then(data => console.log(data))
* .catch(error => console.error(error));
*
* @see {@link https://racing-bars.hatemhosny.dev/documentation/api#loaddata}
*/
export function loadData(
url: string,
type: Options['dataType'] = 'auto',
Expand Down
102 changes: 51 additions & 51 deletions src/lib/options/options.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,65 +49,65 @@ export const defaultOptions: Options = {
selectBars: false,
};

/**
* Reducer function to manage options state.
*
* @param {Options} state - The current state of options. Defaults to defaultOptions.
* @param {OptionsAction} action - The action dispatched to modify the options state.
* @returns {Options} The new state of options after applying the action.
*/
export const optionsReducer: Reducer<Options, OptionsAction> = (state = defaultOptions, action) => {
switch (action.type) {
case actionTypes.loadOptions:
case actionTypes.changeOptions: {
const excludedKeys = ['inputHeight', 'inputWidth', 'minHeight', 'minWidth'];
const options: Partial<Options> = {};
const { changeOptions, loadOptions } = actionTypes;
if (action.type !== changeOptions && action.type !== loadOptions) return state;

// remove null, undefined and excluded keys
(Object.keys(action.payload) as Array<keyof Options>).forEach((key) => {
if (!excludedKeys.includes(key)) {
(options[key] as any) = action.payload[key] ?? state[key];
}
});
const excludedKeys = ['inputHeight', 'inputWidth', 'minHeight', 'minWidth'];
const options: Partial<Options> = {};

const startDate = options.startDate ? getDateString(options.startDate) : state.startDate;
const endDate = options.endDate ? getDateString(options.endDate) : state.startDate;
// remove null, undefined and excluded keys
(Object.keys(action.payload) as Array<keyof Options>).forEach((key) => {
if (!excludedKeys.includes(key)) {
(options[key] as any) = action.payload[key] ?? state[key];
}
});

const inputHeight = options.height || state.inputHeight;
const inputWidth = options.width || state.inputWidth;
const startDate = options.startDate ? getDateString(options.startDate) : state.startDate;
const endDate = options.endDate ? getDateString(options.endDate) : state.startDate;

const fixedOrder = Array.isArray(options.fixedOrder)
? [...options.fixedOrder]
: state.fixedOrder;
const inputHeight = options.height || state.inputHeight;
const inputWidth = options.width || state.inputWidth;

const colorMap = Array.isArray(options.colorMap)
? [...options.colorMap].map(String)
: typeof options.colorMap === 'object'
? { ...options.colorMap }
: state.colorMap;
const fixedOrder = Array.isArray(options.fixedOrder) ? [...options.fixedOrder] : state.fixedOrder;

const topN = fixedOrder.length || Number(options.topN) || state.topN;
const colorMap = Array.isArray(options.colorMap)
? [...options.colorMap].map(String)
: typeof options.colorMap === 'object'
? { ...options.colorMap }
: state.colorMap;

const tickDuration = Number(options.tickDuration) || state.tickDuration;
const labelsWidth = Number(options.labelsWidth) || state.labelsWidth;
const marginTop = Number(options.marginTop) || state.marginTop;
const marginRight = Number(options.marginRight) || state.marginRight;
const marginBottom = Number(options.marginBottom) || state.marginBottom;
const marginLeft = Number(options.marginLeft) || state.marginLeft;
const topN = fixedOrder.length || Number(options.topN) || state.topN;

return {
...state,
...options,
startDate,
endDate,
inputHeight,
inputWidth,
fixedOrder,
colorMap,
topN,
tickDuration,
labelsWidth,
marginTop,
marginRight,
marginBottom,
marginLeft,
};
}
const tickDuration = Number(options.tickDuration) || state.tickDuration;
const labelsWidth = Number(options.labelsWidth) || state.labelsWidth;
const marginTop = Number(options.marginTop) || state.marginTop;
const marginRight = Number(options.marginRight) || state.marginRight;
const marginBottom = Number(options.marginBottom) || state.marginBottom;
const marginLeft = Number(options.marginLeft) || state.marginLeft;

default:
return state;
}
return {
...state,
...options,
startDate,
endDate,
inputHeight,
inputWidth,
fixedOrder,
colorMap,
topN,
tickDuration,
labelsWidth,
marginTop,
marginRight,
marginBottom,
marginLeft,
};
};
Loading
Loading