From 4b53100166133d742f271b184409fd3ec6fe8ac5 Mon Sep 17 00:00:00 2001 From: "Xie, Ziyu" Date: Fri, 10 Nov 2023 10:31:32 +0800 Subject: [PATCH] feat: support standalone directive (#411) --- README.md | 294 ++++++++++-------- projects/ngx-echarts/package.json | 2 +- .../src/lib/ngx-echarts.directive.ts | 1 + .../ngx-echarts/src/lib/ngx-echarts.module.ts | 23 +- src/app/app.module.ts | 7 +- src/app/pages/welcome/welcome.component.html | 7 +- src/app/pages/welcome/welcome.component.ts | 20 +- 7 files changed, 212 insertions(+), 142 deletions(-) diff --git a/README.md b/README.md index 678a47e4..63c4f1f4 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,19 @@ Angular directive for [Apache ECharts (incubating)](https://github.com/apache/in - [Installation](#installation) - [Upgrade from v4.x](#upgrade-from-v4x) - [Usage](#usage) + - [Standalone](#standalone) + - [NgModule](#ngmodule) + - [Directive](#directive) - [API](#api) - - [Directive](#directive) + - [Directive](#directive-1) - [ECharts API](#echarts-api) - [ECharts Instance](#echarts-instance) - [ECharts Extensions](#echarts-extensions) - [Service](#service) - [Events](#events) - [Custom Build](#custom-build) - - [Legacy Custom Build](#legacy-custom-build) - [Treeshaking Custom Build](#treeshaking-custom-build) + - [Legacy Custom Build](#legacy-custom-build) - [Custom Locale](#custom-locale) - [Demo](#demo) @@ -42,8 +45,8 @@ Angular directive for [Apache ECharts (incubating)](https://github.com/apache/in Latest version @npm: -- `v17.0.1` for Angular 17 -- `v16.1.2` for Angular 16 +- `v17.1.0` for Angular 17 +- `v16.2.0` for Angular 16 - `v15.0.3` for Angular 15 - `v14.0.0` for Angular 14 - `v8.0.1` for Angular 13 @@ -56,6 +59,10 @@ A starter project on Github: https://github.com/xieziyu/ngx-echarts-starter # Latest Update +- 2023.11.10: v17.1.0 / v16.2.0: + + - Feat: Exported standalone `NgxEchartsDirective`, `provideEcharts` and `provideEchartsCore` + - 2023.11.08: v17.0.1: - Feat: upgrade to Angular 17 @@ -98,10 +105,6 @@ A starter project on Github: https://github.com/xieziyu/ngx-echarts-starter - Fix: remove @juggle/resize-observer from the peer dependencies - Perf: fix performance issue [#330](https://github.com/xieziyu/ngx-echarts/issues/330) -- 2021.08.05: v7.0.2: - - - [PR #322](https://github.com/xieziyu/ngx-echarts/pull/322): Add initOpts locale property (by [augustoicaro](https://github.com/augustoicaro)) - - 2021.05.17: v7.0.0: - Feat: support Angular v11, ECharts v5 @@ -172,107 +175,105 @@ A starter project on Github: https://github.com/xieziyu/ngx-echarts-starter Please refer to the [demo](https://xieziyu.github.io/ngx-echarts) page. -1. Firstly, import `NgxEchartsModule` in your app module (or any other proper angular module): - - ```typescript - import { NgxEchartsModule } from 'ngx-echarts'; - - @NgModule({ - imports: [ - NgxEchartsModule.forRoot({ - /** - * This will import all modules from echarts. - * If you only need custom modules, - * please refer to [Custom Build] section. - */ - echarts: () => import('echarts'), // or import('./path-to-my-custom-echarts') - }), - ], - }) - export class AppModule {} - ``` +## Standalone - The echarts library will be imported **only when it gets called the first time** thanks to the function that uses the native import. +import `NgxEchartsDirective` and `provideEcharts`. Or you can use `provideEchartsCore` to do treeshaking custom build. - You can also directly pass the echarts instead which will slow down initial rendering because it will load the whole echarts into your main bundle. +```typescript +import { NgxEchartsDirective, provideEcharts } from 'ngx-echarts'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [CommonModule, NgxEchartsDirective], + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], + providers: [ + provideEcharts(), + ] +}) +export class AppComponent {} +``` - ```typescript - import * as echarts from 'echarts'; - import { NgxEchartsModule } from 'ngx-echarts'; +## NgModule - @NgModule({ - imports: [ - NgxEchartsModule.forRoot({ echarts }), - ], - }) - export class AppModule {} - ``` +import `NgxEchartsModule`: - When using NgxEchartsModule in a **standalone component**, we can use token `NGX_ECHARTS_CONFIG` to provide echarts - - ```typescript - import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts'; - - @Component({ - standalone: true, - selector: 'my-chart', - template: ` -
- `, - imports: [NgxEchartsModule], - providers: [ - { - provide: NGX_ECHARTS_CONFIG, - useFactory: () => ({ echarts: () => import('echarts') }) - }, - ] - }) - export class MyChartComponent { - // logic - } - ``` +```typescript +import { NgxEchartsModule } from 'ngx-echarts'; -2. Then: use `echarts` directive in a div which has **pre-defined height**. (From v2.0, it has default height: 400px) +@NgModule({ + imports: [ + NgxEchartsModule.forRoot({ + /** + * This will import all modules from echarts. + * If you only need custom modules, + * please refer to [Custom Build] section. + */ + echarts: () => import('echarts'), // or import('./path-to-my-custom-echarts') + }), + ], +}) +export class AppModule {} +``` + +The echarts library will be imported **only when it gets called the first time** thanks to the function that uses the native import. + +You can also directly pass the echarts instead which will slow down initial rendering because it will load the whole echarts into your main bundle. + +```typescript +import * as echarts from 'echarts'; +import { NgxEchartsModule } from 'ngx-echarts'; - - Simple example: +@NgModule({ + imports: [ + NgxEchartsModule.forRoot({ echarts }), + ], +}) +export class AppModule {} +``` - - html: +## Directive - ```html -
- ``` +use `echarts` directive in a div which has **pre-defined height**. (From v2.0, it has default height: 400px) - - scss: +- html: - ```css - .demo-chart { - height: 400px; - } - ``` +```html +
+``` - - component: +- css: - ```typescript - import { EChartsOption } from 'echarts'; +```css +.demo-chart { + height: 400px; +} +``` - // ... +- component: - chartOption: EChartsOption = { - xAxis: { - type: 'category', - data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], - }, - yAxis: { - type: 'value', - }, - series: [ - { - data: [820, 932, 901, 934, 1290, 1330, 1320], - type: 'line', - }, - ], - }; - ``` +```typescript +import { EChartsOption } from 'echarts'; + +// ... + +chartOption: EChartsOption = { + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + }, + yAxis: { + type: 'value', + }, + series: [ + { + data: [820, 932, 901, 934, 1290, 1330, 1320], + type: 'line', + }, + ], +}; +``` # API @@ -413,6 +414,76 @@ You can refer to the ECharts tutorial: [Events and Actions in ECharts](https://e # Custom Build +## Treeshaking Custom Build + +> Since version 5.0.1 ECharts supports [Treeshaking with NPM](https://echarts.apache.org/en/tutorial.html#Use%20ECharts%20with%20bundler%20and%20NPM). + +The `app.modules.ts` should look like this: + +```typescript +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { HttpClientModule } from '@angular/common/http'; + +import { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts'; + +import { AppComponent } from './app.component'; + +// Import the echarts core module, which provides the necessary interfaces for using echarts. +import * as echarts from 'echarts/core'; + +// Import bar charts, all suffixed with Chart +import { BarChart } from 'echarts/charts'; + +// Import the tooltip, title, rectangular coordinate system, dataset and transform components +import { + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent +} from 'echarts/components'; + +// Features like Universal Transition and Label Layout +import { LabelLayout, UniversalTransition } from 'echarts/features'; + +// Import the Canvas renderer +// Note that including the CanvasRenderer or SVGRenderer is a required step +import { CanvasRenderer } from 'echarts/renderers'; + +// Import the theme +import 'echarts/theme/macarons.js'; + +// Register the required components +echarts.use([ + BarChart, + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + LabelLayout, + UniversalTransition, + CanvasRenderer +]); + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + HttpClientModule, + // import standalone directive: + NgxEchartsDirective, + ], + providers: [{ + // Provide custom builded ECharts core: + provideEchartsCore({ echarts }) + }], + bootstrap: [AppComponent], +}) +export class AppModule {} +``` + ## Legacy Custom Build > Please refer to [ECharts Documentation](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) for more details. @@ -471,41 +542,6 @@ function (root, factory) { } ``` -## Treeshaking Custom Build - -> Since version 5.0.1 ECharts supports [Treeshaking with NPM](https://echarts.apache.org/en/tutorial.html#Use%20ECharts%20with%20bundler%20and%20NPM). - -There is no need for the `custom-echarts.ts` file anymore. The `app.modules.ts` should look like this: - -```typescript -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; - -import { NgxEchartsModule } from 'ngx-echarts'; - -import { AppComponent } from './app.component'; - -// Import the echarts core module, which provides the necessary interfaces for using echarts. -import * as echarts from 'echarts/core'; -// Import bar charts, all with Chart suffix -import { BarChart } from 'echarts/charts'; -import { TitleComponent, TooltipComponent, GridComponent } from 'echarts/components'; -// Import the Canvas renderer, note that introducing the CanvasRenderer or SVGRenderer is a required step -import { CanvasRenderer } from 'echarts/renderers'; -import 'echarts/theme/macarons.js'; - -echarts.use([TitleComponent, TooltipComponent, GridComponent, BarChart, CanvasRenderer]); - -@NgModule({ - declarations: [AppComponent], - imports: [BrowserModule, NgxEchartsModule.forRoot({ echarts }), HttpClientModule], - providers: [], - bootstrap: [AppComponent], -}) -export class AppModule {} -``` - # Custom Locale You can change the chart locale registering a built-in locale (located in `node_modules/echarts/lib/i18n/`) or a custom locale object. To register a locale, you will need to change the module that echart is being imported (usually `app.module.ts`). diff --git a/projects/ngx-echarts/package.json b/projects/ngx-echarts/package.json index 18bd2c8b..d3a7d677 100644 --- a/projects/ngx-echarts/package.json +++ b/projects/ngx-echarts/package.json @@ -1,6 +1,6 @@ { "name": "ngx-echarts", - "version": "17.0.1", + "version": "17.1.0", "author": "Xie, Ziyu", "license": "MIT", "keywords": [ diff --git a/projects/ngx-echarts/src/lib/ngx-echarts.directive.ts b/projects/ngx-echarts/src/lib/ngx-echarts.directive.ts index b85f86a9..0dec96e1 100644 --- a/projects/ngx-echarts/src/lib/ngx-echarts.directive.ts +++ b/projects/ngx-echarts/src/lib/ngx-echarts.directive.ts @@ -27,6 +27,7 @@ export type ThemeOption = Record; export const NGX_ECHARTS_CONFIG = new InjectionToken('NGX_ECHARTS_CONFIG'); @Directive({ + standalone: true, selector: 'echarts, [echarts]', exportAs: 'echarts', }) diff --git a/projects/ngx-echarts/src/lib/ngx-echarts.module.ts b/projects/ngx-echarts/src/lib/ngx-echarts.module.ts index 64df1f9a..650fb095 100644 --- a/projects/ngx-echarts/src/lib/ngx-echarts.module.ts +++ b/projects/ngx-echarts/src/lib/ngx-echarts.module.ts @@ -1,4 +1,4 @@ -import { NgModule, ModuleWithProviders } from '@angular/core'; +import { NgModule, ModuleWithProviders, Provider } from '@angular/core'; import { NgxEchartsDirective, NgxEchartsConfig, @@ -6,16 +6,29 @@ import { ThemeOption, } from './ngx-echarts.directive'; +const provideEcharts = (): Provider => { + return { + provide: NGX_ECHARTS_CONFIG, + useFactory: () => ({ echarts: () => import('echarts') }), + }; +}; + +const provideEchartsCore = (config: NgxEchartsConfig): Provider => { + return { + provide: NGX_ECHARTS_CONFIG, + useValue: config, + }; +}; + @NgModule({ - imports: [], - declarations: [NgxEchartsDirective], + imports: [NgxEchartsDirective], exports: [NgxEchartsDirective], }) export class NgxEchartsModule { static forRoot(config: NgxEchartsConfig): ModuleWithProviders { return { ngModule: NgxEchartsModule, - providers: [{ provide: NGX_ECHARTS_CONFIG, useValue: config }], + providers: [provideEchartsCore(config)], }; } static forChild(): ModuleWithProviders { @@ -25,4 +38,4 @@ export class NgxEchartsModule { } } -export { NgxEchartsDirective, NGX_ECHARTS_CONFIG, ThemeOption }; +export { NgxEchartsDirective, NGX_ECHARTS_CONFIG, ThemeOption, provideEcharts, provideEchartsCore }; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8e6ea0b2..80a63584 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -7,7 +7,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { registerLocaleData, LocationStrategy, HashLocationStrategy } from '@angular/common'; import en from '@angular/common/locales/en'; import { NgZorroCustomModule } from './shared/ng-zorro-custom.module'; -import { NgxEchartsModule } from 'ngx-echarts'; +import { NgxEchartsDirective, provideEcharts } from 'ngx-echarts'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -31,15 +31,14 @@ registerLocaleData(en); MarkdownModule.forRoot(), HttpClientModule, BrowserAnimationsModule, - NgxEchartsModule.forRoot({ - echarts: () => import('echarts'), // Import all modules from echarts: - }), + NgxEchartsDirective, ], providers: [ { provide: LocationStrategy, useClass: HashLocationStrategy, }, + provideEcharts(), ], bootstrap: [AppComponent], }) diff --git a/src/app/pages/welcome/welcome.component.html b/src/app/pages/welcome/welcome.component.html index 3a5fd886..f147037b 100644 --- a/src/app/pages/welcome/welcome.component.html +++ b/src/app/pages/welcome/welcome.component.html @@ -37,11 +37,14 @@

-
+
-
+
+
+ +
diff --git a/src/app/pages/welcome/welcome.component.ts b/src/app/pages/welcome/welcome.component.ts index 88558a60..5c55e639 100644 --- a/src/app/pages/welcome/welcome.component.ts +++ b/src/app/pages/welcome/welcome.component.ts @@ -17,7 +17,25 @@ export class WelcomeComponent { \`\`\` `; importText = ` - ## Import + ## Import Standalone Directive + \`\`\`typescript + import { NgxEchartsDirective, provideEcharts } from 'ngx-echarts'; + + @Component({ + selector: 'app-root', + standalone: true, + imports: [CommonModule, NgxEchartsDirective], + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], + providers: [ + provideEcharts(), + ] + }) + export class AppComponent {} + \`\`\` +`; + importNgModuleText = ` + ## Import NgModule \`\`\`typescript import { NgxEchartsModule } from 'ngx-echarts'; @NgModule({