Skip to content

Commit

Permalink
Merge branch 'master' into horizontal-price-scale-example
Browse files Browse the repository at this point in the history
  • Loading branch information
SlicedSilver committed Jun 14, 2024
2 parents 1ab1af9 + 86aa897 commit b7b0ebf
Show file tree
Hide file tree
Showing 12 changed files with 1,066 additions and 98 deletions.
8 changes: 4 additions & 4 deletions .size-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ module.exports = [
{
name: 'CJS',
path: 'dist/lightweight-charts.production.cjs',
limit: '48.22 KB',
limit: '48.24 KB',
},
{
name: 'ESM',
path: 'dist/lightweight-charts.production.mjs',
limit: '48.14 KB',
limit: '48.16 KB',
},
{
name: 'Standalone-ESM',
path: 'dist/lightweight-charts.standalone.production.mjs',
limit: '49.84 KB',
limit: '49.87 KB',
},
{
name: 'Standalone',
path: 'dist/lightweight-charts.standalone.production.js',
limit: '49.89 KB',
limit: '49.91 KB',
},
];
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"private": true,
"version": "4.2.0",
"version": "4.1.6",
"name": "lightweight-charts",
"author": "TradingView, Inc.",
"license": "Apache-2.0",
Expand Down
12 changes: 12 additions & 0 deletions src/api/create-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,15 @@ export function createChart(container: string | HTMLElement, options?: DeepParti
HorzScaleBehaviorTime.applyDefaults(options)
);
}

