grofit / aurelia-chart

A chart element for aurelia which is powered by chart js using html5 canvas.
MIT License
46 stars 25 forks source link

native-options.bind is causing error #36

Open adelaideX opened 7 years ago

adelaideX commented 7 years ago

I am binding and creating charts fine but when i try and add options I am getting an Binding expression "{'barThickness':15}" cannot be assigned to. error.

I am using cli-version and tried with canvas and chart element. here is my chart version:

and canvas version:

Am new to Aurelia to appreciate any help. Thanks

grofit commented 7 years ago

Hey, sorry I dont really use Aurelia that much anymore, so I am not really supporting this but hopefully someone else can help, I would assume that the chart js version doesnt support that option or there is a problem with the binding, if you post in your whole element and the VM that it is linked to I can attempt to help further.

adelaideX commented 7 years ago

grofit thanks for your help. Below is the VM i am using for this chart - the bar chart is getting data from a fetch promise and the doughnut is just hardcoded example which i am trying to get to work with the options. I am pretty sure that the options are from the current chart.js version. http://www.chartjs.org/docs/latest/charts/doughnut.html

home.html

<template>
  <div class="row">
    <div class="col-lg-6">
      <div class="panel panel-default">
        <div class="panel-heading">
          <i class="fa fa-bar-chart-o fa-fw"></i>${chart_title}
        </div>
        <!-- /.panel-heading -->
        <div class="panel-body">
          <chart id="bar-chart" type="bar" style="display: block; height: 100%; width: 100%;" data.bind="SimpleLineData" should-update="true"></chart>
        </div>
      </div>
      <!-- /.panel-body -->
    </div>
    <!-- /.panel -->
  </div>
  <!-- /.col-lg-6 -->
  <div class="col-lg-6">
    <div class="panel panel-default">
      <div class="panel-heading">
        <i class="fa fa-bar-chart-o fa-fw"></i>${chart_title}
      </div>
      <!-- /.panel-heading -->
      <div class="panel-body">
        <div class="flot-chart">
          <chart id="dynamic-doughnut-chart" type="doughnut" style="display: block;" should-update="true" throttle="2000" data.bind="DynamicDoughnutData"
            native-options.bind="{
              title: {
                  display: true,
                  text: 'Chart.js Doughnut Chart'
              } }"></chart>
        </div>
      </div>
      <!-- /.panel-body -->
    </div>
    <!-- /.panel -->
  </div>
  <!-- /.col-lg-6 -->
  </div>
  <!-- /.row -->
</template>

home.js

import {WebAPI} from '../../web-api';
import {inject} from 'aurelia-framework';

let chartColors = {
  red: 'rgb(255, 99, 132)',
  reda: 'rgba(255, 99, 132, 0.5)',
  orange: 'rgb(255, 159, 64)',
  orangea: 'rgba(255, 159, 64, 0.5)',
  yellow: 'rgb(255, 205, 86)',
  yellowa: 'rgba(255, 205, 86, 0.5)',
  green: 'rgb(75, 192, 192)',
  greena: 'rgba(75, 192, 192, 0.5)',
  blue: 'rgb(54, 162, 235)',
  bluea: 'rgba(54, 162, 235, 0.5)',
  purple: 'rgb(153, 102, 255)',
  purplea: 'rgba(153, 102, 255, 0.5)',
  grey: 'rgb(201, 203, 207)',
  greya: 'rgba(201, 203, 207, 0.5)'
};

@inject(WebAPI)
export class Home {
  constructor(api) {
    this.api = api;
    this.plays = [{'key': 'hamlet'}, {'key': 'henry5'}, {'key': 'midsummer'}, {'key': 'othello'}, {'key': 'winterstale'}];
    this.getWorks();
    this.heading = 'Shakespeare by the Numbers';
    this.para = 'Explore the Shakespeare plays featured in this course.';
    this.chart_title = 'Total Speeches vs Total Words';
    this.SimpleLineData = {};
    this.resetLineData();
    this.DynamicDoughnutData = {};
    this.resetPieData();
  }

  getWorks() {
    this.works = new Map();
    for (let value of this.plays) {
      this.api.getWorks(value.key)
      .then(response => response.json())
      .then(data => {
        this.works.set(value.key, Object.assign({}, data));
        this.SimpleLineData.labels.push(data.title);
        this.SimpleLineData.datasets[0].data.push(data.totalparagraphs);
        this.SimpleLineData.datasets[1].data.push(data.totalwords);
        this.SimpleLineData.datasets[2].data.push(data.characters.length);
      })
      .catch(console.error);
    }
    console.log(this.works);
  }

  resetLineData() {
    this.SimpleLineData = {
      labels: [],
      datasets: [{
        label: 'total speeches',
        backgroundColor: chartColors.reda,
        borderColor: chartColors.red,
        borderWidth: 1,
        data: []
      },
      {
        label: 'total words',
        backgroundColor: chartColors.bluea,
        borderColor: chartColors.blue,
        borderWidth: 1,
        data: []
      },
      {
        label: 'total characters',
        backgroundColor: chartColors.greena,
        borderColor: chartColors.green,
        borderWidth: 1,
        data: []
      }]
    };
  }

  resetPieData() {
    this.DynamicDoughnutData = {
      labels: ['Red', 'Green', 'Yellow' ],
      datasets: [
        {
          data: [300, 50, 100],
          backgroundColor: [
            '#FF6384',
            '#36A2EB',
            '#FFCE56'
          ],
          hoverBackgroundColor: [
            '#FF6384',
            '#36A2EB',
            '#FFCE56'
          ]
        }]
    };
  }
}
grofit commented 7 years ago

Thanks for the code, I don't see a bar thickness mentioned in there, so is that error being displayed even though you have no bar thickness related vars in there?

adelaideX commented 7 years ago

Ahh yep i switched my test code to the hardcoded doughnut chart as the bar chart gets its data from a promise. However, it does not matter any option that is applicable to the doughnut chart like the title attribute throw the same error. ERROR [app-router] Error: Binding expression "{'title':{'display':true,'text':'Chart.js Doughnut Chart'}}" cannot be assigned to.

grofit commented 7 years ago

ah right ok so its basically the act of binding native options that blows up? Looking in the code there is:

https://github.com/grofit/aurelia-chart/blob/master/src/elements/chart-element.js#L13

So the nativeOptions should be brought in as a 2 way binding and should be assigned to the chart, I know Aurelia does some conventions stuff behind the scenes so I think nativeOptions in the view would be native-options like you have put so that seems fine.

The only thing I think which could possibly cause issues is:

https://github.com/grofit/aurelia-chart/blob/master/src/elements/chart-element.js#L67

As that is re-assigning the options back to the property (not entirely sure why, I imagine its because ChartJS augments the options data somehow and we want to cache that back?), but if you try cracking open your node_modules and removing that line from the lib and running yours and seeing if it still misbehaves?

I am not sure if the solution would be to remove that line, as I assume its needed, but if that is a problem it may be that a new variable needs to be added to account for the "transformed options" or something.

Anyway hope that helps

adelaideX commented 7 years ago

Hey thanks Grofit for help. Anyway i fixed it but commenting that line did not help. In the built chart-element.js file in the module I commented out the decorators and intializer to remove the two way binding and it worked..

line 44

key: "nativeOptions",
      decorators: [_aureliaFramework.bindable],
      initializer: null,
      enumerable: true
      // decorators: [(0, _aureliaFramework.bindable)({ defaultBindingMode: _aureliaFramework.bindingMode.twoWay })],
      // initializer: function initializer() {
      //   return {};
      // },
      // enumerable: true