Giter Club home page Giter Club logo

ember-google-charts's Introduction

Ember Google Charts Build Status npm

Ember Google Charts makes it very easy to implement Google Charts in Ember CLI apps.

All dependencies are lazy loaded using the Google JS API Loader, which intelligently caches requests between a user's sessions.

Installation

ember install ember-google-charts

See the demo app here.

Usage

Charts

There are six types of chart supported out of the box:

  • Area Charts ({{area-chart}})
  • Bar Charts ({{bar-chart}})
  • Geo Charts ({{geo-chart}})
  • Line Charts ({{line-chart}})
  • Pie Charts ({{pie-chart}})
  • Scatter Charts ({{scatter-chart}})

To add a chart to any route, simply add the relevant component:

<AreaChart @data={{this.model}} @options={{this.options}} />

Or if you're using an old template syntax:

{{area-chart data=data options=options}}

Data and options should be in the format expected by the given chart, as detailed in the Google Charts documentation.

For example:

/* stats/route.js */

import Route from '@ember/routing/route';

export default Route.extend({

  model() {
    return [
      ['Task', 'Hours per Day'],
      ['Work', 11],
      ['Eat', 2],
      ['Commute', 2],
      ['Watch TV', 2],
      ['Sleep', 7],
    ];
  },

});
/* stats/controller.js */

import Controller from '@ember/controller';

export default Controller.extend({

  options: {
    title: 'How I spend my days',
    height: 300,
    width: 400,

    animation: {
      startup: true,
      easing: 'inAndOut',
    },
  },

});
{{!-- stats/template.hbs --}}

<PieChart @data={{this.model}} @options={{this.options}} />

You can pass data as an array (see above example) or as a Google Data Table:

/* stats/route.js */

import Route from '@ember/routing/route';

export default Route.extend({

  model() {
    return google.visualization.arrayToDataTable([
      ['Year', 'Sales', 'Expenses'],
      ['2004', 1000, 400],
      ['2005', 1170, 460],
    ], false);
  },

});
{{!-- stats/template.hbs --}}

<PieChart @data={{this.model}} @options={{this.options}} />

For more information about data tables and how to create them, see the Google Charts guides.

Where possible, this addon default to using Material Charts over Google's 'classic' design.

It's very easy to add non-default charts (e.g. table charts or gauge charts) - see the custom charts docs here

Design

Indicate which design you want: classic or material.

<BarChart @data={{this.model}} @options={{this.options}} @design="classic" />

Only some chart types support Material Charts. See the Google Charts documentation Chart Types to learn more.

Default Options

Default options for all charts can be set in the GoogleChartsService.

Default options are always merged with the options you pass into a component. Passed in options will only override specific options properties, not the whole options object.

/* services/google-charts.js */

import GoogleChartsService from 'ember-google-charts/services/google-charts';

export default GoogleChartsService.extend({

  defaultOptions: {
    backgroundColor: '#389fcc',
    annotations: {
      alwaysOutside: true,
    },
  },

});

You can also set default options for individual components by overriding defaultOptions for the component. For example, if you want a custom chart component to use different default options:

/* components/gantt-chart.js */

import GoogleChart from 'ember-google-charts/components/google-chart';
import renderMaterialChart from 'ember-google-charts/utils/render-material-chart';

export default GoogleChart.extend({
  type: 'gantt',

  defaultOptions: {
    backgroundColor: '#389fcc',
    annotations: {
      alwaysOutside: true,
    },
  },

  renderChart: renderMaterialChart,
});

Locales

You can set the language of the charts you render by specifying the language code in the google-charts service:

/* services/google-charts.js */

import GoogleChartsService from 'ember-google-charts/services/google-charts';

export GoogleChartsService.extend({
  language: 'fr',
});

For more information on locales, see the Google Charts documentation.

Please note, Google Charts dependencies can only be loaded for a single language. This is a limitation of the Google API loader.

Resize

By default charts will rerender when the window size changes. You can opt out of this by setting responsiveResize to false:

{{pie-chart data=data responsiveResize=false}}

Actions

Two actions are available for you to hook on to:

chartDidRender()

This fires when the Google chart has rendered and is ready for interaction via Google Charts public methods.

This action receives the chart object of the rendered chart.

/* stats/controller.js */

import Controller from '@ember/controller';