/**
* Provides the default implementation of the horizontal scale (time-based) that can be used as a base for extending the horizontal scale with custom behavior.
* This allows for the introduction of custom functionality without re-implementing the entire {@link IHorzScaleBehavior}<{@link Time}> interface.
*
* For further details, refer to the {@link createChartEx} chart constructor method.
*
* @returns An uninitialized class implementing the {@link IHorzScaleBehavior}<{@link Time}> interface
*/
export function defaultHorzScaleBehavior(): new () => IHorzScaleBehavior<Time> {
return HorzScaleBehaviorTime;
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const customSeriesDefaultOptions: CustomSeriesOptions = {
...customStyleDefaults,
};

export { createChart, createChartEx } from './api/create-chart';
export { createChart, createChartEx, defaultHorzScaleBehavior } from './api/create-chart';

/**
* Returns the current version as a string. For example `'3.3.0'`.
Expand Down
100 changes: 10 additions & 90 deletions src/model/horz-scale-behavior-time/horz-scale-behavior-time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { DateTimeFormatter } from '../../formatters/date-time-formatter';

import { ensureNotNull } from '../../helpers/assertions';
import { Mutable } from '../../helpers/mutable';
import { DeepPartial, isString, merge } from '../../helpers/strict-type-checks';
import { DeepPartial, merge } from '../../helpers/strict-type-checks';

import { SeriesDataItemTypeMap } from '../data-consumer';
import { TimedData } from '../data-layer';
import { DataItem, HorzScaleItemConverterToInternalObj, IHorzScaleBehavior, InternalHorzScaleItem, InternalHorzScaleItemKey } from '../ihorz-scale-behavior';
import { LocalizationOptions } from '../localization-options';
import { SeriesType } from '../series-options';
Expand All @@ -16,96 +15,17 @@ import { markWithGreaterWeight, TimeMark } from '../time-scale';
import { defaultTickMarkFormatter } from './default-tick-mark-formatter';
import { TimeChartOptions } from './time-based-chart-options';
import { fillWeightsForPoints } from './time-scale-point-weight-generator';
import { BusinessDay, isBusinessDay, isUTCTimestamp, TickMarkType, TickMarkWeight, Time, TimePoint, UTCTimestamp } from './types';

type TimeConverter = (time: Time) => InternalHorzScaleItem;

function businessDayConverter(time: Time): InternalHorzScaleItem {
let businessDay = time;
if (isString(time)) {
businessDay = stringToBusinessDay(time);
}
if (!isBusinessDay(businessDay)) {
throw new Error('time must be of type BusinessDay');
}

const date = new Date(Date.UTC(businessDay.year, businessDay.month - 1, businessDay.day, 0, 0, 0, 0));

return {
timestamp: Math.round(date.getTime() / 1000) as UTCTimestamp,
businessDay,
} as unknown as InternalHorzScaleItem;
}

function timestampConverter(time: Time): InternalHorzScaleItem {
if (!isUTCTimestamp(time)) {
throw new Error('time must be of type isUTCTimestamp');
}
return {
timestamp: time,
} as unknown as InternalHorzScaleItem;
}

function selectTimeConverter(data: TimedData<Time>[]): TimeConverter | null {
if (data.length === 0) {
return null;
}
if (isBusinessDay(data[0].time) || isString(data[0].time)) {
return businessDayConverter;
}
return timestampConverter;
}

const validDateRegex = /^\d\d\d\d-\d\d-\d\d$/;

export function convertTime(time: Time): InternalHorzScaleItem {
if (isUTCTimestamp(time)) {
return timestampConverter(time);
}

if (!isBusinessDay(time)) {
return businessDayConverter(stringToBusinessDay(time));
}

return businessDayConverter(time);
}

export function stringToBusinessDay(value: string): BusinessDay {
if (process.env.NODE_ENV === 'development') {
// in some browsers (I look at your Chrome) the Date constructor may accept invalid date string
// but parses them in 'implementation specific' way
// for example 2019-1-1 isn't the same as 2019-01-01 (for Chrome both are 'valid' date strings)
// see https://bugs.chromium.org/p/chromium/issues/detail?id=968939
// so, we need to be sure that date has valid format to avoid strange behavior and hours of debugging
// but let's do this in development build only because of perf
if (!validDateRegex.test(value)) {
throw new Error(`Invalid date string=${value}, expected format=yyyy-mm-dd`);
}
}

const d = new Date(value);
if (isNaN(d.getTime())) {
throw new Error(`Invalid date string=${value}, expected format=yyyy-mm-dd`);
}

return {
day: d.getUTCDate(),
month: d.getUTCMonth() + 1,
year: d.getUTCFullYear(),
};
}

function convertStringToBusinessDay(value: TimedData<Time>): void {
if (isString(value.time)) {
value.time = stringToBusinessDay(value.time);
}
}

function convertStringsToBusinessDays(data: TimedData<Time>[]): void {
return data.forEach(convertStringToBusinessDay);
}
import { convertStringsToBusinessDays, convertStringToBusinessDay, convertTime, selectTimeConverter } from './time-utils';
import { TickMarkType, TickMarkWeight, Time, TimePoint } from './types';

/**
* Represents options for formatting dates, times, and prices according to a locale.
*/
interface TimeLocalizationOptions extends LocalizationOptions<Time> {
/**
* Date formatting string.
*
*/
dateFormat: string;
}

Expand Down
93 changes: 93 additions & 0 deletions src/model/horz-scale-behavior-time/time-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

import { isString } from '../../helpers/strict-type-checks';

import { TimedData } from '../data-layer';
import { InternalHorzScaleItem } from '../ihorz-scale-behavior';
import { BusinessDay, isBusinessDay, isUTCTimestamp, Time, UTCTimestamp } from './types';

export type TimeConverter = (time: Time) => InternalHorzScaleItem;

export function businessDayConverter(time: Time): InternalHorzScaleItem {
let businessDay = time;
if (isString(time)) {
businessDay = stringToBusinessDay(time);
}
if (!isBusinessDay(businessDay)) {
throw new Error('time must be of type BusinessDay');
}

const date = new Date(Date.UTC(businessDay.year, businessDay.month - 1, businessDay.day, 0, 0, 0, 0));

return {
timestamp: Math.round(date.getTime() / 1000) as UTCTimestamp,
businessDay,
} as unknown as InternalHorzScaleItem;
}

export function timestampConverter(time: Time): InternalHorzScaleItem {
if (!isUTCTimestamp(time)) {
throw new Error('time must be of type isUTCTimestamp');
}
return {
timestamp: time,
} as unknown as InternalHorzScaleItem;
}

export function selectTimeConverter(data: TimedData<Time>[]): TimeConverter | null {
if (data.length === 0) {
return null;
}
if (isBusinessDay(data[0].time) || isString(data[0].time)) {
return businessDayConverter;
}
return timestampConverter;
}

const validDateRegex = /^\d\d\d\d-\d\d-\d\d$/;

export function convertTime(time: Time): InternalHorzScaleItem {
if (isUTCTimestamp(time)) {
return timestampConverter(time);
}

if (!isBusinessDay(time)) {
return businessDayConverter(stringToBusinessDay(time));
}

return businessDayConverter(time);
}

export function stringToBusinessDay(value: string): BusinessDay {
if (process.env.NODE_ENV === 'development') {
// in some browsers (I look at your Chrome) the Date constructor may accept invalid date string
// but parses them in 'implementation specific' way
// for example 2019-1-1 isn't the same as 2019-01-01 (for Chrome both are 'valid' date strings)
// see https://bugs.chromium.org/p/chromium/issues/detail?id=968939
// so, we need to be sure that date has valid format to avoid strange behavior and hours of debugging
// but let's do this in development build only because of perf
if (!validDateRegex.test(value)) {
throw new Error(`Invalid date string=${value}, expected format=yyyy-mm-dd`);
}
}

const d = new Date(value);
if (isNaN(d.getTime())) {
throw new Error(`Invalid date string=${value}, expected format=yyyy-mm-dd`);
}

return {
day: d.getUTCDate(),
month: d.getUTCMonth() + 1,
year: d.getUTCFullYear(),
};
}

export function convertStringToBusinessDay(value: TimedData<Time>): void {
if (isString(value.time)) {
value.time = stringToBusinessDay(value.time);
}
}

export function convertStringsToBusinessDays(data: TimedData<Time>[]): void {
return data.forEach(convertStringToBusinessDay);
}
10 changes: 10 additions & 0 deletions src/model/ihorz-scale-behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,14 @@ export interface IHorzScaleBehavior<HorzScaleItem> {
* @returns void
*/
fillWeightsForPoints(sortedTimePoints: readonly Mutable<TimeScalePoint>[], startIndex: number): void;

/**
* If returns true, then the tick mark formatter will be called for all the visible
* tick marks even if the formatter has previously been called for a specific tick mark.
* This allows you to change the formatting on all the tick marks.
*
* @param tickMarks - array of tick marks
* @returns boolean
*/
shouldResetTickmarkLabels?(tickMarks: readonly TickMark[]): boolean;
}
Loading

0 comments on commit b7b0ebf

Please sign in to comment.