Problem/Motivation

  • This module in it's current state doesn't fully satisfy the http://dgo.to/highcharts namespace.
  • The only current module name in the project repo is views_highcharts, logically supporting only Views integration.
  • But there is no abstracted Drupal Highcharts API for modules to make use of apart from Views (there should be).
  • Adding this allows us to leverage the entire Highcharts API without needing to define each type separately.

Proposed resolution

  • Add a Views-independent highcharts.module, with abstracted functions which can be used by views_highcharts and other modules.
  • Move views_highcharts.module to become an included sub-module, dependent on highcharts.module and using the new abstracted API functions.

Remaining tasks

  • Currently a sandbox is at http://drupal.org/sandbox/scottrigby/1507774 (sandbox for now because I would prefer to merge efforts if possible) with 7.x-2.x and 6.x-2.x branches (anticipating this change may warrant a new 2x branch)
  • Add more highcharts types example code for using the API functions. (however there are examples on highcharts.com already. And the current approach duplicating defaults in JSON is not sustainable - what happens when the API changes? Or even aside from that, why should modules need to override example defaults?)
  • Modify views_highcharts to be a wrapper using those functions.
  • In highcharts_render() check for all possible highchart options object callbacks (the sandbox module only addresses tooltip so far, but this is a working example for adding highchart options object methods, which can't be passed through Drupal.settings)

User interface changes

Nothing for the time being. The main API module has no UI, and the views_highcharts module can address UI changes in other tickets (since more functionality is now opened up for additional chart types etc).

API changes

There are two primary functions, theme_highcharts_chart() (returns HTML for a highcharts container), and highcharts_render() (renders a highcharts options object).

Modules may create highchart options objects (see http://www.highcharts.com/ref/), leveraging anything available in the highcharts API.

Example options object:

/**
 * Pie-basic highcharts options object.
 *
 * @see highcharts_render()
 */
function custom_pie_basic_options() {
  $options = new stdClass();

  // Chart.
  $options->chart = (object)array(
    'renderTo' => 'container',
    'plotBackgroundColor' => NULL,
    'plotBorderWidth' => NULL,
    'plotShadow' => FALSE,
  );

  // Title.
  $options->title->text = t('Pies');

  // Tooltip.
  // Normally formatter is a function callback. For now we'll make it a string.
  // @todo whenever this is user defined (views config, etc) be sure to sanitize
  // this string before passing to highcharts_render().
  $options->tooltip->formatter = "function() {return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %';}";

  // Plot options.
  $options->plotOptions->pie = (object)array(
    'allowPointSelect' => TRUE,
    'cursor' => 'pointer',
    'dataLabels' => array(
      'enabled' => FALSE,
    ),
    'showInLegend' => TRUE,
  );

  // Series.
  $options->series = array();
  $series = new StdClass();
  $series->type = 'pie';
  $series->name = 'Slices';
  $series->data = array();
  $series->data[] = array('Banana creme', 45.0);
  $series->data[] = array('Pumpkin', 26.8);

  // Selected item is an object.
  $selected = new stdClass();
  $selected->name = 'Apple';
  $selected->y = 12.8;
  $selected->sliced = TRUE;
  $selected->selected = TRUE;
  $series->data[] = $selected;

  $series->data[] = array('Lemon merengue', 8.5);
  $series->data[] = array('Mincemeat', 6.2);
  $series->data[] = array('Others', 0.7);

  $options->series[] = $series;

  // Diable credits.
  $options->credits->enabled = FALSE;

  return $options;
}

Example implementation of new Drupal Highcharts API functions:

/**
 * Pie-basic highcharts block.
 *
 * @return hook_block() view op definition.
 */
function _custom_block_view_pie_basic() {
  $options = custom_pie_basic_options();
  if (is_object($options)) {
    // Render the chart options object, and retrieve the chart id.
    highcharts_render($options);
    // Define required and optional chart container attributes.
    $attributes = array(
      // Required chart id passed by reference.
      'id' => $options->chart->renderTo,
      // Optionally add styles or any other valid attribute.
      'style' => 'height: 400px;'
    );

    // Return block definition.
    return array(
      'subject' => check_plain($options->title->text),
      'content' => theme('highcharts_chart', $attributes),
    );
  }
}

Props

@stovak, nice work on revamping this module. I just feel it could be made more generically useful apart from the current Views-only approach.

@Matt V., thanks for your use of hook_requirements() and hook_theme() approach in your D6 backport from #1282546-3: Highcharts D6 version. This just needed to be more abstracted, enough to be useful to your filter approach, and views_highcharts (so we're not Druplicating code ;)

Comments

scottrigby’s picture

Issue summary: View changes

fix project token link

indytechcook’s picture

stovak’s picture

Scott, it was always my intention to come up with a config class that was responsive and get rid of the current way or reading the config and altering it. It was also my intention to enlist more maintainers and have some help but i've been drowning in bug fixes of late for this and other efforts.

After Drupalcon I was convinced it needed to be based on the new D8/Synfony2 config classes to future-proof the module and prepare for a d8 release.

I also agree the API should be split from the views module. The module was originally intended only to theme views results.

Let me check out your sandbox, i'll take a look and suggest a way forward. I think you're 2.0 suggestion is prolly the direction I'd like to proceed and make the current views module the 1.0 release.

stovak’s picture

Ok, I like the simplicity of your api. If I make you a co-maintiner of high charts, is your plan to make this a submodule of highcharts or merge this into highcharts?

Honestly, I really wish you'd found me at drupalcon. We could have locked ourselves in a coding room and came out with a 2.0 release.

scottrigby’s picture

@indytechcook
yeah i did check that out :)

The abstraction looks really great, but the visualizations-as-entities thing doesn't seem as easily backportable to D6 (which we still currently need for a while).
Another thing that I had a bit of a problem with (similar to what i said above) the JSON approach is great except it doesn't work well for things like highchart options object methods (callbacks like tooltip formats).

The other thing is the dataviz-adapters (like https://github.com/treehouseagency/dataviz-adapters/blob/master/DATAVIZ....) are really specific (kind of like views_highcharts options are now, though at least those aren't in the js file itself)… which makes it hard to use the full range of Higcharts' API. I think passing the entire options object through Drupal.settings to the implementing chart library gives us much more flexibility.

This is what we are thinking about anyway… definitely worth talking about more though!

@stovak
hey awesome. We're also looking forward to Synfony in D8 :D

Though similar to the concerns above, the approach for D7 & D6 would probably have to be different, don't you think?

Speaking of Bug fixes, i cleaned up a few tickets in the queue, then stopped when i realized almost all of the open ones could be solved (at least in general) by this approach.

I would also like to help with the highcharts_views options, to make more full use of Highcharts' API. I've been scouring for an existing open chart builder GUI we might be able to leverage, but haven't found a good one yet. We may be able to do something cool with automatically getting all the appropriate options for each Highcharts series type (add something like highcharts_ui.module? which highcharts_views could also depend on and pull into the views UI?). But I thought that might go into another ticket. Definitely would like to tag-team that. ^ Edit: looks like we can't reliably get this information automagically.

And yes if you'd like more co-maintainers (for D6 etc), there are also two more people in our dev group who have been working with Highcharts and we could help with this update plan, help keep the queue clean and help keep the branches in sync.

scottrigby’s picture

Update

Hi everyone,
The 2.x branches (7.x-2.x and 6.x-2.x) of that sandbox are merged into this project now. I haven't touched any of the existing branches, except to empty out master (as is the current convention on d.o).

You can check out the commit messages and diffs, but here are the highlights:

Summary of changes

Removed dependency on UUID

UUID was used for the single unique chart container id, but that seemed a little heavy compared to php's uniqid(). @see #1502834: Why does highcharts need UUID?.

Resolving methods

Resolved jQuery methods which can't be passed through Drupal.settings (added a proof of concept for tooltip - which works. @todo potentially just check for all possible highchart options object callbacks? Or find a neater way to scan for these automagically if it can be done safely). @see #1466016: Tooltip formatter.

Code examples

Added API functions example in README text, since these aren't actual hooks. @todo maybe add in doxy comments above the functions - though that may get hideously long.

Views integration

Moved, renamed, and integrated views_highcharts - now highcharts_views - below the new abstracted highcharts module.

I didn't change anything (in the 2.x branches) about the way Views integration had previously worked, except to modify (the renamed) highcharts_views module to be a wrapper around the new API functions. (as I mentioned above, I would like to think together on how highcharts_views could approach this differently than the current overriding a JSON boilerplate options object, but we can save that for other issues).

Caveat: highcharts_views is entirely untested at this point, since I only needed the API so far. So while I changed what seems reasonable to make this work, there are likely new issues that will need to be addressed (in separate tickets).

6.x backport

Same as above, but in the 6.x-2.x branch. @see #1282546: Highcharts D6 version

scottrigby’s picture

Status: Active » Fixed
scottrigby’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

note about why sandbox for now (merge efforts!)