2022-09-02 09:16:30 +00:00
import { get } from "lodash" ;
import equal from "fast-deep-equal/es6" ;
2020-03-13 12:06:41 +00:00
import React from "react" ;
2020-03-20 04:02:49 +00:00
import styled from "styled-components" ;
2020-12-02 10:42:51 +00:00
2022-05-04 09:45:57 +00:00
import { invisible } from "constants/DefaultTheme" ;
2022-01-07 06:08:17 +00:00
import { getAppsmithConfigs } from "@appsmith/configs" ;
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
import type {
2021-09-09 15:10:22 +00:00
ChartDataPoint ,
ChartType ,
CustomFusionChartConfig ,
AllChartData ,
ChartSelectedDataPoint ,
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
} from "../constants" ;
import {
2021-08-26 09:58:43 +00:00
LabelOrientation ,
LABEL_ORIENTATION_COMPATIBLE_CHARTS ,
2021-09-09 15:10:22 +00:00
} from "../constants" ;
2023-02-02 14:17:09 +00:00
import { getSeriesChartData } from "./utils" ;
2021-09-09 15:10:22 +00:00
import log from "loglevel" ;
2022-05-04 09:45:57 +00:00
import { Colors } from "constants/Colors" ;
2022-02-28 09:23:19 +00:00
// Leaving this require here. Ref: https://stackoverflow.com/questions/41292559/could-not-find-a-declaration-file-for-module-module-name-path-to-module-nam/42505940#42505940
// FusionCharts comes with its own typings so there is no need to separately import them. But an import from fusioncharts/core still requires a declaration file.
2020-03-20 04:02:49 +00:00
const FusionCharts = require ( "fusioncharts" ) ;
2021-03-24 22:05:04 +00:00
const plugins : Record < string , any > = {
Charts : require ( "fusioncharts/fusioncharts.charts" ) ,
FusionTheme : require ( "fusioncharts/themes/fusioncharts.theme.fusion" ) ,
Widgets : require ( "fusioncharts/fusioncharts.widgets" ) ,
ZoomScatter : require ( "fusioncharts/fusioncharts.zoomscatter" ) ,
ZoomLine : require ( "fusioncharts/fusioncharts.zoomline" ) ,
PowerCharts : require ( "fusioncharts/fusioncharts.powercharts" ) ,
TimeSeries : require ( "fusioncharts/fusioncharts.timeseries" ) ,
OverlappedColumn : require ( "fusioncharts/fusioncharts.overlappedcolumn2d" ) ,
OverlappedBar : require ( "fusioncharts/fusioncharts.overlappedbar2d" ) ,
TreeMap : require ( "fusioncharts/fusioncharts.treemap" ) ,
Maps : require ( "fusioncharts/fusioncharts.maps" ) ,
Gantt : require ( "fusioncharts/fusioncharts.gantt" ) ,
VML : require ( "fusioncharts/fusioncharts.vml" ) ,
} ;
2020-12-02 10:42:51 +00:00
2021-03-24 22:05:04 +00:00
// Enable all plugins.
// This is needed to support custom chart configs
Object . keys ( plugins ) . forEach ( ( key : string ) = >
( plugins [ key ] as any ) ( FusionCharts ) ,
) ;
2020-12-02 10:42:51 +00:00
2021-03-24 22:05:04 +00:00
const { fusioncharts } = getAppsmithConfigs ( ) ;
2020-12-02 10:42:51 +00:00
FusionCharts . options . license ( {
key : fusioncharts.licenseKey ,
creditLabel : false ,
} ) ;
2020-03-13 12:06:41 +00:00
export interface ChartComponentProps {
2021-10-25 11:39:39 +00:00
allowScroll : boolean ;
2021-04-26 10:35:59 +00:00
chartData : AllChartData ;
2020-03-13 12:06:41 +00:00
chartName : string ;
2021-08-26 09:58:43 +00:00
chartType : ChartType ;
customFusionChartConfig : CustomFusionChartConfig ;
2020-03-13 12:06:41 +00:00
isVisible? : boolean ;
2022-01-18 07:51:28 +00:00
isLoading : boolean ;
2021-09-06 12:15:58 +00:00
setAdaptiveYMin : boolean ;
2021-08-26 09:58:43 +00:00
labelOrientation? : LabelOrientation ;
2021-08-18 07:11:07 +00:00
onDataPointClick : ( selectedDataPoint : ChartSelectedDataPoint ) = > void ;
2021-08-26 09:58:43 +00:00
widgetId : string ;
xAxisName : string ;
yAxisName : string ;
2022-05-04 09:45:57 +00:00
borderRadius : string ;
boxShadow? : string ;
primaryColor? : string ;
2022-08-12 12:10:17 +00:00
fontFamily? : string ;
2020-03-13 12:06:41 +00:00
}
2021-03-04 05:24:47 +00:00
const CanvasContainer = styled . div <
Omit < ChartComponentProps , " onDataPointClick " >
> `
2022-05-04 09:45:57 +00:00
border - radius : $ { ( { borderRadius } ) = > borderRadius } ;
box - shadow : $ { ( { boxShadow } ) = > ` ${ boxShadow } ` } ! important ;
2020-03-13 12:06:41 +00:00
height : 100 % ;
width : 100 % ;
2022-08-12 12:10:17 +00:00
background : $ { Colors . WHITE } ;
2021-02-08 07:30:01 +00:00
overflow : hidden ;
2020-03-13 12:06:41 +00:00
position : relative ;
2020-12-24 04:32:25 +00:00
$ { ( props ) = > ( ! props . isVisible ? invisible : "" ) } ;
2020-04-15 11:42:11 +00:00
padding : 10px 0 0 0 ;
2020-03-13 12:06:41 +00:00
} ` ;
2021-08-26 09:58:43 +00:00
export const isLabelOrientationApplicableFor = ( chartType : string ) = >
LABEL_ORIENTATION_COMPATIBLE_CHARTS . includes ( chartType ) ;
2020-03-20 04:02:49 +00:00
class ChartComponent extends React . Component < ChartComponentProps > {
chartInstance = new FusionCharts ( ) ;
2021-03-24 22:05:04 +00:00
2021-08-26 09:58:43 +00:00
chartContainerId = this . props . widgetId + "chart-container" ;
2020-04-15 11:42:11 +00:00
getChartType = ( ) = > {
2021-10-25 11:39:39 +00:00
const { allowScroll , chartData , chartType } = this . props ;
2021-04-26 10:35:59 +00:00
const dataLength = Object . keys ( chartData ) . length ;
const isMSChart = dataLength > 1 ;
2020-03-13 12:06:41 +00:00
switch ( chartType ) {
case "PIE_CHART" :
return "pie2d" ;
2020-04-15 11:42:11 +00:00
case "LINE_CHART" :
2021-10-25 11:39:39 +00:00
return allowScroll ? "scrollline2d" : isMSChart ? "msline" : "line" ;
2020-04-15 11:42:11 +00:00
case "BAR_CHART" :
2021-10-25 11:39:39 +00:00
return allowScroll ? "scrollBar2D" : isMSChart ? "msbar2d" : "bar2d" ;
case "AREA_CHART" :
return allowScroll ? "scrollarea2d" : isMSChart ? "msarea" : "area2d" ;
2020-03-13 12:06:41 +00:00
case "COLUMN_CHART" :
2021-10-25 11:39:39 +00:00
return allowScroll
2020-04-15 11:42:11 +00:00
? "scrollColumn2D"
: isMSChart
? "mscolumn2d"
: "column2d" ;
2020-03-13 12:06:41 +00:00
default :
2021-10-25 11:39:39 +00:00
return allowScroll ? "scrollColumn2D" : "mscolumn2d" ;
2020-03-13 12:06:41 +00:00
}
} ;
2020-05-07 10:51:37 +00:00
getChartData = ( ) = > {
2021-04-26 10:35:59 +00:00
const chartData : AllChartData = this . props . chartData ;
const dataLength = Object . keys ( chartData ) . length ;
2022-12-09 07:17:21 +00:00
const chartType = this . props . chartType ;
2021-02-26 05:28:31 +00:00
2021-04-26 10:35:59 +00:00
// if datalength is zero, just pass a empty datum
if ( dataLength === 0 ) {
2020-05-07 10:51:37 +00:00
return [
{
label : "" ,
value : "" ,
} ,
] ;
}
2021-02-16 10:29:08 +00:00
2021-04-26 10:35:59 +00:00
const firstKey = Object . keys ( chartData ) [ 0 ] as string ;
let data = get ( chartData , ` ${ firstKey } .data ` , [ ] ) as ChartDataPoint [ ] ;
2022-12-09 07:17:21 +00:00
const color = chartData [ firstKey ] && chartData [ firstKey ] . color ;
2021-04-26 10:35:59 +00:00
if ( ! Array . isArray ( data ) ) {
data = [ ] ;
2021-02-16 10:29:08 +00:00
}
2021-04-26 10:35:59 +00:00
2020-04-29 10:29:02 +00:00
if ( data . length === 0 ) {
2020-05-07 10:51:37 +00:00
return [
{
label : "" ,
value : "" ,
} ,
] ;
2020-04-29 10:29:02 +00:00
}
2021-04-26 10:35:59 +00:00
2020-12-24 04:32:25 +00:00
return data . map ( ( item ) = > {
2020-03-13 12:06:41 +00:00
return {
label : item.x ,
value : item.y ,
2022-12-09 07:17:21 +00:00
color :
chartType === "PIE_CHART"
? ""
: color
? color
: this . props . primaryColor ,
2020-03-13 12:06:41 +00:00
} ;
} ) ;
} ;
2021-08-26 09:58:43 +00:00
getChartCategoriesMultiSeries = ( chartData : AllChartData ) = > {
2020-04-15 11:42:11 +00:00
const categories : string [ ] = [ ] ;
2021-04-26 10:35:59 +00:00
Object . keys ( chartData ) . forEach ( ( key : string ) = > {
let data = get ( chartData , ` ${ key } .data ` , [ ] ) as ChartDataPoint [ ] ;
if ( ! Array . isArray ( data ) ) {
data = [ ] ;
}
2020-04-15 11:42:11 +00:00
for ( let dataIndex = 0 ; dataIndex < data . length ; dataIndex ++ ) {
const category = data [ dataIndex ] . x ;
if ( ! categories . includes ( category ) ) {
categories . push ( category ) ;
}
}
2021-04-26 10:35:59 +00:00
} ) ;
2020-04-15 11:42:11 +00:00
return categories ;
} ;
2021-04-26 10:35:59 +00:00
getChartCategories = ( chartData : AllChartData ) = > {
2021-08-26 09:58:43 +00:00
const categories : string [ ] = this . getChartCategoriesMultiSeries ( chartData ) ;
2021-04-26 10:35:59 +00:00
2020-04-29 10:29:02 +00:00
if ( categories . length === 0 ) {
2021-02-26 05:28:31 +00:00
return [
{
label : "" ,
} ,
] ;
2020-04-29 10:29:02 +00:00
}
2020-12-24 04:32:25 +00:00
return categories . map ( ( item ) = > {
2020-04-15 11:42:11 +00:00
return {
label : item ,
} ;
} ) ;
} ;
2021-04-26 10:35:59 +00:00
/ * *
* creates dataset need by fusion chart from widget object - data
*
* @param chartData
* @returns
* /
getChartDataset = ( chartData : AllChartData ) = > {
2021-08-26 09:58:43 +00:00
const categories : string [ ] = this . getChartCategoriesMultiSeries ( chartData ) ;
2021-04-26 10:35:59 +00:00
2022-12-09 07:17:21 +00:00
const dataset = Object . keys ( chartData ) . map ( ( key : string , index ) = > {
2021-04-26 10:35:59 +00:00
const item = get ( chartData , ` ${ key } ` ) ;
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
const seriesChartData : Array < Record < string , unknown > > =
getSeriesChartData ( get ( item , "data" , [ ] ) , categories ) ;
2020-04-15 11:42:11 +00:00
return {
seriesName : item.seriesName ,
2022-12-09 07:17:21 +00:00
color : item.color
? item . color
: index === 0
? this . props . primaryColor
: "" ,
2020-04-15 11:42:11 +00:00
data : seriesChartData ,
} ;
} ) ;
2021-04-26 10:35:59 +00:00
return dataset ;
2020-04-15 11:42:11 +00:00
} ;
2021-08-26 09:58:43 +00:00
getLabelOrientationConfig = ( ) = > {
switch ( this . props . labelOrientation ) {
case LabelOrientation . AUTO :
return { } ;
case LabelOrientation . ROTATE :
return {
labelDisplay : "rotate" ,
slantLabel : "0" ,
} ;
case LabelOrientation . SLANT :
return {
labelDisplay : "rotate" ,
slantLabel : "1" ,
} ;
case LabelOrientation . STAGGER :
return {
labelDisplay : "stagger" ,
} ;
default : {
return { } ;
}
}
} ;
2020-04-15 11:42:11 +00:00
getChartConfig = ( ) = > {
2022-08-12 12:10:17 +00:00
const isSingleSeriesData = this . getDatalength ( ) === 1 ? true : false ;
const paletteColorConfig = isSingleSeriesData &&
this . props . chartType !== "PIE_CHART" && {
palettecolors : [ this . props . primaryColor ] ,
} ;
const fontFamily =
this . props . fontFamily === "System Default"
? "inherit"
: this . props . fontFamily ;
const canvasPadding =
this . props . chartType === "LINE_CHART"
? {
canvasLeftPadding : "5" ,
canvasTopPadding : "0" ,
canvasRightPadding : "5" ,
canvasBottomPadding : "0" ,
}
: {
canvasPadding : "0" ,
} ;
2021-08-26 09:58:43 +00:00
let config = {
2020-04-15 11:42:11 +00:00
caption : this.props.chartName ,
xAxisName : this.props.xAxisName ,
yAxisName : this.props.yAxisName ,
theme : "fusion" ,
2022-08-12 12:10:17 +00:00
alignCaptionWithCanvas : 1 ,
// Caption styling =======================
captionFontSize : "24" ,
captionAlignment : "center" ,
captionPadding : "20" ,
captionFontColor : Colors.THUNDER ,
// legend position styling ==========
legendIconSides : "4" ,
legendIconBgAlpha : "100" ,
legendIconAlpha : "100" ,
legendItemFont : fontFamily ,
legendPosition : "top" ,
valueFont : fontFamily ,
// Canvas styles ========
. . . canvasPadding ,
// Chart styling =======
chartLeftMargin : "20" ,
chartTopMargin : "10" ,
chartRightMargin : "40" ,
chartBottomMargin : "10" ,
// Axis name styling ======
xAxisNameFontSize : "14" ,
labelFontSize : "12" ,
labelFontColor : Colors.DOVE_GRAY2 ,
xAxisNameFontColor : Colors.DOVE_GRAY2 ,
yAxisNameFontSize : "14" ,
yAxisValueFontSize : "12" ,
yAxisValueFontColor : Colors.DOVE_GRAY2 ,
yAxisNameFontColor : Colors.DOVE_GRAY2 ,
// Base configurations ======
baseFont : fontFamily ,
. . . paletteColorConfig ,
bgColor : Colors.WHITE ,
2021-09-06 12:15:58 +00:00
setAdaptiveYMin : this.props.setAdaptiveYMin ? "1" : "0" ,
2020-04-15 11:42:11 +00:00
} ;
2021-08-26 09:58:43 +00:00
if ( isLabelOrientationApplicableFor ( this . props . chartType ) ) {
config = {
. . . config ,
. . . this . getLabelOrientationConfig ( ) ,
} ;
}
return config ;
2020-04-15 11:42:11 +00:00
} ;
2021-08-18 07:11:07 +00:00
getDatalength = ( ) = > {
return Object . keys ( this . props . chartData ) . length ;
} ;
2020-04-15 11:42:11 +00:00
getChartDataSource = ( ) = > {
2021-08-18 07:11:07 +00:00
const dataLength = this . getDatalength ( ) ;
2021-04-26 10:35:59 +00:00
if ( dataLength <= 1 || this . props . chartType === "PIE_CHART" ) {
2020-04-15 11:42:11 +00:00
return {
chart : this.getChartConfig ( ) ,
2020-05-07 10:51:37 +00:00
data : this.getChartData ( ) ,
2020-04-15 11:42:11 +00:00
} ;
} else {
return {
chart : this.getChartConfig ( ) ,
categories : [
{
2020-04-15 15:26:36 +00:00
category : this.getChartCategories ( this . props . chartData ) ,
2020-04-15 11:42:11 +00:00
} ,
] ,
2020-04-15 15:26:36 +00:00
dataset : this.getChartDataset ( this . props . chartData ) ,
2020-04-15 11:42:11 +00:00
} ;
}
} ;
2021-03-24 22:05:04 +00:00
getCustomFusionChartDataSource = ( ) = > {
2022-04-15 10:58:13 +00:00
// in case of evaluation error, customFusionChartConfig can be undefined
2021-03-24 22:05:04 +00:00
let config = this . props . customFusionChartConfig as CustomFusionChartConfig ;
if ( config && config . dataSource ) {
config = {
. . . config ,
dataSource : {
chart : {
. . . config . dataSource . chart ,
caption : this.props.chartName || config . dataSource . chart . caption ,
2021-09-06 12:15:58 +00:00
setAdaptiveYMin : this.props.setAdaptiveYMin ? "1" : "0" ,
2021-03-24 22:05:04 +00:00
} ,
2022-08-12 12:10:17 +00:00
. . . config . dataSource ,
2021-03-24 22:05:04 +00:00
} ,
} ;
}
2022-04-15 10:58:13 +00:00
return config || { } ;
2021-03-24 22:05:04 +00:00
} ;
2020-04-15 11:42:11 +00:00
getScrollChartDataSource = ( ) = > {
const chartConfig = this . getChartConfig ( ) ;
2021-02-26 05:28:31 +00:00
2020-04-15 11:42:11 +00:00
return {
chart : {
. . . chartConfig ,
scrollheight : "10" ,
showvalues : "1" ,
numVisiblePlot : "5" ,
flatScrollBars : "1" ,
} ,
categories : [
{
2020-04-15 15:26:36 +00:00
category : this.getChartCategories ( this . props . chartData ) ,
2020-04-15 11:42:11 +00:00
} ,
] ,
2021-02-26 05:28:31 +00:00
data : this.getChartData ( ) ,
2020-04-15 15:26:36 +00:00
dataset : this.getChartDataset ( this . props . chartData ) ,
2020-04-15 11:42:11 +00:00
} ;
} ;
2021-08-18 07:11:07 +00:00
// return series title name for in clicked data point
getSeriesTitle = ( data : any ) = > {
2022-08-23 13:32:57 +00:00
const dataLength = this . getDatalength ( ) ;
// if pie chart or other chart have single dataset,
// get seriesName from chartData
if (
( dataLength <= 1 || this . props . chartType === "PIE_CHART" ) &&
this . props . chartType !== "CUSTOM_FUSION_CHART"
) {
const chartData : AllChartData = this . props . chartData ;
const firstKey = Object . keys ( chartData ) [ 0 ] as string ;
return get ( chartData , ` ${ firstKey } .seriesName ` , "" ) ;
2021-08-18 07:11:07 +00:00
}
2022-08-23 13:32:57 +00:00
// other charts return datasetName from clicked data point
return get ( data , "datasetName" , "" ) ;
2021-08-18 07:11:07 +00:00
} ;
2020-03-20 04:02:49 +00:00
createGraph = ( ) = > {
2021-03-24 22:05:04 +00:00
if ( this . props . chartType === "CUSTOM_FUSION_CHART" ) {
const chartConfig = {
2021-08-26 09:58:43 +00:00
renderAt : this.chartContainerId ,
2021-03-24 22:05:04 +00:00
width : "100%" ,
height : "100%" ,
2021-05-28 06:16:11 +00:00
events : {
dataPlotClick : ( evt : any ) = > {
const data = evt . data ;
2021-08-18 07:11:07 +00:00
const seriesTitle = this . getSeriesTitle ( data ) ;
2021-05-28 06:16:11 +00:00
this . props . onDataPointClick ( {
x : data.categoryLabel ,
y : data.dataValue ,
2021-08-18 07:11:07 +00:00
seriesTitle ,
2021-05-28 06:16:11 +00:00
} ) ;
} ,
} ,
2021-03-24 22:05:04 +00:00
. . . this . getCustomFusionChartDataSource ( ) ,
} ;
this . chartInstance = new FusionCharts ( chartConfig ) ;
return ;
}
2020-04-15 11:42:11 +00:00
const dataSource =
2021-10-25 11:39:39 +00:00
this . props . allowScroll && this . props . chartType !== "PIE_CHART"
2020-04-15 11:42:11 +00:00
? this . getScrollChartDataSource ( )
: this . getChartDataSource ( ) ;
2021-02-26 05:28:31 +00:00
2020-03-20 04:02:49 +00:00
const chartConfig = {
2020-04-15 11:42:11 +00:00
type : this . getChartType ( ) ,
2021-08-26 09:58:43 +00:00
renderAt : this.chartContainerId ,
2020-03-20 04:02:49 +00:00
width : "100%" ,
height : "100%" ,
dataFormat : "json" ,
2020-04-15 11:42:11 +00:00
dataSource : dataSource ,
2021-02-22 16:31:13 +00:00
events : {
dataPlotClick : ( evt : any ) = > {
const data = evt . data ;
2021-08-18 07:11:07 +00:00
const seriesTitle = this . getSeriesTitle ( data ) ;
2021-02-22 16:31:13 +00:00
this . props . onDataPointClick ( {
x : data.categoryLabel ,
y : data.dataValue ,
2021-08-18 07:11:07 +00:00
seriesTitle ,
2021-02-22 16:31:13 +00:00
} ) ;
} ,
} ,
2020-03-20 04:02:49 +00:00
} ;
2021-02-26 05:28:31 +00:00
2020-03-20 04:02:49 +00:00
this . chartInstance = new FusionCharts ( chartConfig ) ;
} ;
componentDidMount() {
this . createGraph ( ) ;
FusionCharts . ready ( ( ) = > {
2020-12-02 10:42:51 +00:00
/ * C o m p o n e n t c o u l d b e u n m o u n t e d b e f o r e F u s i o n C h a r t s i s r e a d y ,
2020-08-28 09:52:18 +00:00
this check ensure we don ' t render on unmounted component * /
if ( this . chartInstance ) {
2021-03-24 22:05:04 +00:00
try {
this . chartInstance . render ( ) ;
} catch ( e ) {
log . error ( e ) ;
}
2020-08-28 09:52:18 +00:00
}
2020-03-20 04:02:49 +00:00
} ) ;
}
2020-08-28 09:52:18 +00:00
componentWillUnmount() {
if ( this . chartInstance ) {
this . chartInstance = null ;
}
}
2020-03-20 04:02:49 +00:00
componentDidUpdate ( prevProps : ChartComponentProps ) {
2022-09-02 09:16:30 +00:00
if ( ! equal ( prevProps , this . props ) ) {
2020-04-15 11:42:11 +00:00
const chartType = this . getChartType ( ) ;
this . chartInstance . chartType ( chartType ) ;
2022-04-15 10:58:13 +00:00
if ( this . props . chartType === "CUSTOM_FUSION_CHART" ) {
const { dataSource , type } = this . getCustomFusionChartDataSource ( ) ;
this . chartInstance . chartType ( type ) ;
this . chartInstance . setChartData ( dataSource ) ;
} else if (
this . props . allowScroll &&
this . props . chartType !== "PIE_CHART"
) {
2020-04-15 11:42:11 +00:00
this . chartInstance . setChartData ( this . getScrollChartDataSource ( ) ) ;
2020-03-20 04:02:49 +00:00
} else {
2020-04-15 11:42:11 +00:00
this . chartInstance . setChartData ( this . getChartDataSource ( ) ) ;
2020-03-20 04:02:49 +00:00
}
}
}
render() {
2021-03-04 05:24:47 +00:00
//eslint-disable-next-line @typescript-eslint/no-unused-vars
const { onDataPointClick , . . . rest } = this . props ;
2022-01-18 07:51:28 +00:00
return (
< CanvasContainer
className = { this . props . isLoading ? "bp3-skeleton" : "" }
{ . . . rest }
id = { this . chartContainerId }
/ >
) ;
2020-03-20 04:02:49 +00:00
}
}
2020-03-13 12:06:41 +00:00
export default ChartComponent ;