【问题标题】:Angular Highcharts - How to clone chart dynamicallyAngular Highcharts - 如何动态克隆图表
【发布时间】:2018-10-05 16:05:59
【问题描述】:

我在本地使用以下 highcharts 依赖项:

  • “angular-highcharts”:“最新”
  • “highcharts”:“最新”
  • “@types/highcharts”:“最新”

这是我的源代码的实时demo

我在我的 angular 5 应用程序中广泛使用 angular-highcharts。很多时候需要扩展图表(当图表上有很多数据点可见时),以适应这种情况,我想创建一个通用组件。

这个名为 chart-widget 的组件在引导卡中显示图表,并带有展开图表的选项,在展开时,相同的图表将在模式中打开。这个通用组件将负责在模式中打开任何图表所需的所有逻辑(可以拖动和调整大小)。这样我们就不需要在每个地方都复制相同的功能。

我制作了一个通用组件,过去一切正常,但最近我们升级了我们的 repo 依赖项,因为我们使用的 highcharts 版本中存在一些其他问题,这些问题在最新版本的 highcharts 中得到了修复,所以我们认为最好升级到最新版本。此后此功能停止工作。

在模态打开时用于克隆 chartConfig 的以下逻辑。然后将克隆的配置传递给位于模式内的扩展图表。但是现在展开的图表现在总是空白。

this.expandChartConfig = new Chart(Object.assign({}, this.chartConfig.options));

其中 chartConfig 是用于渲染图表的常规配置,

expandChartConfig 是传递给 modal 的图表对象。

升级后我发现 chartConfig.options 属性现在已设为私有,所以我也尝试了:

this.expandChartConfig = new Chart(Object.assign({}, this.chartConfig.ref.options));

但这也没有用。

最初我对两个图表使用相同的配置,但这会导致关闭模式时出现问题 highChart 也被破坏。所以我认为在打开模式时为模式内的图表实例化一个单独的配置是最好的情况。

所以现在简单来说,我的问题是如何动态地克隆现有图表

  • 数十个地方都需要此功能,因此我无法在每个地方都维护单独的图表对象。

  • 还有很多在图表上执行的操作,如 setData、setCategories、addSeries、removeSeries、update 等。这就是为什么不建议在每次操作时维护副本和更新它们的原因。此外,这些操作将由父组件执行,因此 ChartWidgetComponent 在执行时无法察觉这些更改。

简而言之,如何动态克隆现有的 highchart 以及最好的方法是什么?

附:我尝试了 stackOverflow 上提到的一堆方法,但似乎都没有工作。

【问题讨论】:

  • 我认为最好的方法是在模态容器中创建一个新图表,并传递相同的选项(参考)。然后,如果用户使用它,您的图表应该改变数据,因为两个图表都可以在相同的数据引用上工作。您能否在某个沙盒(即 stackblitz 或代码沙盒)上重现您的应用程序的最小工作示例,并提供给我?
  • @daniel_s 我确实在问题顶部提供了指向 stackBlitz 的链接。在这里,stackblitz.com/edit/highcharts-cloning-chart

标签: javascript angular highcharts angular2-highcharts


【解决方案1】:

为了达到预期的效果,不幸的是,如果您之前(最初)没有定义系列数据,复制chart.options并将其传递给新的是不够的。在这种情况下,您需要获取数据(来自响应)并将其分配给新的组件变量,然后将其传递给小部件并更新您的系列。以下是如何操作的说明:

在组件中添加新字段:

export class AppComponent {
  chartConfig: Chart;
  chartData: Object;
...

将响应分配给创建的字段:

private setChartData(chartData) {
  const options = this.chartConfig.ref.options;
  if (chartData.categories.length === 0) {
    options.lang.noData = `no data from: ${chartData.customMsgFromDate} to ${chartData.customMsgEndDate}.`;
  } else {
    options.lang.noData = 'No data to display';
  }
this.chartData = chartData;

将数据传递给小部件:

<app-chart-widget [chartConfig]="chartConfig" chartLabel="Title" [chartData]="chartData"></app-chart-widget>

将每个系列的数据添加到新图表选项中:

onExpandChart(content): void {
  this.expandChartConfig = new Chart(this.chartConfig.ref.options);
  // Clone series data
  this.expandChartConfig.options.series.forEach((s, i) => {
    let name = s.name.toLowerCase()
    s.data = this.chartData[name]
  })

  this.modalService.open(content, { size: 'xl' as 'lg' });
  setTimeout(() => {
    this.resizeChart();
  ...

现场示例: https://stackblitz.com/edit/highcharts-cloning-chart-bo3tfp

亲切的问候!

【讨论】:

  • 那么为了概括这个图表数据必须采用预定义的格式。问题是它们可以是 n 个静态或动态系列。在静态系列的情况下,我可以有图表数据的预定义格式。但是在动态系列的情况下,我不仅要调用 this.chartConfig.ref.addSeries 还要更新 chartConfig,所以克隆时使用的实际配置与实际图表同步?同样在 this.chartConfig.ref.removeSeries 时,我必须执行相同的步骤。
  • 具有状态的组件的一般概念是将状态存储在一个地方,并与需要该数据的所有其他组件共享。然后,如果您想更改它,只需在一个地方进行,所有组件都具有相同的来源。而不是使用addSeries() 方法,只需通过新的系列对象更新您的组件状态,并在图表上调用update(),以使您的图表数据(主数据种子)始终保持最新。顺便问一下,您是否尝试过使用官方的 Highcharts 包装器?
  • 这真的很奇怪。我从来没有意识到我没有使用官方的。我猜官方是一年前发布的,在这个项目开始的时候,anuglar-highcharts 是唯一的。但我也会试试官方的。真的谢谢伙计。你是英雄! :)
  • 享受吧!另外我可以说,官方版本更好,使用更简单,当然是 Highcharts 开发人员最常用和直接支持的,并且有很好的文档。此外,我们正在尝试尽快解决包装器的问题。
  • 另外,如果我使用官方的,那么我想我不必为 highcharts 维护单独的类型定义,对吧?那太好了,因为更新 highcharts-angular 可以确保类型定义始终保持同步。
【解决方案2】:

我也在使用 Highcharts,我已经将一个图表定义为一个可重用的组件,当我想绘制另一个图表时,我只需通过 Input()decorattor 传递值

在这种情况下,您可以使用以下内容:

图表组件 ts

@Component ({
    selector: 'char-component'
    ...
})
export class CharComponent {
  Input() options: any; 
} 

可重用组件实现

<char-component [options]="firstObject"></char-component>
<char-component [options]="secondObject"></char-component>

要重用代码的组件

export clas Sample implements OnInit {
  ngOninit(){
     firstObject = {...} //Already defined
     secondObject = Object.assign(this.firstObject); //create a copy of this object

  }
}

注意:如果您不知道总共有多少图表,您可以使用带有 options 对象的数组并在模板中绘制,如果您需要另一个,只需将其推入数组中

<char-component *ngfor="option of options" [options]="option "></char-component>

【讨论】:

  • 貌似,你误会了,我有chartWidget组件,它基本上是一个图表的包装器,在扩展它的时候,chartWiget需要克隆当前图表选项并在其中打开一个单独的图表一个模态。我已经尝试过 object.assign() 的方式,但它不起作用,如果你能看一下链接的演示,那就太好了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
  • 2016-04-04
  • 1970-01-01
  • 2019-12-17
  • 2011-05-08
  • 2012-02-10
  • 1970-01-01
相关资源
最近更新 更多