Skip to content

Commit

Permalink
Allow chart data inside shortcode with YAML format
Browse files Browse the repository at this point in the history
This commit enables the following approach

[chartjs]
type: bar
data:
    labels: [Jan, Feb, Mar]
    datasets:
      - label: Bars Other Title
        data: [1,2,4]
[/chartjs]

Significant limitation of this approach is that it (currently) requires disabling all Markdown
processing on the page to work. Would need some raw page processing to fix this, see
the TODO in the source code. It does at least try to detect and warn you off if you try
this approach without disabling md processing.

Huge benefit is that the strings used map 1-1 to the Chart.js library, so any Chart.js
parameters/datasets/options can be utilized. Also, folks can directly reference the
Chart.js documentation, no need to read the readme for this plugin to understand how
the options here map to chart.js options

In order to convert YAML to JSON (faithfully) you need a proper YAML parser. Rather than
asking folks to install a PECL extension, I went with the battle-tested Symphony YAML
parser. The license is MIT, so it should not conflict with this plugin’s license. I chose to
follow the format used in multiple other plugins (and kind of documented at
getgrav/grav#32 ) of embedding the composer “vendor” folder
directly into the git repo. Not what you typically do, but apparently that is the grav way.
I thought I would find a native YAML parser inside Grav (and it’s probably there somewhere)
but I gave up after a bit of looking and pulled in one I trusted.

My thoughts on using YAML (instead of JSON) inside the shortcode - A shortcode
is intended to allow for both quick writing and quick reading. IMO using raw JSON as the
contents would have worsened both the quick-writing and quick-reading nature of this
shortcode extension. As YAML is a pure superset of JSON, any JSON data can be
faithfully reproduced using YAML. If a user has any desire at all to go to raw JSON,
they can always paste that JSON directly into the markdown and bypass the shortcode
mechanism entirely. IMO the only negative of the YAML is that it makes it harder to
copy/paste chart examples into grav using this plugin, but I hope to address that by
adding some other functionality later.
  • Loading branch information
hamiltont committed Jan 25, 2019
1 parent ec49b87 commit c593928
Show file tree
Hide file tree
Showing 72 changed files with 11,311 additions and 6 deletions.
26 changes: 26 additions & 0 deletions Usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Usage

This page has some new usage examples.

## Data Flow

Document the order in which data sources are scanned...


## Data Inside Shortcode

To use this approach, you must disable `process.markdown` inside your frontmatter.
If you do not, then the YAML inside the `chartjs` shortcode will be processed by
the Markdown formatter, and the plugin will fail to properly process it.

````
[chartjs]
type: bar
data:
labels: [Jan, Feb, Mar, Apr]
datasets:
- label: Bars Other Title
data: [1,2,4,7]
[/chartjs]
````

8 changes: 8 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"require": {
"symfony/yaml": "4.2.*"
},
"config": {
"optimize-autoloader": true
}
}
135 changes: 135 additions & 0 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions shortcode-chartjs.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ShortcodeChartjsPlugin extends Plugin
*/
public static function getSubscribedEvents()
{
require_once(__DIR__.'/vendor/autoload.php');

return [ 'onShortcodeHandlers' => ['onShortcodeHandlers', 0] ];
}

Expand Down
63 changes: 57 additions & 6 deletions shortcodes/ChartjsShortcode.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
namespace Grav\Plugin\Shortcodes;

use Thunder\Shortcode\Shortcode\ShortcodeInterface;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
use \Exception;

function jlog($msg) {
echo '<script>console.log("' . $msg . '")</script>';
}

class ChartjsShortcode extends Shortcode
{
Expand All @@ -15,6 +22,7 @@ class ChartjsShortcode extends Shortcode

public function init()
{
// TODO pull processing into distinct function ...
$this->shortcode->getHandlers()->add('chartjs', function(ShortcodeInterface $sc) {
// Get plugin settings
$this->pluginConfig = $this->config->get('plugins.shortcode-chartjs');
Expand All @@ -36,14 +44,29 @@ public function init()

// @todo: Add support for data and config from URL/path

// Add our canvas
// Add canvas
$output = $this->buildCanvas($sc);

// Configure our JS
// Add JS libary assets
$this->shortcode->addAssets('js', '//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.bundle.min.js');
$chartjs = $this->buildChartJS($sc);
$output = $output . "<script>$chartjs</script>";


try {
// Build chart JS
// TODO error-fast or fallback to different data sources?
$id = $sc->getParameter('id', null);
$contents = $sc->getContent();
if (isset($contents) && $contents != '') {
$chartjs = $this->buildChartWithContents($sc, $contents);
} elseif (isset($id)) {
$chartjs = $this->buildChartWithFrontMatter($sc, $id);
} else {
$chartjs = $this->buildChartWithDatapoints($sc);
}

$output = $output . "<script>$chartjs</script>";
} catch (Exception $e) {
$output = "<p>" . $e->getMessage() . "</p>";
}

// Return canvas etc
return $output;
Expand Down Expand Up @@ -85,7 +108,35 @@ private function convertArrayToJSRepresentation($values)
return $jsStringLiteralArray;
}

private function buildChartJS($sc)
private function buildChartWithContents($sc, $content)
{

# TODO - Fix the 'disable markdown' requirement for using this approach
#
# See https://github.com/getgrav/grav-plugin-shortcode-core/issues/38
$header = $this->grav['page']->header();
$header = new \Grav\Common\Page\Header((array) $header);
$markdown = $header->get('process.markdown');
var_dump($markdown);
if (is_null($markdown) || $markdown == 'true' || $markdown == TRUE)
throw new Exception("Disable markdown processing on this page to manually embed chart data");

try {
$content = Yaml::parse($content);
} catch (ParseException $exception) {
throw new Exception("Unable to parse YAML - " . $exception->getMessage());
}

$data = json_encode($content);
if (is_null($data) || $data == FALSE)
throw new Exception("Could not encode chartjs.$id data as JSON");

$canvasName = $sc->getParameter('name', $this->defCanvas);
return "new Chart(document.getElementById(\"$canvasName\"), $data);";
}


private function buildChartWithDatapoints($sc)
{
// Chart details
$type = $sc->getParameter('type', 'bar');
Expand Down
7 changes: 7 additions & 0 deletions vendor/autoload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitb7b7515bd2f76b476ec219ccf4044334::getLoader();
Loading

0 comments on commit c593928

Please sign in to comment.