export default Controller.extend({

  actions: {
    selectCountry(chart) {
      chart.setSelection('someValue');
    },
  },

});
{{!-- stats/template.hbs --}}

<GeoChart
  @data={{this.model}}
  @options={{this.options}}
  @chartDidRender=(action 'selectCountry')
/>

packagesDidLoad()

This fires when the Google chart has finished loading the required Google packages for a specific chart.

This action receives no params.

/* stats/controller.js */

import Controller from '@ember/controller';

export default Controller.extend({

  actions: {
    checkGoogleExists() {
      if (window.google) {
        // Do something...
      }
    },
  },

});
{{!-- stats/template.hbs --}}

<LineChart
  @data={{this.model}}
  @options={{this.options}}
  @packagesDidLoad=(action 'checkGoogleExists')
/>

Events

It's easy to listen to events emitted by a chart:

/* stats/controller.js */

import Controller from '@ember/controller';

export default Controller.extend({

  actions: {
    addChartEventListeners(chart) {
      const { google: { visualization } } = window;

      visualization.events.addListener(chart, 'onmouseover', function(event) {
        /* Do something here... */;
      });
    }
  },

});
{{!-- stats/template.hbs --}}

<LineChart
  @data={{this.model}}
  @options={{this.options}}
  @chartDidRender=(action 'addChartEventListeners')
/>

For more information on events, see the Google Charts event documentation.

Custom Charts

All chart components in this addon extend from a single core component: the GoogleChartComponent.

  1. Find the type of chart in the Google guides and see what Google Charts package it requires
  2. Update the Google Chart service packages property with the new Google Charts package you require (if applicable)
  3. Specify whether to use 'material' or 'classic' design (depending on what Google Charts documentation says the chart type supports)
/* components/gantt-chart.js */

import GoogleChart from 'ember-google-charts/components/google-chart';

export default GoogleChart.extend({
  design: 'classic',
  type: 'gantt',
});
/* services/google-charts.js */

import GoogleChartsService from 'ember-google-charts/services/google-charts';

export GoogleChartsService.extend({
  googlePackages: ['corechart', 'bar', 'line', 'scatter', 'gantt'], // Added gantt to defaults
});

If preferred, you can write your own renderChart method. Use the renderChart util as your guide.

renderChart() receives the DOM Element in which to render the chart followed by the chart properties, which is an object that should include the following properties:

  • data (see usage instructions)
  • design ('material' or 'classic')
  • options (see usage instructions)
  • type (e.g. 'bar', 'line', etc)

renderChart() must return a promise that resolves with the chart object (resolve(chart)).

Content Security Policy

You will need to add the following to your app's content security policy to mitigate CSP errors:

contentSecurityPolicy: {
  'script-src': "'self' 'unsafe-eval' *.google.com *.gstatic.com",
  'style-src': "'self' 'unsafe-inline' *.google.com *.googleapis.com *.gstatic.com",
  'font-src': "'self' *.gstatic.com *.googleapis.com",
}

Testing

This addon makes two test helpers available that you can use in your app's test suite:

  • renderChart()
  • assertChart()

renderChart()

renderChart() is an async helper that renders a chart using @ember/test-helpers's render() method.

You must pass in an ES6 tagged template string, as is expected by render(), documented here, so this helper is designed for use in integration tests.

For convenience, renderChart() returns the chart's DOM element.

For example:

/* tests/integration/some-test */

import { module } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { renderChart } from 'ember-google-charts/test-support';

module('Integration | Component | pretty color', function(hooks) {
  setupRenderingTest(hooks);

  test('Rendering the expenses chart', async function(assert) {
    this.set('data', [
      ['Year', 'Sales', 'Expenses'],
      ['2004', 1000, 400],
      ['2005', 1170, 460],
      ['2006', 660, 1120],
      ['2007', 1030, 540],
    ]);

    const chart = await renderChart(hbs`{{area-chart data=data}}`);

    /* Now run some assertions... */

    assert.ok(chart.textContent.indexOf('2007') > -1,
      'Should contain 2007 data');

  });

});

renderChart() adds a delay to your test suite that can be removed if you desire (but this may fail test suites in remote environments, like Travis):

const chart = await renderChart(hbs`{{area-chart data=data}}`, {
  delay: 0, // Or some number of milliseconds
});

assertChart()

