This commit is contained in:
Violet Voronetzky 2020-03-30 12:37:18 +03:00
Родитель 5642866686
Коммит e5138d8db4
8 изменённых файлов: 45 добавлений и 60 удалений

Просмотреть файл

@ -10,7 +10,7 @@ npm install adx-query-charts
1. [lodash](https://www.npmjs.com/package/lodash): `npm i lodash`
2. [css-element-queries](https://www.npmjs.com/package/css-element-queries): `npm i css-element-queries`
3. [highcharts](https://www.npmjs.com/package/highcharts): `npm i highcharts`
<b>Please note</b>: Highcharts/Highstock libraries are free to use with Log Analytics/adx-query-charts. <br>If you plan to use Highcharts separately, in your own project, you must obtain a license: <br>follow the link [License and Pricing](https://shop.highsoft.com/highcharts).
<b>Please note</b>: Highcharts/Highstock libraries are free to use with Log Analytics/adx-query-charts. <br/>If you plan to use Highcharts separately, in your own project, you must obtain a license: <br/>follow the link [License and Pricing](https://shop.highsoft.com/highcharts).
## Usage
```typescript
@ -34,42 +34,42 @@ chartHelper.draw(queryResultData, chartOptions);
### KustoChartHelper
| Method: | Description: | Input: | Return value: |
| ------------------------ |-------------------------- | ----------------------------------------------------------------------------- | ---------------- |
| draw | Draw the chart | [IQueryResultData](#IQueryResultData) - The original query result data<br>[IChartOptions](#IChartOptions) - The information required to draw the chart | Promise&lt;[IChartInfo](#IChartInfo)&gt; |
| draw | Draw the chart | [IQueryResultData](#IQueryResultData) - The original query result data<br/>[IChartOptions](#IChartOptions) - The information required to draw the chart | Promise&lt;[IChartInfo](#IChartInfo)&gt; |
| changeTheme | Change the theme of an existing chart | [ChartTheme](#ChartTheme) - The theme to apply | Promise&lt;void&gt; |
| getSupportedColumnTypes | Get the supported column types for the axes and the split-by<br>for a specific chart type | [ChartType](#ChartType) - The type of the chart | [ISupportedColumnTypes](#ISupportedColumnTypes) |
| getSupportedColumnsInResult | Get the supported columns from the query result data for the axes and the split-by for a specific chart type | [IQueryResultData](#IQueryResultData) - The original query result data<br> [ChartType](#ChartType) - The type of the chart | [ISupportedColumns](#ISupportedColumns) |
| getDefaultSelection | Get the default columns selection from the query result data.<br>Select the default columns for the axes and the split-by for drawing a default chart of a specific chart type. | [IQueryResultData](#IQueryResultData) - The original query result data<br> [ChartType](#ChartType) - The type of the chart<br>[ISupportedColumns](#ISupportedColumns) - (Optional) The list of the supported column types for the axes and the split-by | [ColumnsSelection](#ColumnsSelection) |
| getSupportedColumnTypes | Get the supported column types for the axes and the split-by<br/>for a specific chart type | [ChartType](#ChartType) - The type of the chart | [ISupportedColumnTypes](#ISupportedColumnTypes) |
| getSupportedColumnsInResult | Get the supported columns from the query result data for the axes and the split-by for a specific chart type | [IQueryResultData](#IQueryResultData) - The original query result data<br/> [ChartType](#ChartType) - The type of the chart | [ISupportedColumns](#ISupportedColumns) |
| getDefaultSelection | Get the default columns selection from the query result data.<br/>Select the default columns for the axes and the split-by for drawing a default chart of a specific chart type. | [IQueryResultData](#IQueryResultData) - The original query result data<br/> [ChartType](#ChartType) - The type of the chart<br/>[ISupportedColumns](#ISupportedColumns) - (Optional) The list of the supported column types for the axes and the split-by | [ColumnsSelection](#ColumnsSelection) |
| downloadChartJPGImage | Download the chart as JPG image | (error: Error) => void - [Optional] A callback that will be called if the module failed to export the chart image | void |
### IChartOptions
| Option name: | Type: | Details: | Default value: |
| ------------------- |-------------------- | --------------------------------------------- | ----------------|
| chartType | [ChartType](#ChartType) | Mandatory. <br>The type of the chart to draw | |
| columnsSelection | [ColumnsSelection](#ColumnsSelection)| The columns selection for the Axes and the split-by of the chart | If not provided, default columns will be selected. <br>See: getDefaultSelection method|
| maxUniqueXValues | number | The maximum number of the unique X-axis values.<br>The chart will show the biggest values, and the rest will be aggregated to a separate data point.| 100 |
| chartType | [ChartType](#ChartType) | Mandatory. <br/>The type of the chart to draw | |
| columnsSelection | [ColumnsSelection](#ColumnsSelection)| The columns selection for the Axes and the split-by of the chart | If not provided, default columns will be selected. <br/>See: getDefaultSelection method|
| maxUniqueXValues | number | The maximum number of the unique X-axis values.<br/>The chart will show the biggest values, and the rest will be aggregated to a separate data point.| 100 |
| exceedMaxDataPointLabel| string | The label of the data point that contains the aggregated value of all the X-axis values that exceed the 'maxUniqueXValues'| 'OTHER' |
| aggregationType | [AggregationType](#AggregationType) | Multiple rows with the same values for the X-axis and the split-by will be aggregated using a function of this type.<br>For example, assume we get the following query result data:<br>['2016-08-02T10:00:00Z', 'Chrome 51.0', 15], <br>['2016-08-02T10:00:00Z', 'Internet Explorer 9.0', 4]<br>When drawing a chart with columnsSelection = { xAxis: timestamp, yAxes: count_ }, and aggregationType = AggregationType.Sum we need to aggregate the values of the same timestamp value and return one row with ["2016-08-02T10:00:00Z", 19] | AggregationType.Sum |
| aggregationType | [AggregationType](#AggregationType) | Multiple rows with the same values for the X-axis and the split-by will be aggregated using a function of this type.<br/>For example, assume we get the following query result data:<br/>['2016-08-02T10:00:00Z', 'Chrome 51.0', 15], <br/>['2016-08-02T10:00:00Z', 'Internet Explorer 9.0', 4]<br/>When drawing a chart with columnsSelection = { xAxis: timestamp, yAxes: count_ }, and aggregationType = AggregationType.Sum we need to aggregate the values of the same timestamp value and return one row with ["2016-08-02T10:00:00Z", 19] | AggregationType.Sum |
| title | string | The title of the chart | |
| legendOptions | [ILegendOptions](#ILegendOptions) | The legend configuration options | |
| yMinimumValue | number | The minimum value to be displayed on the y-axis <br/> If not provided, the minimum value is automatically calculated | |
| yMaximumValue | number | The maximum value to be displayed on the y-axis <br/> If not provided, the maximum value is automatically calculated | |
| fontFamily | string | Chart labels font family | 'az_ea_font, wf_segoe-ui_normal, \"Segoe UI\", \"Segoe WP\", Tahoma, Arial, sans-serif' |
| chartTheme | [ChartTheme](#ChartTheme) | The theme of the chart | ChartTheme.Light |
| getUtcOffset | Function<br>(dateStr: string): number | Callback that is used to get the desired offset from UTC in hours for date value. Used to handle timezone.<br>The offset will be added to the original date from the query results data.<br>For example:<br>For 'South Africa Standard Time' timezone provide utcOffset = 2 and the displayed date will be:<br>'11/25/2019, 04:00 PM' instead of '11/25/2019, 02:00 PM'<br>See time zone [info](https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11) <br> Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;dateStr - The original date string from the query result. For example: '2019-11-25T07:14:00.000Z'<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The desired offset from UTC in hours | If not provided, the utcOffset will be 0 |
| dateFormatter | Function<br>(dateValue: Date, defaultFormat: DateFormat): string| Callback that is used to format the date values both in the axis and the tooltip<br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;dateValue - The original date value. If utcOffset was provided, this value will include the utcOffset<br>&nbsp;&nbsp;&nbsp;&nbsp;[DateFormat](#DateFormat) - The default format of the label<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The string represents the display value of the dateValue| If not provided - the default formatting will apply |
| numberFormatter | Function<br>(numberValue: number): string | Callback that is used to format number values both in the axis and the tooltip<br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;numberValue - The original number<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The string represents the display value of the numberValue |If not provided - the default formatting will apply |
| xAxisTitleFormatter | Function<br>(xAxisColumn: IColumn): string | Callback that is used to get the xAxis title<br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;[IColumn](#IColumn) - The x-axis column<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The desired x-axis title | If not provided - the xAxis title will be the xAxis column name |
| yAxisTitleFormatter | Function<br>(yAxisColumns: IColumn[]): string | Callback that is used to get the yAxis title<br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;[IColumn[]](#IColumn) - The y-axis columns<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The desired y-axis title | If not provided - the yAxis title will be the first yAxis column name |
| onFinishDataTransformation | Function(dataTransformationInfo: IDataTransformationInfo) : Promise&lt;boolean&gt; | Callback that is called when all the data transformations required to draw the chart are finished<br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;[IDataTransformationInfo](#IDataTransformationInfo) - The information regarding the applied transformations on the original query results<br>Callback return value:<br>&nbsp;&nbsp;&nbsp;&nbsp;The promise that is used to continue/stop drawing the chart<br>&nbsp;&nbsp;&nbsp;&nbsp;When provided, the drawing of the chart will be suspended until this promise will be resolved<br>&nbsp;&nbsp;&nbsp;&nbsp;When resolved with true - the chart will continue the drawing<br>&nbsp;&nbsp;&nbsp;&nbsp;When resolved with false - the chart drawing will be canceled | |
| onFinishDrawing | Function(chartInfo: IChartInfo) : void | Callback that is called when the chart drawing is finished <br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;[IChartInfo](#IChartInfo) - The information regarding the chart | | |
| onFinishChartAnimation | Function(chartInfo: IChartInfo) : void | Callback that is called when the chart animation is finished <br>Callback inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;[IChartInfo](#IChartInfo) - The information regarding the chart | | |
| getUtcOffset | Function<br/>(dateValue: number): number | Callback that is used to get the desired offset from UTC in minutes for date value. Used to handle timezone.<br/>The offset will be added to the original UTC date from the query results data.<br/>For example:<br/>For 'South Africa Standard Time' timezone return -120 and the displayed date will be:<br/>'11/25/2019, 02:00 PM' instead of '11/25/2019, 04:00 PM'<br/>See time zone [info](https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11)<br/>If dateFormatter wasn't provided, the callback will be also used for the X axis labels and the tooltip header. Otherwise - it will only be used for positionning the x-axis.<br/> Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;dateValue - The time value in milliseconds since midnight, January 1, 1970 UTC of the date from the query result.&nbsp;&nbsp;&nbsp;&nbsp;<br/> For example: 1574666160000 represent '2019-11-25T07:16:00.000Z'<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The desired offset from UTC in hours | If not provided, the utcOffset will be 0 |
| dateFormatter | Function<br/>(dateValue: number, defaultFormat: DateFormat): string | Callback that is used to format the date values both in the axis and the tooltip<br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;dateValue - The original date value in milliseconds since midnight, January 1, 1970 UTC<br/>&nbsp;&nbsp;&nbsp;&nbsp;[DateFormat](#DateFormat) - The default format of the label<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The string represents the display value of the dateValue| If not provided - the default formatting will apply |
| numberFormatter | Function<br/>(numberValue: number): string | Callback that is used to format number values both in the axis and the tooltip<br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;numberValue - The original number<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The string represents the display value of the numberValue |If not provided - the default formatting will apply |
| xAxisTitleFormatter | Function<br/>(xAxisColumn: IColumn): string | Callback that is used to get the xAxis title<br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[IColumn](#IColumn) - The x-axis column<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The desired x-axis title | If not provided - the xAxis title will be the xAxis column name |
| yAxisTitleFormatter | Function<br/>(yAxisColumns: IColumn[]): string | Callback that is used to get the yAxis title<br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[IColumn[]](#IColumn) - The y-axis columns<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The desired y-axis title | If not provided - the yAxis title will be the first yAxis column name |
| onFinishDataTransformation | Function(dataTransformationInfo: IDataTransformationInfo) : Promise&lt;boolean&gt; | Callback that is called when all the data transformations required to draw the chart are finished<br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[IDataTransformationInfo](#IDataTransformationInfo) - The information regarding the applied transformations on the original query results<br/>Callback return value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;The promise that is used to continue/stop drawing the chart<br/>&nbsp;&nbsp;&nbsp;&nbsp;When provided, the drawing of the chart will be suspended until this promise will be resolved<br/>&nbsp;&nbsp;&nbsp;&nbsp;When resolved with true - the chart will continue the drawing<br/>&nbsp;&nbsp;&nbsp;&nbsp;When resolved with false - the chart drawing will be canceled | |
| onFinishDrawing | Function(chartInfo: IChartInfo) : void | Callback that is called when the chart drawing is finished <br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[IChartInfo](#IChartInfo) - The information regarding the chart | | |
| onFinishChartAnimation | Function(chartInfo: IChartInfo) : void | Callback that is called when the chart animation is finished <br/>Callback inputs:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[IChartInfo](#IChartInfo) - The information regarding the chart | | |
### IDataTransformationInfo
| Option name: | Type: | Details: |
| -------------------------- |------------------------------------- | -------------------------------------------------------------------------------------------------- |
| numberOfDataPoints | number | The amount of the data points that will be drawn for the chart |
| isPartialData | boolean | True if the chart presents partial data from the original query results<br>The chart data will be partial when the maximum number of the unique X-axis values exceed the<br> 'maxUniqueXValues' in [IChartOptions](#IChartOptions) |
| isAggregationApplied | boolean | True if aggregation was applied on the original query results in order to draw the chart<br>See 'aggregationType' in [IChartOptions](#IChartOptions) for more details |
| isPartialData | boolean | True if the chart presents partial data from the original query results<br/>The chart data will be partial when the maximum number of the unique X-axis values exceed the<br/> 'maxUniqueXValues' in [IChartOptions](#IChartOptions) |
| isAggregationApplied | boolean | True if aggregation was applied on the original query results in order to draw the chart<br/>See 'aggregationType' in [IChartOptions](#IChartOptions) for more details |
### IChartInfo
| Option name: | Type: | Details: |

Просмотреть файл

@ -217,25 +217,26 @@ export interface IChartOptions {
fontFamily?: string;
/**
* Callback that is used to get the desired offset from UTC in hours for date value. Used to handle timezone.
* The offset will be added to the original date from the query results data.
* The callback input is the string value of the date from the query result. For example: '2019-11-25T07:14:00.000Z'
* For example:
* For 'South Africa Standard Time' timezone return 2 and the displayed date will be '11/25/2019, 04:00 PM' instead of '11/25/2019, 02:00 PM'
* Callback that is used to get the desired offset from UTC in minutes for date value. Used to handle timezone.
* The offset will be added to the original UTC date from the query results data.
* The callback input is the time value in milliseconds since midnight, January 1, 1970 UTC of the date from the query result.
* For example: 1574666160000 represent '2019-11-25T07:16:00.000Z'
* For 'South Africa Standard Time' timezone return -120 and the displayed date will be '11/25/2019, 02:00 PM' instead of '11/25/2019, 04:00 PM'
* See time zone info: https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx
* If dateFormatter wasn't provided, the callback will be also used for the X axis labels and the tooltip header. Otherwise - it will only be used for positionning the x-axis.
* [Default value: 0]
*/
getUtcOffset?: (dateStr: string) => number;
getUtcOffset?: (dateValue: number) => number;
/**
* Callback that is used to format the date values both in the axis and the tooltip. If not provided - the default formatting will apply
* Callback that is used to format the date values both in the axis and the tooltip. If not provided - the default formatting will apply.
* Callback inputs:
* @param dateValue - The original date value. If utcOffset was provided, this value will include the utcOffset.
* @param dateValue - The original date value.
* @param defaultFormat - The default format of the label.
* Callback return value:
* @returns The string represents the display value of the dateValue
*/
dateFormatter?: (dateValue: Date, defaultFormat: DateFormat) => string;
dateFormatter?: (dateValue: number, defaultFormat: DateFormat) => string;
/**
* Callback that is used to format number values both in the axis and the tooltip. If isn't provided - the default formatting will apply.

Просмотреть файл

@ -23,24 +23,18 @@ export class Utilities {
}
/**
* Returns the value of the local date after adding the desired offset (from UTC)
* @param dateStr - The string value that represents the date to transform.
* @param getUtcOffset - Callback that returns the offset in hours from UTC.
* @returns The value of the date + the desired UTC offset
* Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC
* @param dateStr - The string value that represents the date
* @returns The date value in milliseconds since midnight, January 1, 1970 UTC
*/
public static getDateValue(dateStr: string, getUtcOffset: (dateStr: string) => number): number {
public static getDateValue(dateStr: string): number {
const date = new Date(dateStr);
if (date.toDateString() === 'Invalid Date') {
return null;
}
// Add UTC offset to the date
const utcOffset = getUtcOffset(dateStr);
const utcOffsetInMilliseconds = utcOffset * 60 * 60 * 1000;
const localDateValue = date.valueOf();
return localDateValue + utcOffsetInMilliseconds;
}
return date.valueOf()
}
public static isValidDate(str: string): boolean {

Просмотреть файл

@ -50,7 +50,7 @@ export abstract class Chart {
// If the x-axis is a date, convert its value to milliseconds as this is what expected by 'Highcharts'
if(isDatetimeAxis) {
xAxisValue = Utilities.getDateValue(xAxisValue, chartOptions.getUtcOffset);
xAxisValue = Utilities.getDateValue(xAxisValue);
if(!xAxisValue) {
throw new InvalidInputError(`The x-axis value '${row[xAxisColumnIndex]}' is an invalid date`, ErrorCode.InvalidDate);
@ -227,7 +227,7 @@ export abstract class Chart {
let xValue = row[xAxisColumnIndex];
// For date the a-axis, convert its value to ms as this is what expected by Highcharts
xValue = Utilities.getDateValue(<string>xValue, options.chartOptions.getUtcOffset);
xValue = Utilities.getDateValue(<string>xValue);
if(!xValue) {
throw new InvalidInputError(`The x-axis value '${row[xAxisColumnIndex]}' is an invalid date`, ErrorCode.InvalidDate);

Просмотреть файл

@ -2,7 +2,6 @@
import { DraftColumnType, DateFormat, IColumn, IChartOptions } from "../../../common/chartModels";
import { Utilities } from "../../../common/utilities";
import { HC_Utilities } from "./utilities";
export class TooltipHelper {
public static getSingleTooltip(chartOptions: IChartOptions, context: Highcharts.TooltipFormatterContextObject, column: IColumn, originalValue: any, columnName?: string, valueSuffix: string = ''): string {
@ -19,9 +18,7 @@ export class TooltipHelper {
if(chartOptions.numberFormatter && Utilities.isNumeric(columnType)) {
return chartOptions.numberFormatter(originalValue);
} else if(Utilities.isDate(columnType)) {
const utcWithOffsetDate = HC_Utilities.getUtcWithOffsetDate(originalValue);
return chartOptions.dateFormatter ? chartOptions.dateFormatter(utcWithOffsetDate, DateFormat.FullDate) : utcWithOffsetDate.toString();
return chartOptions.dateFormatter ? chartOptions.dateFormatter(originalValue, DateFormat.FullDate) : new Date(originalValue).toString();
}
return originalValue.toString();

Просмотреть файл

@ -20,12 +20,4 @@ export class HC_Utilities {
return originalValue;
}
public static getUtcWithOffsetDate(originalValue: number): Date {
const localWithOffsetDate = new Date(originalValue); // HC gets the local date + utc offset addition
const utcWithOffsetDateValue = localWithOffsetDate.valueOf() + (localWithOffsetDate.getTimezoneOffset() * 60 * 1000); // Add the local offset. This way the utc offset addition is added to the UTC, and not to the local
const utcWithOffsetDate = new Date(utcWithOffsetDateValue);
return utcWithOffsetDate;
}
}

Просмотреть файл

@ -14,7 +14,6 @@ import { IVisualizerOptions } from '../IVisualizerOptions';
import { ChartFactory } from './charts/chartFactory';
import { ChartTheme, DateFormat, IChartOptions, IColumn, DrawChartStatus } from '../../common/chartModels';
import { Changes, ChartChange } from '../../common/chartChange';
import { HC_Utilities } from './common/utilities';
import { Utilities } from '../../common/utilities';
import { Themes } from './themes/themes';
import { HighchartsDateFormatToCommon } from './highchartsDateFormatToCommon';
@ -204,6 +203,9 @@ export class HighchartsVisualizer implements IVisualizer {
fontFamily: options.chartOptions.fontFamily
}
},
time: {
getTimezoneOffset: this.options.chartOptions.getUtcOffset
},
title: {
text: chartOptions.title
},
@ -252,9 +254,8 @@ export class HighchartsVisualizer implements IVisualizer {
formatter = function() {
const dataPoint = this;
const dateFormat = HighchartsDateFormatToCommon[dataPoint.dateTimeLabelFormat] || DateFormat.FullDate;
const utcWithOffsetDate = HC_Utilities.getUtcWithOffsetDate(dataPoint.value);
return chartOptions.dateFormatter(utcWithOffsetDate, dateFormat);
return chartOptions.dateFormatter(dataPoint.value, dateFormat);
}
}

Просмотреть файл

@ -16,7 +16,7 @@ describe('Unit tests for Chart methods', () => {
// Add mock to Utilities.getDateValue -> return the full year
jest
.spyOn(Utilities, 'getDateValue')
.mockImplementation(function(dateStr, offset) {
.mockImplementation(function(dateStr) {
return new Date(dateStr).getFullYear();
});