Angular Highcharts - Как динамически клонировать диаграмму

Я локально использую следующие зависимости highcharts:

  • "angular-highcharts": "последний"
  • "highcharts": "последний"
  • "@ types / highcharts": "последний"

Вот живая демонстрация моего исходного кода,

Я широко использую angular-highcharts в моем приложении angular 5. Много времени необходимо расширить диаграмму (когда на диаграмме видно много точек данных), чтобы учесть такие случаи, я хотя бы создал общий компонент.

Этот компонент с именем chart-widget отображает диаграмму в загрузочной карточке с возможностью раскрытия диаграммы, в развернутом виде та же диаграмма открывается в модальном окне. Этот общий компонент позаботится обо всей логике, необходимой для открытия любой диаграммы в модальном окне (которое можно перетаскивать и изменять размер). Таким образом, нам не нужно везде воспроизводить одни и те же функции.

Я сделал общий компонент, и все работало нормально, но недавно мы обновили наши зависимости репо, так как в версии highcharts, которую мы использовали, были некоторые другие проблемы, эти проблемы были исправлены в последней версии highCharts, поэтому мы решили, что лучше обновитесь до последней версии. С тех пор этот функционал перестал работать.

Следующая логика использовалась для клонирования chartConfig во время открытия модального окна. Затем клонированная конфигурация была передана в расширенную диаграмму, которая находится внутри модального окна. Но теперь развернутая диаграмма всегда пуста.

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

где chartConfig - обычная конфигурация, используемая для отображения диаграммы,

а expandChartConfig - объект диаграммы, переданный модальному окну.

После обновления я понял, что свойство chartConfig.options теперь закрыто, поэтому я также попробовал:

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

но это тоже не сработало.

Первоначально я использовал одну и ту же конфигурацию для обеих диаграмм, но это приводило к проблемам, так как при закрытии модального окна highChart также был уничтожен. Поэтому я решил, что создание отдельной конфигурации во время открытия модального окна для диаграммы внутри модального окна было бы лучшим случаем.

Итак, простыми словами, мой вопрос: как я могу динамически клонировать существующую диаграмму.

  • Эта функциональность требуется в десятках мест, поэтому я не могу поддерживать отдельные объекты диаграммы в каждом месте.

  • Также с диаграммами выполняется множество операций, таких как setData, setCategories, addSeries, removeSeries, update и т. Д. поэтому не рекомендуется сохранять копии и обновлять их при каждой операции. Также эта операция будет выполняться родительским компонентом, поэтому ChartWidgetComponent не может знать о таких изменениях, когда они выполняются.

Итак, вкратце, как я могу динамически клонировать существующий highchart, а также какой метод лучше всего?

P.s. Я попробовал несколько методов, упомянутых в stackOverflow, но ни один из них, похоже, не работает.


person Saif    schedule 05.10.2018    source источник
comment
Я думаю, что лучший способ сделать это - создать новую диаграмму в модальном контейнере с теми же параметрами (ссылкой), переданными ей. Затем ваша диаграмма должна изменять данные, если пользователь играет с ними, потому что обе диаграммы будут работать с одной и той же ссылкой на данные. Можете ли вы воспроизвести минимальный рабочий пример вашего приложения в какой-нибудь песочнице (например, stackblitz или codeandbox) и предоставить мне его?   -  person daniel_s    schedule 08.10.2018
comment
@daniel_s Я дал ссылку на stackBlitz в начале вопроса. вот он, stackblitz.com/edit/highcharts-cloning-chart   -  person Saif    schedule 09.10.2018


Ответы (2)


Для достижения ожидаемого эффекта, к сожалению, недостаточно скопировать 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

С уважением!

person daniel_s    schedule 09.10.2018
comment
тогда, чтобы обобщить эту диаграмму, данные должны быть в заранее определенном формате. Дело в том, что их может быть n количество статических или динамических серий. В случае статической серии я могу иметь предопределенный формат для данных диаграммы. Но в случае динамической серии мне придется не только вызвать this.chartConfig.ref.addSeries, но и обновить chartConfig, чтобы фактическая конфигурация, используемая во время клонирования, была синхронизирована с фактической диаграммой? аналогично во время this.chartConfig.ref.removeSeries мне придется выполнить те же действия. - person Saif; 09.10.2018
comment
Общая концепция компонентов с состоянием - хранить это состояние в одном месте и делиться им со всеми другими компонентами, которым нужны эти данные. Затем, если вы хотите изменить его, просто сделайте это в одном месте, и все компоненты будут иметь один и тот же источник. Вместо использования метода addSeries() просто обновите состояние вашего компонента с помощью нового объекта серии и вызовите update() на диаграмме, чтобы данные диаграммы (основные исходные данные) всегда были актуальными. Кстати, вы пробовали использовать официальную обертку Highcharts? - person daniel_s; 09.10.2018
comment
это действительно странно. Так и не понял, что официальной не пользуюсь. Я предполагаю, что официальная версия была выпущена около года назад, и в то время, когда этот проект только начинался, anuglar-highcharts был единственным. Но я попробую и официальный. Большое спасибо, чувак. Ты герой! :) - person Saif; 10.10.2018
comment
Наслаждаться! Кроме того, я могу сказать, что официальный намного лучше и проще в использовании, чаще всего и напрямую поддерживается разработчиками Highcharts, и имеет отличную документацию. Кроме того, мы стараемся как можно быстрее решать проблемы с нашими оболочками. - person daniel_s; 10.10.2018
comment
Кроме того, если я использую официальный, то, думаю, мне не придется поддерживать отдельные определения типов для высоких диаграмм, верно? Это было бы здорово, так как обновление highcharts-angular обеспечит постоянную синхронизацию определений типов. - person Saif; 10.10.2018
comment
Официальная оболочка имеет собственный файл определений. Наши определения officla для чистых Highcharts сейчас находятся на стадии сборки и должны быть выпущены в ближайшее время, поэтому, что касается вопроса о поддержании определений, он ничего не меняет в данный момент. - person daniel_s; 10.10.2018

Я тоже использую Highcharts, я определил диаграмму как компонент многократного использования, когда я когда-либо хочу нарисовать другую диаграмму, я просто передаю значения через Input() decorattor

в этом случае вы можете использовать что-то вроде этого:

Компонент диаграммы

@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>
person Abel Valdez    schedule 05.10.2018
comment
похоже, вы меня неправильно поняли, у меня есть компонент chartWidget, который по сути является оболочкой для диаграммы, в момент ее развертывания chartWiget необходимо клонировать текущие параметры диаграммы и открывать отдельную диаграмму в модальном окне. Я уже пробовал использовать метод object.assign (), и он не работает, было бы здорово, если бы вы могли взглянуть на связанную демонстрацию. Спасибо. - person Saif; 06.10.2018