2

I'm attempting to integrate ZingChart as a custom component type in GrapesJs. I've followed some examples and have implemented the following plugin.

blocks.js

import { lineChartRef, chartType } from './consts';
export default (editor, opt = {}) => {
   const c = opt;
   const bm = editor.BlockManager;

   if (c.blocks.indexOf(lineChartRef) >= 0) {
       bm.add(lineChartRef, {
           label: c.labelLineChart,
           content: `
               <div data-gjs-type="${chartType}" id="myChart"></div>
           `
       });
   }
};


components.js

import { chartType } from './consts';

export default (editor, opt = {}) => {
    const domc = editor.DomComponents;
    const defaultType = domc.getType('default');
    const defaultModel = defaultType.model;

    domc.addType(chartType, {
        model: defaultModel.extend(
            {
                defaults: {
                    ...defaultModel.prototype.defaults,
                    script: function() {
                        if (typeof zingchart == 'undefined') {
                            var script = document.createElement('script');
                            script.src =
                                'https://cdn.zingchart.com/zingchart.min.js';
                            document.body.appendChild(script);
                        }
                    }
                }
            },
            {
                isComponent: el => {
                    if (
                        el.getAttribute &&
                        el.getAttribute('data-gjs-type') === chartType
                    ) {
                        return {
                            type: chartType
                        };
                    }
                }
            }
        ),
        view: {
            onRender() {
                renderZingChart.bind(this)();
            }
        }
    });

    function renderZingChart() {
        const data = {
            type: 'bar',
            title: {
                text: 'Data Basics',
                fontSize: 24
            },
            legend: {
                draggable: true
            },
            scaleX: {
                // Set scale label
                label: { text: 'Days' },
                // Convert text on scale indices
                labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
            },
            scaleY: {
                label: { text: 'Temperature (°F)' }
            },
            plot: {
                animation: {
                    effect: 'ANIMATION_EXPAND_BOTTOM',
                    method: 'ANIMATION_STRONG_EASE_OUT',
                    sequence: 'ANIMATION_BY_NODE',
                    speed: 275
                }
            },
            series: [
                {
                    // plot 1 values, linear data
                    values: [23, 20, 27, 29, 25, 17, 15],
                    text: 'Week 1'
                },
                {
                    // plot 2 values, linear data
                    values: [35, 42, 33, 49, 35, 47, 35],
                    text: 'Week 2'
                },
                {
                    // plot 2 values, linear data
                    values: [15, 22, 13, 33, 44, 27, 31],
                    text: 'Week 3'
                }
            ]
        };
        const chart = {
            id: 'myChart',
            data
        };

        zingchart.render(chart);
    }
};

index.js

import grapesjs from 'grapesjs';
import loadBlocks from './blocks';
import loadComponents from './components';
import { lineChartRef } from './consts';

export default grapesjs.plugins.add('fndy-charts', (editor, opts = {}) => {
    let c = opts;

    let defaults = {
        blocks: [lineChartRef],
        defaultStyle: 1,
        labelLineChart: 'Line Chart'
    };

    // Load defaults
    for (let name in defaults) {
        if (!(name in c)) c[name] = defaults[name];
    }

    loadBlocks(editor, c);
    loadComponents(editor, c);
});

consts.js

export const lineChartRef = 'line-chart';
export const chartType = 'chart';

When I add the block to the canvas, it renders, but the ZingChart inside does not. Some things I've tried already:

  1. Verify that the ZingChart render function is being called.
  2. Try moving the renderZingChart function call to different component hooks. Specifically, component:mount, view.init(), and view.onRender().
  3. Move the renderZingChart function call to the script function as a script.onload callback. A similar example can be found here: https://grapesjs.com/docs/modules/Components-js.html#basic-scripts. This does render the ZingChart correctly but doesn't feel correct, and does not allow me to pass in parameters since the script function runs outside the scope of GrapesJs.

I'm running out of ideas so any guidance would be great! Thanks!

2 Answers2

2

I'm making a chart component library with echarts, and the approach for rendering the chart would be similar. The only missing thing I see is element's id. It is an attribute that zing uses to render the chart.

I've made a small example which is obviously not production ready because the id of the block is static. This solves specifically the render problem to make the id dynamic you can do it listening to component:add event and add model id as attribute.

const plugin = editor => {
  const {
    BlockManager: bm
  } = editor;
  bm.add("mychart", {
    label: "Chart",
    content: {
      tagName: "div",
      attributes: {
        id: 'myChart'
      },
      style: {
        width: "300px",
        height: "300px"
      },
      script: function() {
        const init = () => {
          const data = {
            type: "bar",
            title: {
              text: "Data Basics",
              fontSize: 24
            },
            legend: {
              draggable: true
            },
            scaleX: {
              // Set scale label
              label: {
                text: "Days"
              },
              // Convert text on scale indices
              labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
            },
            scaleY: {
              label: {
                text: "Temperature (°F)"
              }
            },
            plot: {
              animation: {
                effect: "ANIMATION_EXPAND_BOTTOM",
                method: "ANIMATION_STRONG_EASE_OUT",
                sequence: "ANIMATION_BY_NODE",
                speed: 275
              }
            },
            series: [{
                // plot 1 values, linear data
                values: [23, 20, 27, 29, 25, 17, 15],
                text: "Week 1"
              },
              {
                // plot 2 values, linear data
                values: [35, 42, 33, 49, 35, 47, 35],
                text: "Week 2"
              },
              {
                // plot 2 values, linear data
                values: [15, 22, 13, 33, 44, 27, 31],
                text: "Week 3"
              }
            ]
          };
          const chart = {
            id: this.id,
            data
          };

          zingchart.render(chart);
        };
        if (typeof zingchart == "undefined") {
          var script = document.createElement("script");
          script.onload = init;
          script.src = "https://cdn.zingchart.com/zingchart.min.js";
          document.body.appendChild(script);
        } else {
          init();
        }
      }
    }
  });
};
const editor = grapesjs.init({
  container: "#gjs",
  fromElement: true,
  height: "100vh",
  width: "auto",
  storageManager: false,
  panels: {
    defaults: []
  },
  plugins: ["gjs-preset-webpage", plugin]
});

You can give a check here the chart is rendering. Codepen

Hope that's enough, cheers!

Julio Vásconez
  • 308
  • 5
  • 11
-1

I don't think you need to write very complicated code for using Zing charts.I will add a small sample code for making a chart block element , So when you drag and drop the block element then it will make the chart a part of the gjs div of grapesjs .I am using Highcharts.

editor.BlockManager.add('Blockhighcharts', {
    label: 'Highchart',
    category: 'CHART',
    attributes: { class:'gjs-fonts gjs-f-b1' },
    content: {
    script: function () {
var container = "container"+Math.floor(Math.random() * 100);
$(this).attr("id",container);    
$('#gridly_div').append($(this));
    var myChart = Highcharts.chart(container, {
        chart: {
            type: 'bar',
        },
        title: {
            text: 'Fruit Consumption'
        },
        xAxis: {
            categories: ['Apples', 'Bananas', 'Oranges']
        },
        yAxis: {
            title: {
                text: 'Fruit eaten'
            }
        },
        series: [{
            name: 'Jane',
            data: [1, 0, 4]
        }, {
            name: 'John',
            data: [5, 7, 3]
        }]
    });

The HTML code where the chart will be displayed is as follows.

 <div id="gjs" style="height:0px; overflow:hidden;">
  <style>
    #gjs{
      height:  100%;
      width: 100%;
      margin: 0;
    }
  </style>
<div id='gridly_div' class="gridly">
</div>