assertChart() runs a series of predefined assertions on any chart element to assert that the chart has been rendered correctly.

assertChart() expects several params to be passed:

  • assert, which is available in all 'ember-qunit' tests
  • chart, which is the chart's element and is returned by the renderChart() test helper
  • properties, which is an object that should include the properties passed into the chart component:
    • data
    • design ('material' or 'classic')
    • options
    • type (e.g. 'bar', 'line', etc)

Here is an example, which also uses renderChart():

/* tests/integration/some-test */

import { module } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { assertChart, renderChart } from 'ember-google-charts/test-support';

module('Integration | Component | pretty color', function(hooks) {
  setupRenderingTest(hooks);

  const data = [
    ['Year', 'Sales', 'Expenses'],
    ['2004', 1000, 400],
    ['2005', 1170, 460],
    ['2006', 660, 1120],
    ['2007', 1030, 540],
  ];

  const options = {
    title: 'Yearly expenses',
    animation: {
      startup: true,
      easing: 'inAndOut',
    },
  };

  test('Rendering the expenses chart', async function(assert) {

    this.setProperties({
      data,
      options,
    });

    const chart = await renderChart(hbs`{{area-chart data=data options=options}}`);

    assertChart(assert, chart, {
      data,
      design: 'classic', // Because it's not a Material Chart
      options,
      type: 'area',
    });
  });
});

Development

All PRs and issues are welcome.

  • git clone https://github.com/sir-dunxalot/ember-google-charts.git
  • cd ember-tooltips
  • npm install && bower install
  • ember s
  • ember test, ember try:testall, or the /tests route

Please include tests and documentation updates with any new features.

You do not need to bump the version when you have a PR.

To release an update to the demo app:

git checkout master # make sure you're on master branch
ember github-pages:commit --message "Some commit message" # Builds the app
git push origin gh-pages:gh-pages # Deploys the app

ember-google-charts's People

Contributors

cibernox avatar cmcn avatar denchen avatar dortort avatar eduardoweiland avatar ember-tomster avatar nfc036 avatar rmachielse avatar sir-dunxalot avatar steven-ferguson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ember-google-charts's Issues

Default options are not inherited by child components

If I override the GoogleChartComponent to add default options:

import GoogleChart from 'ember-google-charts/components/google-chart';

export default GoogleChart.extend({
  defaultOptions: {
    legend: {
      position: 'none',
    },
  },
});

I would expect all chart types to inherit these options. However when I add a chart type component to my template:

{{pie-chart data=model}}

it does not inherit the options. In the example above, I would expect the pie chart to not have a legend, but the actual result renders a legend to the right of the chart.

Custom Charts Example in Readme is confusing

The Gantt chart type cannot be rendered by the Material renderer so if you take the "example" code and think it will work you will get very frustrated.

The example should probably be changed to show the classic renderer and perhaps even provide a link to a place to find the list of which charts are available in the material renderer. Unfortunately that only seems available in the Release Notes by searching for 'material'.

Columnchart as component

