├── .nvmrc ├── _config.yml ├── .babelrc ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── zingchart-demo.gif ├── .editorconfig ├── test ├── utils.js └── build.spec.js ├── src ├── index.css ├── reportWebVitals.js ├── components │ ├── Simple.js │ ├── ModuleChart.js │ ├── Methods.js │ ├── Dynamic.js │ ├── Events.js │ ├── License.js │ └── ModuleDrag.js ├── index.js ├── App.css ├── App.js └── lib │ └── Zingchart.js ├── .gitignore ├── .configs └── .mocharc.js ├── rollup.config.js ├── .github └── workflows │ ├── test.yaml │ ├── build.yaml │ └── publish-to-npm.yaml ├── LICENSE ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v17.5.0 -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", "@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zingchart/zingchart-react/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zingchart/zingchart-react/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zingchart/zingchart-react/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /zingchart-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zingchart/zingchart-react/HEAD/zingchart-demo.gif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | // SETUP & INITIALIZE 2 | // --------------------------------- 3 | 4 | global.Logger = console; 5 | 6 | // Chai 7 | global.expect = require('chai').expect; 8 | 9 | 10 | // CONSTS & HELPER FUNCTIONS 11 | // --------------------------------- 12 | let utils = { 13 | // Helper Functions 14 | }; 15 | 16 | module.exports = { 17 | utils, 18 | }; 19 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # production 7 | /build 8 | 9 | # output files 10 | /dist 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # Other generated files 25 | CHANGELOG.md -------------------------------------------------------------------------------- /src/components/Simple.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | 5 | /* 6 | * Simplest demo, just a bar chart of static data 7 | */ 8 | 9 | function Simple() { 10 | const config = { 11 | type: "bar", 12 | series: [ 13 | { 14 | values: [4, 5, 3, 4, 5, 3, 5, 4, 11], 15 | }, 16 | ], 17 | }; 18 | 19 | return ; 20 | } 21 | 22 | export default Simple; 23 | -------------------------------------------------------------------------------- /.configs/.mocharc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Here's a JavaScript-based config file. 4 | // If you need conditional logic, you might want to use this type of config. 5 | // Otherwise, JSON or YAML is recommended. 6 | 7 | module.exports = { 8 | diff: true, 9 | extension: ['spec'], 10 | opts: false, 11 | exit: true, // end bash script when done 12 | slow: 75, 13 | timeout: 5000, 14 | ui: 'bdd', 15 | spec: ['test/*.spec.js'], 16 | color: true, 17 | output: 'test/test.js' 18 | }; -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import reportWebVitals from "./reportWebVitals"; 4 | import { BrowserRouter } from "react-router-dom"; 5 | 6 | import "./index.css"; 7 | import App from "./App"; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById("root")); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | // If you want to start measuring performance in your app, pass a function 19 | // to log results (for example: reportWebVitals(console.log)) 20 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 21 | reportWebVitals(); 22 | -------------------------------------------------------------------------------- /src/components/ModuleChart.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | import "zingchart/modules-es6/zingchart-maps.min.js"; 5 | import "zingchart/modules-es6/zingchart-maps-usa.min.js"; 6 | 7 | /* 8 | * Vector map of the 48 US states. Demonstrates explicitly importing 9 | * ZingChart modules. 10 | */ 11 | 12 | function ModuleChart() { 13 | const [config] = useState({ 14 | shapes: [ 15 | { 16 | type: "zingchart.maps", 17 | options: { 18 | name: "usa", 19 | ignore: ["AK", "HI"], 20 | }, 21 | }, 22 | ], 23 | }); 24 | 25 | return ; 26 | } 27 | 28 | export default ModuleChart; 29 | -------------------------------------------------------------------------------- /test/build.spec.js: -------------------------------------------------------------------------------- 1 | const utils = require("./utils.js"); 2 | const chai = require("chai"); 3 | chai.use(require("chai-fs")); 4 | 5 | // server/controllers/api/card.js 6 | describe("Build", function () { 7 | describe("dist/zingchart-react.js", function () { 8 | // verify the ZingChart object exists 9 | it(`zingchart-react.esm.js file should exist`, async function () { 10 | let zcReactFilePath = "dist/zingchart-react.esm.js"; 11 | expect(zcReactFilePath).to.be.a.path(); 12 | }); 13 | // verify exports 14 | it(`default export exists`, async function () { 15 | // exports.ZC = ZC$2; 16 | let zcReactFilePath = "dist/zingchart-react.cjs.js"; 17 | expect(zcReactFilePath) 18 | .to.be.a.file() 19 | .with.contents.that.match(/module.exports = ZingChart;/); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from "rollup-plugin-babel"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import external from "rollup-plugin-peer-deps-external"; 4 | import postcss from "rollup-plugin-postcss"; 5 | import resolve from "@rollup/plugin-node-resolve"; 6 | import url from "@rollup/plugin-url"; 7 | import svgr from "@svgr/rollup"; 8 | 9 | import pkg from "./package.json"; 10 | 11 | export default { 12 | input: "src/lib/Zingchart.js", 13 | output: [ 14 | { 15 | file: pkg.main, 16 | format: "cjs", 17 | }, 18 | { 19 | file: pkg.module, 20 | format: "esm", 21 | }, 22 | ], 23 | plugins: [ 24 | external(), 25 | postcss({ 26 | modules: true, 27 | }), 28 | url(), 29 | svgr(), 30 | babel({ 31 | exclude: "node_modules/**", 32 | }), 33 | resolve(), 34 | commonjs(), 35 | ], 36 | }; 37 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | # Name is optional and if present must be used 2 | # in the url path for badges 3 | name: Test 4 | 5 | # Run on a dev branch 6 | on: 7 | push: 8 | branches: 9 | - master 10 | - dev 11 | pull_request: 12 | branches: 13 | - master 14 | 15 | jobs: 16 | Test: 17 | name: Test 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | node-version: [18.17.0] 22 | 23 | steps: 24 | - name: Checkout Repository 25 | uses: actions/checkout@v1 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v1 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | - name: Install Fresh Dependencies 31 | run: npm ci 32 | - name: Build library 33 | run: npm run build 34 | - name: Run Unit Tests 35 | run: npm run test:unit 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | # Name is optional and if present must be used 2 | # in the url path for badges 3 | name: Build 4 | 5 | # Run on a dev branch 6 | on: 7 | push: 8 | branches: 9 | - master 10 | - dev 11 | pull_request: 12 | branches: 13 | - master 14 | 15 | jobs: 16 | Build: 17 | name: Build 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | node-version: [18.17.0] 22 | 23 | steps: 24 | - name: Checkout Repository 25 | uses: actions/checkout@v1 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v1 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | - name: Install Fresh Dependencies 31 | run: npm ci 32 | - name: Build library 33 | run: npm run build 34 | - name: Log build output 35 | run: ls -alt dist/ 36 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-npm.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Name is optional and if present must be used 3 | # in the url path for badges 4 | name: Publish to NPM 5 | 6 | # only run when a release has been "published" 7 | on: 8 | release: 9 | types: [released] 10 | 11 | jobs: 12 | 13 | # publish to npm on release 14 | publish: 15 | name: NPM Publish 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | node-version: [17.5.0] 20 | 21 | steps: 22 | - uses: actions/checkout@v1 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | registry-url: https://registry.npmjs.org/ 28 | - run: npm install 29 | - run: npm run build 30 | - run: npm publish --access public 31 | env: 32 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 ZingChart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/Methods.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef } from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | 5 | /* 6 | * A bar chart with a button that adds additional data. Demonstrates 7 | * using a reference to a ZingChart element. 8 | */ 9 | 10 | function Methods() { 11 | const nValues = 10; 12 | 13 | // Return an array of `count` random values 14 | const randomData = (count) => 15 | [...Array(count)].map(() => Math.floor(Math.random() * 10)); 16 | 17 | const chart = useRef(null); 18 | const [nSets, setNSets] = useState(1); 19 | const [config] = useState({ 20 | type: "bar", 21 | series: [ 22 | { 23 | values: randomData(nValues), 24 | }, 25 | ], 26 | }); 27 | 28 | /* 29 | * Add an additional dataset to the existing barchart 30 | */ 31 | function addDataset() { 32 | chart.current.addplot({ 33 | data: { 34 | values: randomData(nValues), 35 | }, 36 | }); 37 | 38 | setNSets((n) => n + 1); 39 | } 40 | 41 | return ( 42 |
43 | 44 | 45 |
46 | ); 47 | } 48 | 49 | export default Methods; 50 | -------------------------------------------------------------------------------- /src/components/Dynamic.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | 5 | /* 6 | * A dynamically updating line plot. Demonstrates modifying the 7 | * configuration of an existing ZingChart. 8 | */ 9 | 10 | function Dynamic() { 11 | const nValues = 10; 12 | const period = 1000; // milliseconds 13 | 14 | // Return an array of `count` random values 15 | const randomData = (count) => 16 | [...Array(count)].map(() => Math.floor(Math.random() * 10)); 17 | 18 | const [config, setConfig] = useState({ 19 | type: "line", 20 | series: [{ values: randomData(nValues) }], 21 | }); 22 | 23 | /* 24 | * Set a new random dataset 25 | */ 26 | function shuffle() { 27 | setConfig((state) => ({ 28 | ...state, 29 | series: [{ values: randomData(nValues) }], 30 | })); 31 | } 32 | 33 | // Create an effect to periodically update the chart data 34 | useEffect(() => { 35 | const interval = setInterval(shuffle, period); 36 | 37 | // Invoked to clean up when unmounted 38 | return () => clearInterval(interval); 39 | }, []); 40 | 41 | return ( 42 |
43 |
{JSON.stringify(config.series[0].values)}
44 | 45 |
46 | ); 47 | } 48 | 49 | export default Dynamic; 50 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-header { 6 | background-color: #c3c3c5; 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | justify-content: center; 11 | font-size: 120%; 12 | color: white; 13 | } 14 | 15 | .App-buttonbar { 16 | display: flex; 17 | flex-direction: row; 18 | padding-bottom: 2em; 19 | } 20 | 21 | [class*="App-button-"] { 22 | background-color: #4CAF50; 23 | border: none; 24 | color: white; 25 | padding: 15px 32px; 26 | text-align: center; 27 | display: inline-block; 28 | font-size: 16px; 29 | border-radius: 8px; 30 | text-decoration: none; 31 | margin-right: 1em; 32 | } 33 | 34 | .App-button-plain { 35 | color: white; 36 | } 37 | 38 | .App-button-active { 39 | color: black; 40 | } 41 | 42 | .App-button-plain:hover { 43 | box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19); 44 | } 45 | 46 | .App-link { 47 | color: #61dafb; 48 | } 49 | 50 | .Events-wrapper { 51 | display: flex; 52 | flex-direction: row; 53 | } 54 | 55 | .Events-output { 56 | border: 1px; 57 | border-style: solid; 58 | width: 30%; 59 | margin-top: 1em; 60 | margin-bottom: 1em; 61 | margin-right: 1em; 62 | } 63 | 64 | .Events-bound { 65 | margin-left: 1em; 66 | text-align: left; 67 | } 68 | 69 | .Events-bound ul { 70 | margin-top: 0.5em; 71 | } 72 | 73 | .Events-renderState { 74 | background-color:#c3c3c5; 75 | color: white; 76 | padding-top: 0.3em; 77 | padding-bottom: 0.3em; 78 | } 79 | 80 | .Events-nodeInfo { 81 | margin-left: 1em; 82 | text-align: left; 83 | } 84 | -------------------------------------------------------------------------------- /src/components/Events.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | 5 | /* 6 | * A line chart with events logged to a text box. 7 | */ 8 | 9 | function Events() { 10 | const listOfEventListeners = ["complete", "node_mouseover"]; 11 | const events = listOfEventListeners.map((value, index) => ( 12 |
  • {value}
  • 13 | )); 14 | 15 | const [config] = useState({ 16 | type: "line", 17 | series: [ 18 | { 19 | values: [4, 5, 3, 4, 5, 3, 5, 4, 11], 20 | }, 21 | ], 22 | }); 23 | 24 | const [output, setOutput] = useState(""); 25 | const [renderState, setRenderState] = useState("pending"); 26 | 27 | /* 28 | * Invoked when the chart has finished rendering 29 | */ 30 | function chartDone() { 31 | setRenderState("rendered"); 32 | } 33 | 34 | /* 35 | * Handle the info relating to the node under the cursor 36 | */ 37 | function nodeInfo(info) { 38 | delete info.ev; // Remove the event data 39 | setOutput(`Node Info\n${JSON.stringify(info, null, 2)}\n`); 40 | } 41 | 42 | return ( 43 |
    44 | 45 |
    46 |

    Output from events

    47 |
    48 | Events bound: 49 |
      {events}
    50 |
    51 |
    Chart is {renderState}
    52 |
    {output}
    53 |
    54 |
    55 | ); 56 | } 57 | 58 | export default Events; 59 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
    32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/components/License.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import zingchart from "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | 5 | /* 6 | * Demonstrate setting the license key and performance 7 | * flags on the ZingChart object, as well as multiple 8 | * plots in one chart. 9 | */ 10 | 11 | // Set performance flags on the ZingChart object 12 | zingchart.DEV.KEEPSOURCE = 0; // prevents lib from storing the original data package 13 | zingchart.DEV.COPYDATA = 0; // prevents lib from creating a copy of the data package 14 | 15 | // Set the license key on the ZingChart object 16 | zingchart.LICENSE = ["abcdefghijklmnopqrstuvwxy"]; 17 | 18 | function License() { 19 | const [config] = useState({ 20 | /* Graphset array */ 21 | graphset: [ 22 | { 23 | /* Object containing chart data */ type: "line", 24 | /* Size your chart using height/width attributes */ 25 | height: "200px", 26 | width: "90%", 27 | /* Position your chart using x/y attributes */ 28 | x: "5%", 29 | y: "5%", 30 | series: [ 31 | { 32 | values: [76, 23, 15, 85, 13], 33 | }, 34 | { 35 | values: [36, 53, 65, 25, 45], 36 | }, 37 | ], 38 | }, 39 | { 40 | /* Object containing chart data */ type: "funnel", 41 | height: "55%", 42 | width: "45%", 43 | x: "5%", 44 | y: "200px", 45 | series: [ 46 | { values: [30] }, 47 | { values: [15] }, 48 | { values: [5] }, 49 | { values: [3] }, 50 | ], 51 | }, 52 | { 53 | type: "pie", 54 | height: "55%", 55 | width: "45%", 56 | x: "50%", 57 | y: "200px", 58 | series: [{ values: [15] }, { values: [30] }, { values: [34] }], 59 | }, 60 | ], 61 | }); 62 | 63 | return ; 64 | } 65 | 66 | export default License; 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zingchart-react", 3 | "version": "3.2.1", 4 | "description": "ZingChart React Component wrapper to allow native react syntax for javascript charts, chart events, chart methods and chart styling.", 5 | "author": "ZingSoft Inc.", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/zingchart/zingchart-react.git" 10 | }, 11 | "main": "dist/zingchart-react.cjs.js", 12 | "module": "dist/zingchart-react.esm.js", 13 | "jsnext:main": "dist/zingchart-react.es.js", 14 | "homepage": "https://www.zingchart.com/", 15 | "engines": { 16 | "node": ">=14", 17 | "npm": ">=5" 18 | }, 19 | "keywords": [ 20 | "dashboard", 21 | "zingchart", 22 | "data visualization", 23 | "charts", 24 | "dataviz", 25 | "react" 26 | ], 27 | "scripts": { 28 | "prepare": "npm run build", 29 | "build": "rollup -c", 30 | "build:watch": "rollup -c -W", 31 | "start": "react-scripts start", 32 | "test": "react-scripts test", 33 | "eject": "react-scripts eject", 34 | "commit": "git-cz", 35 | "test:unit": "mocha --config=./.configs/.mocharc.js" 36 | }, 37 | "peerDependencies": { 38 | "react": ">=15.0.0", 39 | "react-dom": ">=15.0.0" 40 | }, 41 | "dependencies": { 42 | "zingchart": "latest", 43 | "zingchart-constants": "github:zingchart/zingchart-constants#master" 44 | }, 45 | "devDependencies": { 46 | "@babel/cli": "^7.23.4", 47 | "@babel/core": "^7.23.5", 48 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11", 49 | "@babel/preset-env": "^7.23.5", 50 | "@babel/preset-react": "^7.23.3", 51 | "@rollup/plugin-commonjs": "^25.0.7", 52 | "@rollup/plugin-node-resolve": "^15.2.3", 53 | "@rollup/plugin-url": "^8.0.2", 54 | "@svgr/rollup": "^8.1.0", 55 | "chai": "^4.3.10", 56 | "chai-fs": "^2.0.0", 57 | "cross-env": "^7.0.3", 58 | "mocha": "^10.2.0", 59 | "react": "^18.2.0", 60 | "react-dom": "^18.2.0", 61 | "react-router-dom": "^6.20.1", 62 | "react-scripts": "^5.0.1", 63 | "rollup": "^2.79.1", 64 | "rollup-plugin-babel": "^4.4.0", 65 | "rollup-plugin-peer-deps-external": "^2.2.4", 66 | "rollup-plugin-postcss": "^4.0.2", 67 | "web-vitals": "^3.5.0" 68 | }, 69 | "files": [ 70 | "dist/*" 71 | ], 72 | "browserslist": { 73 | "production": [ 74 | ">0.2%", 75 | "not dead", 76 | "not op_mini all" 77 | ], 78 | "development": [ 79 | "last 1 chrome version", 80 | "last 1 firefox version", 81 | "last 1 safari version" 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/components/ModuleDrag.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef } from "react"; 2 | import "zingchart/es6"; 3 | import ZingChart from "../lib/Zingchart"; 4 | import "zingchart/modules-es6/zingchart-dragging.min.js"; 5 | 6 | /* 7 | * Demonstrate interacting with a chart to change its data 8 | * using the dragging module. Note that the module is imported 9 | * and then passed as a prop to the ZingChart component. 10 | */ 11 | 12 | function ModuleDrag() { 13 | const startingValues = [20, 40, 14, 50, 15, 35, 5]; 14 | const goals = [25, 43, 30, 40, 21, 59, 35]; 15 | 16 | // Compare values to goals and return count of goals met 17 | function countGoodDays(vs, gs) { 18 | let n = 0; 19 | 20 | for (const i in vs) if (vs[i] >= gs[i]) n++; 21 | 22 | return n; 23 | } 24 | 25 | const chart = useRef(null); 26 | const [goodDays, setGoodDays] = useState( 27 | countGoodDays(startingValues, goals) 28 | ); 29 | const [config] = useState({ 30 | type: "vbullet", 31 | title: { 32 | text: "Pushups Per Day", 33 | }, 34 | subtitle: { 35 | text: "Bars are draggable", 36 | }, 37 | plot: { 38 | valueBox: [ 39 | { 40 | type: "all", 41 | text: "[%node-value / %node-goal-value]", 42 | color: "#000", 43 | placement: "goal", 44 | }, 45 | ], 46 | }, 47 | scaleX: { 48 | labels: ["Mon", "Tues", "Wed", "Thur", "Fri", "Sat", "Sun"], 49 | }, 50 | tooltip: { 51 | borderRadius: "3px", 52 | borderWidth: "0px", 53 | fontSize: "14px", 54 | shadow: true, 55 | }, 56 | series: [ 57 | { 58 | values: startingValues, 59 | dataDragging: true, 60 | goal: { 61 | backgroundColor: "#64b5f6", 62 | borderWidth: "0px", 63 | }, 64 | goals: goals, 65 | rules: [ 66 | { 67 | backgroundColor: "#81c784", 68 | rule: "%v >= %g", 69 | }, 70 | { 71 | backgroundColor: "#ef5350", 72 | rule: "%v < %g/2", 73 | }, 74 | { 75 | backgroundColor: "#ffca28", 76 | rule: "%v >= %g/2 && %v < %g", 77 | }, 78 | ], 79 | }, 80 | ], 81 | }); 82 | 83 | /* 84 | * Update the number of days the goals have been met 85 | */ 86 | function showData() { 87 | const data = chart.current.getseriesdata(); 88 | 89 | setGoodDays(countGoodDays(data[0].values, data[0].goals)); 90 | } 91 | 92 | return ( 93 |
    94 |
    Goals met {goodDays} days this week
    95 | 102 |
    103 | ); 104 | } 105 | 106 | export default ModuleDrag; 107 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { NavLink, Route, Routes } from "react-router-dom"; 3 | 4 | import Simple from "./components/Simple.js"; 5 | import ModuleChart from "./components/ModuleChart.js"; 6 | import ModuleDrag from "./components/ModuleDrag.js"; 7 | import Dynamic from "./components/Dynamic.js"; 8 | import Events from "./components/Events.js"; 9 | import Methods from "./components/Methods.js"; 10 | import License from "./components/License.js"; 11 | import "./App.css"; 12 | 13 | /** 14 | * The main application component. This component is responsible for 15 | * rendering the navigation bar and the content of the currently selected 16 | * demo. 17 | */ 18 | 19 | function App() { 20 | const modules = { 21 | "/": { 22 | label: "Hello World", 23 | text: "Demonstrates a simple chart of static data", 24 | file: "Simple.js", 25 | }, 26 | "/module_chart": { 27 | label: "US Map", 28 | text: "Demonstrates explicitly importing ZingChart modules", 29 | file: "ModuleChart.js", 30 | }, 31 | "/module_drag": { 32 | label: "Interaction", 33 | text: "Demonstrates interacting with a chart to change data", 34 | file: "ModuleDrag.js", 35 | }, 36 | "/dynamic": { 37 | label: "Reconfiguring", 38 | text: "Demonstrates modifying the configuration of an existing chart", 39 | file: "Dynamic.js", 40 | }, 41 | "/events": { 42 | label: "Events", 43 | text: "Demonstrates responding to chart events", 44 | file: "Events.js", 45 | }, 46 | "/methods": { 47 | label: "Methods", 48 | text: "Demonstrates using a reference to a ZingChart element to invoke methods on it", 49 | file: "Methods.js", 50 | }, 51 | "/license": { 52 | label: "Multiple Plots", 53 | text: "Demonstrates setting the license key and performance flags on the ZingChart object, as well as multiple plots", 54 | file: "License.js", 55 | }, 56 | }; 57 | 58 | return ( 59 |
    60 |
    61 |

    ZingChart React Demo

    62 |
    63 | A simple example of binding data, mutations with methods, and 64 | listening to events 65 |
    66 |
    67 | {Object.entries(modules).map(([path, mod], index) => ( 68 | 72 | isActive ? "App-button-active" : "App-button-plain" 73 | } 74 | > 75 | {mod.label} 76 | 77 | ))} 78 |
    79 |
    80 |
    81 |
    82 | 83 | {Object.entries(modules).map(([path, mod], index) => ( 84 | {mod.text}} 89 | /> 90 | ))} 91 | 92 |
    93 |
    94 | 95 | } /> 96 | } /> 97 | } /> 98 | } /> 99 | } /> 100 | } /> 101 | } /> 102 | 103 |
    104 |
    105 |
    106 | ); 107 | } 108 | 109 | export default App; 110 | -------------------------------------------------------------------------------- /src/lib/Zingchart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import zingchart from "zingchart"; 3 | import constants from "zingchart-constants"; 4 | 5 | const { 6 | DEFAULT_WIDTH, 7 | DEFAULT_HEIGHT, 8 | DEFAULT_OUTPUT, 9 | EVENT_NAMES, 10 | METHOD_NAMES, 11 | } = constants; 12 | 13 | // One time setup globally to handle all zingchart-react objects in the app space. 14 | if (!window.ZCReact) { 15 | window.ZCReact = { 16 | instances: {}, 17 | count: 0, 18 | }; 19 | } 20 | 21 | class ZingChart extends Component { 22 | constructor(props) { 23 | super(props); 24 | this.id = this.props.id || "zingchart-react-" + window.ZCReact.count++; 25 | 26 | // Bind all methods available to zingchart to be accessed via Refs. 27 | METHOD_NAMES.forEach((name) => { 28 | this[name] = (args) => { 29 | return window.zingchart.exec(this.id, name, args); 30 | }; 31 | }); 32 | this.state = { 33 | style: { 34 | height: this.props.height || DEFAULT_HEIGHT, 35 | width: this.props.width || DEFAULT_WIDTH, 36 | }, 37 | }; 38 | } 39 | 40 | render() { 41 | return
    ; 42 | } 43 | 44 | bindEvent(eventName, originalEventName) { 45 | if (EVENT_NAMES.includes(eventName)) { 46 | // Filter through the provided events list, then register it to zingchart. 47 | window.zingchart.bind(this.id, eventName, (result) => { 48 | this.props[originalEventName || eventName](result); 49 | }); 50 | return true; 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | componentDidMount() { 57 | // Bind all events registered. 58 | Object.keys(this.props).forEach((eventName) => { 59 | if (!this.bindEvent(eventName)) { 60 | // Replace '_' with '.' and attempt again 61 | let newEventName = eventName.replace(/\_/g, "."); 62 | this.bindEvent(newEventName, eventName); 63 | } 64 | }); 65 | 66 | this.renderChart(); 67 | } 68 | 69 | // Used to check the values being passed in to avoid unnecessary changes. 70 | shouldComponentUpdate(nextProps) { 71 | // Data change 72 | if (JSON.stringify(nextProps.data) !== JSON.stringify(this.props.data)) { 73 | zingchart.exec(this.id, "setdata", { 74 | data: nextProps.data, 75 | }); 76 | 77 | // Series change 78 | } else if ( 79 | JSON.stringify(nextProps.series) !== JSON.stringify(this.props.series) 80 | ) { 81 | zingchart.exec(this.id, "setseriesdata", { 82 | graphid: 0, 83 | plotindex: 0, 84 | data: nextProps.series, 85 | }); 86 | 87 | // Resize 88 | } else if ( 89 | nextProps.width !== this.props.width || 90 | nextProps.height !== this.props.height 91 | ) { 92 | this.setState({ 93 | style: { 94 | width: nextProps.width || DEFAULT_WIDTH, 95 | height: nextProps.height || DEFAULT_HEIGHT, 96 | }, 97 | }); 98 | zingchart.exec(this.id, "resize", { 99 | width: nextProps.width || DEFAULT_WIDTH, 100 | height: nextProps.height || DEFAULT_HEIGHT, 101 | }); 102 | } 103 | 104 | // React should never re-render since ZingChart controls this component. 105 | return false; 106 | } 107 | 108 | renderChart() { 109 | const renderObject = {}; 110 | Object.keys(this.props).forEach((prop) => { 111 | renderObject[prop] = this.props[prop]; 112 | }); 113 | // Overwrite some existing props. 114 | renderObject.id = this.id; 115 | renderObject.width = this.props.width || DEFAULT_WIDTH; 116 | renderObject.height = this.props.height || DEFAULT_HEIGHT; 117 | renderObject.data = this.props.data; 118 | renderObject.output = this.props.output || DEFAULT_OUTPUT; 119 | 120 | if (this.props.series) { 121 | renderObject.data.series = this.props.series; 122 | } 123 | if (this.props.theme) { 124 | renderObject.defaults = this.props.theme; 125 | } 126 | if (this.props.modules) { 127 | renderObject.modules = this.props.modules; 128 | } 129 | zingchart.render(renderObject); 130 | } 131 | 132 | componentWillUnmount() { 133 | zingchart.exec(this.id, "destroy"); 134 | } 135 | } 136 | 137 | // export ZingChart react class as the default 138 | export default ZingChart; 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://img.shields.io/npm/v/zingchart-react) 2 | ![](https://github.com/zingchart/zingchart-react/workflows/Build/badge.svg?branch=master) 3 | ![](https://github.com/zingchart/zingchart-react/workflows/Test/badge.svg?branch=master) 4 | ![](https://img.shields.io/npm/dw/zingchart-react) 5 | 6 | ![](https://img.shields.io/david/zingchart/zingchart-react) 7 | ![](https://img.shields.io/david/peer/zingchart/zingchart-react) 8 | ![](https://img.shields.io/david/dev/zingchart/zingchart-react) 9 | 10 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 11 | 12 | [![](https://github.com/zingchart/zingchart-react/blob/master/zingchart-demo.gif?raw=true)](https://codesandbox.io/s/zingchart-react-wrapper-example-dxfc9) 13 | 14 | ## Quickstart Guide 15 | 16 | Quickly add charts to your React application with our ZingChart component 17 | 18 | This guide assumes some basic working knowledge of React and jsx. 19 | 20 | 21 | ## 1. Install 22 | 23 | Install the `zingchart` package via npm 24 | 25 | `npm install zingchart` 26 | 27 | Install the `zingchart-react` package via npm 28 | 29 | `npm install zingchart-react` 30 | 31 | ## 2. Include the `zingchart` package in your project 32 | 33 | The `zingchart` package is a **DIRECT** dependency of `zingchart-react` but you can also update this package outside of this component. Meaning the wrapper is no longer tied to a ZingChart library version, but just the component itself. 34 | 35 | You can import the library like so: 36 | 37 | ```javascript 38 | // import the es6 version 39 | import 'zingchart/es6'; 40 | ``` 41 | 42 | ## 3. Include the component in your project 43 | 44 | You can either include the zingchart-react component to your project via UMD or modules (recommended). 45 | 46 | 47 | ### Modules (recommended) 48 | ```js 49 | import 'zingchart/es6'; 50 | import ZingChart from 'zingchart-react'; 51 | ``` 52 | 53 | You must **EXPLICITLY IMPORT MODULE CHARTS**. The modules are 54 | wrapped as a closure an eval statement so there is **NO** default 55 | export objects. Just import them. 56 | 57 | ```js 58 | import 'zingchart/es6'; 59 | import ZingChart from 'zingchart-react'; 60 | // EXPLICITLY IMPORT MODULE from node_modules 61 | import "zingchart/modules-es6/zingchart-maps.min.js"; 62 | import "zingchart/modules-es6/zingchart-maps-usa.min.js"; 63 | ``` 64 | 65 | ### UMD 66 | 67 | In your main html file, include the package as a script include. 68 | ```html 69 | 70 | 71 | ``` 72 | 73 | ### `zingchart` Global Object 74 | 75 | If you need access to the `window.zingchart` objects for licensing or development flags or any top level 76 | variables for other modules like `zingchart.loadGeoJSON()`. This is all exposed by importing the library as 77 | the `zingchart` variable with `import zingchart from 'zingchart/es6'`. 78 | 79 | ```javascript 80 | import zingchart from 'zingchart/es6'; 81 | import ZingChart from 'zingchart-react'; 82 | 83 | // zingchart object for performance flags 84 | zingchart.DEV.KEEPSOURCE = 0; // prevents lib from storing the original data package 85 | zingchart.DEV.COPYDATA = 0; // prevents lib from creating a copy of the data package 86 | 87 | // ZC object for license key 88 | zingchart.LICENSE = ['abcdefghijklmnopqrstuvwxy']; 89 | ``` 90 | 91 | ## Usage 92 | 93 | Use the newly imported `ZingChart` component in your markup. 94 | 95 | ### Using class components: 96 | 97 | ```jsx 98 | import React, {Component} from 'react'; 99 | import zingchart from 'zingchart/es6'; 100 | import ZingChart from 'zingchart-react'; 101 | /* Additional imports and settings as needed, see above */ 102 | 103 | class Simple extends Component { 104 | constructor(props) { 105 | super(props); 106 | this.state = { 107 | config: { 108 | type: 'bar', 109 | series: [{ 110 | values: [4,5,3,4,5,3,5,4,11] 111 | }] 112 | } 113 | } 114 | } 115 | render() { 116 | return ( 117 |
    118 | 119 |
    120 | ); 121 | } 122 | } 123 | 124 | export default Simple; 125 | ``` 126 | 127 | ### Using function components: 128 | 129 | ```jsx 130 | import React, {useState} from 'react'; 131 | import 'zingchart/es6'; 132 | import ZingChart from 'zingchart-react'; 133 | /* Additional imports and settings as needed, see above */ 134 | 135 | function Simple() { 136 | const [config] = useState({ 137 | type: 'bar', 138 | series: [{ 139 | values: [4,5,3,4,5,3,5,4,11] 140 | }] 141 | }) 142 | 143 | return 144 | } 145 | 146 | export default Simple; 147 | ``` 148 | 149 | ## Parameters 150 | 151 | The properties, or parameters, you can pass to the `` tag itself. 152 | 153 | 154 | ### data [object] 155 | 156 | ```jsx 157 | 158 | const myData = { 159 | type: 'line', 160 | series: [ 161 | { values: [1,2,4,5,6] } 162 | ] 163 | }; 164 | 165 | 166 | ``` 167 | 168 | ### `id` [string] (optional) 169 | The id for the DOM element for ZingChart to attach to. If no id is specified, the id will be autogenerated in the form of zingchart-react-# 170 | 171 | ### `series` [array] (optional) 172 | Accepts an array of series objects, and overrides a series if it was supplied into the config object. Varries by chart type used - Refer to the ZingChart documentation for more details. 173 | 174 | 175 | ```jsx 176 | const myData = { 177 | type: 'line', 178 | }; 179 | 180 | const mySeries = [ 181 | { values: [1,2,4,5,6] } 182 | ]; 183 | 184 | 185 | 186 | ``` 187 | 188 | ### `width` [string or number] (optional) 189 | 190 | The width of the chart. **Defaults to 100%**. 191 | 192 | ### `height` [string or number] (optional) 193 | 194 | The height of the chart. **Defaults to 480px**. 195 | 196 | ### `theme` [object] (optional) 197 | 198 | The theme or 'defaults' object defined by ZingChart. More information available here: https://www.zingchart.com/docs/api/themes 199 | 200 | ### modules [string] (optional) 201 | The modules object to load additional modules. More information available here: https://www.zingchart.com/docs/api/zingchart-modules#modules-list 202 | 203 | ### `output` [string] (optional) 204 | 205 | The render type of the chart. **The default is `svg`** but you can also pass the string `canvas` to render the charts in canvas. 206 | 207 | Note: All other properties that are added as a prop will be added to the render object. This allows for settings such as 'customprogresslogo' to be set. Any unrecognized properties will be ignored. 208 | 209 | ## Events 210 | All zingchart events are readily available on the component to listen to. For example, to listen for the 'complete' event when the chart is finished rendering: 211 | 212 | ```jsx 213 | class App extends Component { 214 | constructor(props) { 215 | super(props); 216 | this.state = { 217 | config: { 218 | type: 'line', 219 | series: [{ 220 | values: [4,5,3,4,5,3,5,4,11] 221 | }] 222 | } 223 | } 224 | this.chartDone = this.chartDone.bind(this); 225 | } 226 | render() { 227 | return ( 228 |
    229 | 230 |
    231 | ); 232 | } 233 | chartDone(event) { 234 | console.log(`Event "Complete" - The chart is rendered\n`); 235 | } 236 | } 237 | ``` 238 | 239 | For a list of all the events that you can listen to, refer to the complete documentation on https://www.zingchart.com/docs/api/events 240 | 241 | 242 | ### Methods 243 | 244 | All zingchart methods are readily available on the component's instance to call. For example, to add a new plot node to the chart: 245 | 246 | ```jsx 247 | class App extends Component { 248 | constructor(props) { 249 | super(props); 250 | this.state = { 251 | config: { 252 | type: 'bar', 253 | series: [{ 254 | values: [4,5,3,4,5,3,5,4,11] 255 | }] 256 | } 257 | }; 258 | this.chart = React.createRef(); 259 | this.addPlot = this.addPlot.bind(this); 260 | 261 | } 262 | render() { 263 | return ( 264 |
    265 | 266 | 267 |
    268 | ); 269 | } 270 | addPlot() { 271 | this.chart.current.addplot({ 272 | data: { 273 | values: [5,3,3,5,6,4,3,4,6], 274 | text: "My new plot" 275 | } 276 | }); 277 | } 278 | } 279 | 280 | ``` 281 | 282 | For a list of all the methods that you can call and the parameters each method can take, refer to the complete documentation on https://www.zingchart.com/docs/api/methods 283 | 284 | ## Working Example 285 | 286 | See https://github.com/zingchart-demos/zingchart-react-demo for a demo based on "Create React App" that shows this component in action. 287 | --------------------------------------------------------------------------------