Thank you very much for the addon. Do you consider to implement also component form column chart (https://developers.google.com/chart/interactive/docs/gallery/columnchart)? I know that it is similar to a bar chart with changed orientation but the column chart has different options, for instance slantedText (displays labels at an angle http://jsfiddle.net/56cjL9me/).

I also know it is possible to make a custom chart but I would say it would be pretty useful to have it "ready to use" as a component.

how to obtain data from json file

how to pass data from a json file?

route Js file:-

import Ember from 'ember':
export default Ember.Route.extend({
model(){
return Ember.$.get('/dashboardstore/employee-country.json');
}
});

template hbs file:

{{log model}}

<br>
<table style="border:1px solid black">
	<tr > 
		<th style="border:1px solid black">country</th><th style="border:1px solid black">Employee count</th>
	</tr>
	{{#each model as |item|}}
			  <tr >
			  		<td style="border:1px solid black">{{item.company_location}}</td>
			  		<td style="border:1px solid black">{{item.employee_count}}</td>
			  </tr>
	{{/each}}
</table>

{{outlet}}

json file i tried to use:

[{ "company_location": "Mexico", "employee_count": 60 }, { "company_location": "Russia", "employee_count": 343 }, { "company_location": "Poland", "employee_count": 491 }, { "company_location": "United Arab Emirates", "employee_count": 85 }, { "company_location": "Philippines", "employee_count": 310 }, { "company_location": "Yemen", "employee_count": 99 }, { "company_location": "Portugal", "employee_count": 466 }, { "company_location": "Greece", "employee_count": 437 }, { "company_location": "Colombia", "employee_count": 285 }, { "company_location": "Iran", "employee_count": 306 }]

how should be model defined in the Js file so that to get output in the template

_handleResize in google-chart component has wrong context

I recently upgraded this addon to 1.8.1 in my app and it started giving me this error everytime I resized the window:

backburner.js:389 Uncaught Error: You attempted to schedule an action in a queue (actions) for a method that doesn't exist
    at DeferredActionQueues.schedule (backburner.js:389)
    at Backburner._scheduleExpiredTimers (backburner.js:1122)
    at Backburner._runExpiredTimers (backburner.js:1095)

Debugging, I found out this error was triggered by the call to debounce within _handleResize, which is being added as event listener to the 'resize' event on window. When the event is triggered, the handler is called with window as this, so this._handlingResize is undefined and that gives the error above.

Data roles not working

Following the example bar chart, the data is set in the router:

import Ember from 'ember';

export default Ember.Route.extend({

  model() {
    return [
      ['Element', 'Density', { role: 'style' }],
      ['Copper', 8.94, '#b87333'],
      ['Silver', 10.49, 'silver'],
      ['Gold', 19.30, 'gold'],
      ['Platinum', 21.45, 'color: #e5e4e2'],
    ];
  },

});

Then it is passed into the bar-chart component

{{bar-chart data=model options=options}}

However, the colors are not coming through on the bar chart. Also, when I tried adding annotation data by adding a { role: 'annotation' }, it similarly is not coming through.

Thoughts?

Improve compatibility with Ember Data

Currently, data has to be passed into charts in the Google-required format.

It would be great if one could pass an Ember model into the chart components and specify the properties to chart.

This requires compatibility with promises to render/animate the charts when the data changes.

Can't apply DateFormat

currently my code looks roughly like this:

var dataTable = window.google.visualization.arrayToDataTable(data);

var fmt = new window.google.visualization.DateFormat({
    pattern: 'LLL d, yyyy',
});
fmt.format(dataTable, 0);

chart.draw(dataTable, options);

I would like to use this library, but it seems that the components expect the raw data instead of the dataTable and I have no chance of applying the DateFormat class after it gets converted by the lib.

Crosshairs not working

I am probably doing something incorrect here, but maybe you could help? Crosshairs don't seem to be working for me:

Data:

const lineChart = [
	['Year', 'Sales'],
	['2004', 1000],
        ['2005', 1170],
	['2006', 660],
	['2007', 1030],
];

Options:

const lineOptions = {
	'crosshair': {
	'color': '#000',
		'trigger': 'selection'
	},
	'title': 'Average',
	'height': 500,
	'legend': {
		'position': 'none'
	},
	'colors': ['#00C0F4']
};

Again, I am probably doing something incorrect, but any help would be nice. Thank you!

Add an arrayToDataTable helper

import Ember from 'ember';

/**
Takes an array of data points like [1,2,5,4,5,5,2,1] and
returns the count ({1:2, 2:2, 4:1, 5:3}) of each item for
Google Charts to consume.

@method arrayToDataTable
@param Array dataArray An array of items
@param String [title] An optional column header
@return Object The count of items in the array
*/

export function arrayToDataTable([dataArray = [], title]/*, hash*/) {
  const counter = dataArray.reduce((object, value) => {

    if (!object[value]) {
      object[value] = 1;
    } else {
      object[value]++;
    }

    return object;
  }, {});

  const dataTable = [[title, 'Number of occurences']];

  for (let value in counter) {
    const count = counter[value];

    dataTable.addObject([ value, count ]);
  }

  return dataTable;
}

export default Ember.Helper.helper(arrayToDataTable);

googlePackage is undefined

Hi, since I've installed "ember-cli": "~3.10.1" and "ember-google-charts": "^1.7.0" and getting this error:
jQuery.Deferred exception: googlePackage is undefined renderChart
render-chart.js:18
In my component I use pie-chart:
{{pie-chart data=dailyStatus options=dailyStatusOptions responsiveResize=true}}
Do I need to update my component too, please? Maybe some more imports. But I get the same error when downloading the package and run tests/dummy (which runs Ember 3.3.2)
Thank you very much for your great package.

l.arrayToDataTable is not a function

How can I avoid an error "l.arrayToDataTable is not a function"? It occurs sometimes
when I load page with line-chart component. Chart isn't rendered
error

ember-cli-babel deprecation

This addon is still using ember-cli-babel@5, which is now deprecated.
Would a pr upgrading that and other dependencies be desired?

IE11 Object doesn't support property or method 'contains'

I have a page that allows users to render a data set with different chart types.

{{#if showCharts}}
    <center>
        {{#if chartOptions.bar}}
            {{bar-chart data=dataForCharts.data options=dataForCharts.options}}
        {{/if}}
        {{#if chartOptions.pie}}
            {{pie-chart data=dataForCharts.data options=dataForCharts.options}}
        {{/if}}
        {{#if chartOptions.geo}}
            {{geo-chart data=dataForCharts.data options=dataForCharts.options}}
        {{/if}}
    </center>
{{/if}}

This is contained within' a larger tab selection that changes the data sent to the charts.

When the larger tab selection is changed I hide the charts showCharts then update dataForCharts and show the charts again. I do it this way so the chart component fires the destroy event and the chart can be broken down. This works great in every browser but IE11. In IE11 I get text that says Object doesn't support property or method 'contains'.

I know this has something to do with chart instances being destroyed and recreated. The suggested solution is to reuse the same chart instance, I don't see how that's a option using ember-google-charts unless I rewrite large parts of it. Any suggestions?

Update dummy app for #14 and #15

We need to update the dummy app for #14 and #15. This is because the dummy app is built and hosted on the gh-pages branch and provides documentation for users.

visualization[visualizationName] is not a constructor / Container is not defined

I have a rather complex app that can have several Google charts on a single page. But often, I see this in my console:

screenshot 2016-11-09 19 11 16

My app is rather complex, so I'm not sure how much code I would need to post for you to get a good idea of what's going on, nor am I sure I can pare my app down to a reproducible snippet, so what I'm asking is, can you think of any general reasons why this would occur? Or at least, is there a way to debug this to find the source of (most likely) my mistake? I'm currently on 1.5.0.

Cannot find module 'ember-try-config'

Hey there,

I tried to install ember-google-charts in a fresh ember app, and ran into a dependency issue with the ember-try-config package:

$ ember install ember-google-charts                          
Cannot find module 'ember-try-config'
Error: Cannot find module 'ember-try-config'
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/Users/me/dev/frontend/node_modules/ember-cli/node_modules/ember-try/lib/utils/config.js:7:34)
    at Module._compile (module.js:397:26)
    at Object.Module._extensions..js (module.js:404:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)

I was able to install ember-google-charts by doing the following:

$ npm install ember-try-config
(...snip...)
$ ember install ember-google-charts

My current setup is:

  • ember-cli 2.6.1
  • npm 5.4.1

Anyways, not too big of a deal, and not sure if you guys know about this, but hopefully its saves someone else a few minutes. ๐Ÿป

Make charts responsive

When the window resizes, use chart.draw() the change the size and make the graphs responsive.

Responsiveness should probably be an optional feature that defaults to true.

Deprecation warning for Ember.warn

Receiving the following on Ember 2.5.0:

ember.debug.js:6249 DEPRECATION: When calling `Ember.warn` you must provide an `options` hash
as the third parameter.  `options` should include an `id` property.
[deprecation id: ember-debug.warn-options-missing]
See http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options for more details.

which is in reference to this line:

Ember.warn('You did not specify a chart type', type);

Ember.warn('You did not specify a chart type', type);

I'd send a PR myself, but I'm unsure as to exactly what id to use in the options property.

Formalize documentation of chart component properties

Now that there are a more than a couple of properties that can be passed into chart components and services, the documentation should be standardized to make it easier for a dev to understand what options can be set where with this addon.

Can't use with a ajax.

Hi,

This module is great, but I can't use it inside with data is fulfilled after the model is ready.

Chart not re-rendering

I'm trying to make an area chart by using: {{area-chart data=myData}}

'myData' is an Ember computed property tied to several other properties. When 'myData' changes, I thought the chart was going to automatically update; it does not. Do I need to set some option explicitly to make this happen?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.