├── .nvmrc
├── website
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── favicon.ico
│ │ ├── chartist-guy.gif
│ │ └── logo.svg
├── CNAME
├── docs
│ ├── api
│ │ ├── .gitignore
│ │ ├── basics.md
│ │ └── docs.js
│ ├── plugins.md
│ ├── docs.js
│ ├── examples
│ │ ├── docs.js
│ │ └── index.mdx
│ ├── what-is-it-made-for.md
│ ├── whats-new-in-v1.md
│ └── index.mdx
├── babel.config.js
├── .gitignore
├── tsconfig.json
├── src
│ ├── components
│ │ └── ContextProvider.tsx
│ ├── css
│ │ ├── custom.css
│ │ └── recoloring.css
│ └── prism-theme.js
├── README.md
├── sidebars.js
├── package.json
└── docusaurus.config.js
├── .gitattributes
├── .npmrc
├── pnpm-workspace.yaml
├── src
├── event
│ ├── index.ts
│ └── EventEmitter.ts
├── charts
│ ├── BarChart
│ │ ├── index.ts
│ │ └── BarChart.types.ts
│ ├── PieChart
│ │ ├── index.ts
│ │ └── PieChart.stories.ts
│ ├── LineChart
│ │ └── index.ts
│ ├── index.ts
│ └── types.ts
├── utils
│ ├── index.ts
│ ├── types.ts
│ ├── extend.ts
│ ├── functional.ts
│ └── utils.ts
├── svg
│ ├── index.ts
│ ├── types.ts
│ └── SvgList.ts
├── axes
│ ├── index.ts
│ ├── types.ts
│ ├── StepAxis.ts
│ ├── StepAxis.spec.ts
│ ├── FixedScaleAxis.spec.ts
│ ├── FixedScaleAxis.ts
│ ├── AutoScaleAxis.ts
│ └── Axis.spec.ts
├── interpolation
│ ├── index.ts
│ ├── none.ts
│ ├── simple.ts
│ └── step.ts
├── core
│ ├── data
│ │ ├── index.ts
│ │ ├── serialize.spec.ts
│ │ ├── data.ts
│ │ ├── serialize.ts
│ │ ├── segments.spec.ts
│ │ ├── segments.ts
│ │ └── highLow.ts
│ ├── index.ts
│ ├── constants.ts
│ ├── lang.spec.ts
│ ├── lang.ts
│ ├── optionsProvider.ts
│ └── math.ts
├── index.ts
└── styles
│ └── _settings.scss
├── .browserslistrc
├── .czrc
├── .storybook
├── package.json
├── manager.js
├── theme.js
├── preview.js
└── main.js
├── .clean-publish
├── .nano-staged.json
├── .github
├── FUNDING.yml
├── renovate.json
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature-request.yml
│ └── bug-report.yml
└── workflows
│ ├── commit.yml
│ ├── release.yml
│ ├── update-storyshots.yml
│ ├── ci.yml
│ ├── website.yml
│ └── checks.yml
├── test
├── setup.js
├── __image_snapshots__
│ ├── BarChart__Default-snap.png
│ ├── BarChart__Labels-snap.png
│ ├── BarChart__Stack-snap.png
│ ├── LineChart__Area-snap.png
│ ├── LineChart__Holes-snap.png
│ ├── LineChart__Labels-snap.png
│ ├── PieChart__Default-snap.png
│ ├── PieChart__Donut-snap.png
│ ├── PieChart__Labels-snap.png
│ ├── PieChart__Solid-snap.png
│ ├── BarChart__Adaptive-snap.png
│ ├── BarChart__Bi-Polar-snap.png
│ ├── LineChart__Default-snap.png
│ ├── LineChart__Scatter-snap.png
│ ├── BarChart__Horizontal-snap.png
│ ├── BarChart__Multi-Series-snap.png
│ ├── BarChart__Peak-Circles-snap.png
│ ├── BarChart__Reverse-Data-snap.png
│ ├── LineChart__Auto-Scale-snap.png
│ ├── LineChart__Full-Width-snap.png
│ ├── PieChart__Gauge-Donut-snap.png
│ ├── PieChart__Small-Slices-snap.png
│ ├── PieChart__Start-Angle-snap.png
│ ├── BarChart__Adaptive__iPad-snap.png
│ ├── LineChart__Bi-Polar-Area-snap.png
│ ├── LineChart__Custom-Points-snap.png
│ ├── LineChart__Filled-Holes-snap.png
│ ├── LineChart__Multi-Series-snap.png
│ ├── LineChart__Reverse-Data-snap.png
│ ├── BarChart__Labels-Placement-snap.png
│ ├── BarChart__Multiline-Labels-snap.png
│ ├── LineChart__Path-Animation-snap.png
│ ├── LineChart__Series-Overrides-snap.png
│ ├── BarChart__Adaptive__iPhone-X-snap.png
│ ├── BarChart__Distributed-Series-snap.png
│ ├── LineChart__Only-Whole-Numbers-snap.png
│ ├── PieChart__Ignore-Empty-Values-snap.png
│ ├── PieChart__Label-Interpolation-snap.png
│ ├── PieChart__Relative-Donut-Width-snap.png
│ ├── BarChart__Accumulate-Relative-Stack-snap.png
│ ├── BarChart__Overlapping-Bars-On-Mobile-snap.png
│ ├── BarChart__Adaptive__iPhone-X-landscape-snap.png
│ ├── LineChart__No-Interpolation-With-Holes-snap.png
│ ├── LineChart__Simple-Interpolation-With-Holes-snap.png
│ ├── LineChart__Step-Interpolation-With-Holes-snap.png
│ ├── LineChart__Cardinal-Interpolation-With-Holes-snap.png
│ ├── BarChart__Overlapping-Bars-On-Mobile__iPhone-X-snap.png
│ ├── LineChart__Monotone-Cubic-Interpolation-With-Holes-snap.png
│ └── LineChart__Step-No-Postpone-Interpolation-With-Holes-snap.png
├── utils
│ ├── storyshots
│ │ ├── index.js
│ │ ├── viewport.ts
│ │ ├── storybook.js
│ │ ├── initStoryshots.js
│ │ └── imageSnapshotWithStoryParameters.js
│ └── skipable.js
├── mock
│ ├── cssModule.js
│ └── dom.ts
└── storyshots.spec.js
├── .commitlintrc.json
├── tsconfig.build.json
├── .simple-git-hooks.json
├── sandboxes
├── bar
│ ├── stacked
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── horizontal
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── multiline
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── distributed-series
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── extreme-responsive
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── label-position
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── overlapping-bars
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── bi-polar-interpolated
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── stacked-accumulate-relative
│ │ ├── sandbox.config.json
│ │ ├── index.html
│ │ ├── package.json
│ │ └── index.ts
│ └── with-circle-modify-drawing
│ │ ├── sandbox.config.json
│ │ ├── index.html
│ │ ├── package.json
│ │ └── index.ts
├── line
│ ├── area
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── simple
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── axis-auto
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── bipolar-area
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── data-holes
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── only-integer
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── timeseries
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── data-fill-holes
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── modify-drawing
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── path-animation
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── scatter-random
│ │ ├── sandbox.config.json
│ │ ├── index.html
│ │ ├── package.json
│ │ └── index.ts
│ ├── series-override
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── simple-responsive
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── simple-smoothing
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── svg-animation
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ └── index.html
│ ├── axis-fixed-and-auto
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ └── simple-svg-animation
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
├── pie
│ ├── simple
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── custom-labels
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── donut-chart
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ ├── simple-gauge
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
│ └── donut-animation
│ │ ├── sandbox.config.json
│ │ ├── package.json
│ │ ├── index.html
│ │ └── index.ts
└── tsconfig.json
├── .prettierrc
├── .gitignore
├── postcss.config.cjs
├── .editorconfig
├── LICENSE-WTFPL
├── .size-limit.json
├── jest.config.json
├── tsconfig.json
├── LICENSE-MIT
├── CONTRIBUTING.md
├── scripts
└── styles.cjs
├── rollup.config.js
└── .eslintrc.json
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/*
2 |
--------------------------------------------------------------------------------
/website/static/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/website/CNAME:
--------------------------------------------------------------------------------
1 | chartist.js.org
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | strict-peer-dependencies=false
2 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'website'
3 |
--------------------------------------------------------------------------------
/src/event/index.ts:
--------------------------------------------------------------------------------
1 | export * from './EventEmitter';
2 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | defaults
2 | not ie 11
3 | not ie_mob 11
4 |
--------------------------------------------------------------------------------
/.czrc:
--------------------------------------------------------------------------------
1 | {
2 | "path": "@commitlint/cz-commitlint"
3 | }
4 |
--------------------------------------------------------------------------------
/.storybook/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "commonjs"
3 | }
4 |
--------------------------------------------------------------------------------
/website/docs/api/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 | !docs.js
4 | !basics.md
5 |
--------------------------------------------------------------------------------
/.clean-publish:
--------------------------------------------------------------------------------
1 | {
2 | "withoutPublish": true,
3 | "tempDir": "package"
4 | }
5 |
--------------------------------------------------------------------------------
/.nano-staged.json:
--------------------------------------------------------------------------------
1 | {
2 | "**/*.{js,ts}": ["prettier --write", "eslint"]
3 | }
4 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: gionkunz
4 |
--------------------------------------------------------------------------------
/src/charts/BarChart/index.ts:
--------------------------------------------------------------------------------
1 | export * from './BarChart';
2 | export * from './BarChart.types';
3 |
--------------------------------------------------------------------------------
/src/charts/PieChart/index.ts:
--------------------------------------------------------------------------------
1 | export * from './PieChart';
2 | export * from './PieChart.types';
3 |
--------------------------------------------------------------------------------
/src/charts/LineChart/index.ts:
--------------------------------------------------------------------------------
1 | export * from './LineChart';
2 | export * from './LineChart.types';
3 |
--------------------------------------------------------------------------------
/test/setup.js:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom/extend-expect';
2 |
3 | window.matchMedia = () => ({});
4 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base",
4 | ":preserveSemverRanges"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/website/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/website/static/img/favicon.ico
--------------------------------------------------------------------------------
/website/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')]
3 | };
4 |
--------------------------------------------------------------------------------
/website/static/img/chartist-guy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/website/static/img/chartist-guy.gif
--------------------------------------------------------------------------------
/website/docs/plugins.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /docs/plugins
3 | description: Plugins
4 | ---
5 |
6 | # Plugins
7 |
8 | Coming soon.
9 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './types';
2 | export * from './extend';
3 | export * from './functional';
4 | export * from './utils';
5 |
--------------------------------------------------------------------------------
/.commitlintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["@commitlint/config-conventional"],
3 | "rules": {
4 | "body-max-line-length": [0]
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": [
4 | "**/*.stories.ts",
5 | "**/*.spec.ts"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.simple-git-hooks.json:
--------------------------------------------------------------------------------
1 | {
2 | "commit-msg": "pnpm commitlint --edit \"$1\"",
3 | "pre-commit": "pnpm nano-staged",
4 | "pre-push": "pnpm test"
5 | }
6 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Default-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Default-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Labels-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Labels-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Stack-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Stack-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Area-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Area-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Holes-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Labels-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Labels-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Default-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Default-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Donut-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Donut-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Labels-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Labels-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Solid-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Solid-snap.png
--------------------------------------------------------------------------------
/test/utils/storyshots/index.js:
--------------------------------------------------------------------------------
1 | export * from './initStoryshots';
2 | export * from './imageSnapshotWithStoryParameters';
3 | export * from './storybook';
4 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Adaptive-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Adaptive-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Bi-Polar-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Bi-Polar-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Default-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Default-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Scatter-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Scatter-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Horizontal-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Horizontal-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Multi-Series-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Multi-Series-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Peak-Circles-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Peak-Circles-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Reverse-Data-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Reverse-Data-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Auto-Scale-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Auto-Scale-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Full-Width-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Full-Width-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Gauge-Donut-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Gauge-Donut-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Small-Slices-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Small-Slices-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Start-Angle-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Start-Angle-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Adaptive__iPad-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Adaptive__iPad-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Bi-Polar-Area-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Bi-Polar-Area-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Custom-Points-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Custom-Points-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Filled-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Filled-Holes-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Multi-Series-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Multi-Series-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Reverse-Data-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Reverse-Data-snap.png
--------------------------------------------------------------------------------
/test/mock/cssModule.js:
--------------------------------------------------------------------------------
1 | const mock = new Proxy(
2 | {},
3 | {
4 | get() {
5 | return '';
6 | }
7 | }
8 | );
9 |
10 | module.exports = mock;
11 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/area/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/simple/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/src/charts/index.ts:
--------------------------------------------------------------------------------
1 | export * from './BaseChart';
2 | export * from './LineChart';
3 | export * from './BarChart';
4 | export * from './PieChart';
5 | export * from './types';
6 |
--------------------------------------------------------------------------------
/src/svg/index.ts:
--------------------------------------------------------------------------------
1 | export { easings } from './animation';
2 | export * from './Svg';
3 | export * from './SvgPath';
4 | export * from './SvgList';
5 | export * from './types';
6 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Labels-Placement-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Labels-Placement-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Multiline-Labels-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Multiline-Labels-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Path-Animation-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Path-Animation-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Series-Overrides-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Series-Overrides-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/horizontal/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/bar/multiline/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-auto/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/bipolar-area/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/data-holes/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/only-integer/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/timeseries/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/pie/custom-labels/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-chart/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple-gauge/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/src/axes/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Axis';
2 | export * from './AutoScaleAxis';
3 | export * from './FixedScaleAxis';
4 | export * from './StepAxis';
5 | export * from './types';
6 |
--------------------------------------------------------------------------------
/src/interpolation/index.ts:
--------------------------------------------------------------------------------
1 | export * from './none';
2 | export * from './simple';
3 | export * from './step';
4 | export * from './cardinal';
5 | export * from './monotoneCubic';
6 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Adaptive__iPhone-X-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Adaptive__iPhone-X-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Distributed-Series-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Distributed-Series-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Only-Whole-Numbers-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Only-Whole-Numbers-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Ignore-Empty-Values-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Ignore-Empty-Values-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Label-Interpolation-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Label-Interpolation-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/distributed-series/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/bar/extreme-responsive/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/bar/label-position/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/bar/overlapping-bars/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/data-fill-holes/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/modify-drawing/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/path-animation/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/scatter-random/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/series-override/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-responsive/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-smoothing/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/svg-animation/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-animation/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/PieChart__Relative-Donut-Width-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/PieChart__Relative-Donut-Width-snap.png
--------------------------------------------------------------------------------
/.storybook/manager.js:
--------------------------------------------------------------------------------
1 | import { addons } from '@storybook/addons';
2 |
3 | import { theme } from './theme';
4 |
5 | addons.setConfig({
6 | theme,
7 | panelPosition: 'right'
8 | });
9 |
--------------------------------------------------------------------------------
/sandboxes/bar/bi-polar-interpolated/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-fixed-and-auto/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-svg-animation/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/website/docs/docs.js:
--------------------------------------------------------------------------------
1 | exports.docs = [
2 | { title: "What's new in v1?", slug: '/docs/whats-new-in-v1' },
3 | { title: 'What is it made for?', slug: '/docs/what-is-it-made-for' }
4 | ];
5 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked-accumulate-relative/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/sandboxes/bar/with-circle-modify-drawing/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": true,
4 | "view": "browser",
5 | "template": "parcel"
6 | }
7 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Accumulate-Relative-Stack-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Accumulate-Relative-Stack-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Overlapping-Bars-On-Mobile-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Overlapping-Bars-On-Mobile-snap.png
--------------------------------------------------------------------------------
/sandboxes/line/area/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-area",
3 | "description": "Line chart with area",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pie-simple",
3 | "description": "Simple pie chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Adaptive__iPhone-X-landscape-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Adaptive__iPhone-X-landscape-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__No-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__No-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/multiline/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-multiline",
3 | "description": "Multi-line labels",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-stacked",
3 | "description": "Stacked bar chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-auto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-axis-auto",
3 | "description": "Auto scale axis",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/data-holes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-data-holes",
3 | "description": "Holes in data",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-simple",
3 | "description": "Simple line chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/timeseries/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-timeseries",
3 | "description": "Timeseries",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-chart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pie-donut-chart",
3 | "description": "Donut chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple-gauge/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pie-simple-gauge",
3 | "description": "Gauge chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Simple-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Simple-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Step-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Step-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/horizontal/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-horizontal",
3 | "description": "Horizontal bar chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/core/data/index.ts:
--------------------------------------------------------------------------------
1 | export * from './bounds';
2 | export * from './data';
3 | export * from './highLow';
4 | export * from './normalize';
5 | export * from './segments';
6 | export * from './serialize';
7 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Cardinal-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Cardinal-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/label-position/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-label-position",
3 | "description": "Label placement",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/only-integer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-only-integer",
3 | "description": "Only whole numbers",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/BarChart__Overlapping-Bars-On-Mobile__iPhone-X-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/BarChart__Overlapping-Bars-On-Mobile__iPhone-X-snap.png
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "jsxSingleQuote": true,
4 | "semi": true,
5 | "tabWidth": 2,
6 | "bracketSpacing": true,
7 | "arrowParens": "avoid",
8 | "trailingComma": "none"
9 | }
10 |
--------------------------------------------------------------------------------
/sandboxes/line/path-animation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-path-animation",
3 | "description": "SVG Path animation",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/series-override/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-series-override",
3 | "description": "Series Overrides",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.storybook/theme.js:
--------------------------------------------------------------------------------
1 | import { create } from '@storybook/theming';
2 |
3 | export const theme = create({
4 | base: 'light',
5 | brandTitle: 'chartist',
6 | brandUrl: 'https://github.com/chartist-js/chartist'
7 | });
8 |
--------------------------------------------------------------------------------
/sandboxes/bar/distributed-series/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-distributed-series",
3 | "description": "Distributed series",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/data-fill-holes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-data-fill-holes",
3 | "description": "Filled holes in data",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/svg-animation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-svg-animation",
3 | "description": "Advanced SMIL Animations",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/pie/custom-labels/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pie-custom-labels",
3 | "description": "Pie chart with custom labels",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "chartist": ["../src"]
7 | }
8 | },
9 | "include": ["."]
10 | }
11 |
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Monotone-Cubic-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Monotone-Cubic-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/test/__image_snapshots__/LineChart__Step-No-Postpone-Interpolation-With-Holes-snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mamkin-skuf/chartist/HEAD/test/__image_snapshots__/LineChart__Step-No-Postpone-Interpolation-With-Holes-snap.png
--------------------------------------------------------------------------------
/sandboxes/bar/bi-polar-interpolated/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-bi-polar-interpolated",
3 | "description": "Bi-polar bar chart",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/bar/overlapping-bars/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-overlapping-bars",
3 | "description": "Overlapping bars on mobile",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/bipolar-area/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-bipolar-area",
3 | "description": "Bi-polar Line chart with area only",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.*
14 |
15 | npm-debug.log*
16 |
--------------------------------------------------------------------------------
/sandboxes/line/area/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-fixed-and-auto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-axis-fixed-and-auto",
3 | "description": "Fixed and auto scale axis",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/modify-drawing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-modify-drawing",
3 | "description": "Using events to replace graphics",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-responsive/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-simple-responsive",
3 | "description": "Simple responsive options",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-smoothing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-simple-smoothing",
3 | "description": "Line Interpolation / Smoothing",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-svg-animation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-simple-svg-animation",
3 | "description": "Simple SMIL Animations",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-animation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pie-donut-animation",
3 | "description": "Animating a Donut with Svg.animate",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/core/index.ts:
--------------------------------------------------------------------------------
1 | export * from './constants';
2 | export * from './lang';
3 | export * from './math';
4 | export * from './data';
5 | export * from './creation';
6 | export * from './optionsProvider';
7 | export * from './types';
8 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './core';
2 | export * from './event';
3 | export * from './charts';
4 | export * from './axes';
5 | export * as Interpolation from './interpolation';
6 | export * from './svg';
7 | export * from './utils';
8 |
--------------------------------------------------------------------------------
/website/docs/examples/docs.js:
--------------------------------------------------------------------------------
1 | exports.docs = [
2 | { title: 'Bar Chart', slug: '/examples/bar-chart' },
3 | { title: 'Line Chart', slug: '/examples/line-chart' },
4 | { title: 'Pie Chart', slug: '/examples/pie-chart' }
5 | ];
6 |
--------------------------------------------------------------------------------
/sandboxes/bar/extreme-responsive/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-extreme-responsive",
3 | "description": "Extreme responsive configuration",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/bar/horizontal/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/multiline/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-auto/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/simple/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // This file is not used in compilation. It is here just for a nice editor experience.
3 | "extends": "@tsconfig/docusaurus/tsconfig.json",
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 🤔 Have a Question?
4 | url: https://stackoverflow.com/questions/tagged/chartist.js
5 | about: Feel free to ask questions on Stack Overflow.
6 |
--------------------------------------------------------------------------------
/sandboxes/bar/label-position/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/bipolar-area/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/data-holes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/modify-drawing/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/only-integer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/path-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/scatter-random/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/scatter-random/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "line-scatter-random",
3 | "description": "Line scatter diagram with responsive settings",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/line/svg-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/timeseries/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/pie/custom-labels/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-chart/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple-gauge/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/distributed-series/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/extreme-responsive/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/overlapping-bars/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-fixed-and-auto/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/data-fill-holes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/series-override/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-responsive/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-smoothing/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/bi-polar-interpolated/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-svg-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked-accumulate-relative/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked-accumulate-relative/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-stacked",
3 | "description": "Stacked bar chart with accumulate-relative stack mode",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/bar/with-circle-modify-drawing/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sandboxes/bar/with-circle-modify-drawing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bar-with-circle-modify-drawing",
3 | "description": "Add peak circles using the draw events",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "chartist": "^1.0.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # builds
7 | package
8 | dist
9 | storybook-static
10 |
11 | # misc
12 | .DS_Store
13 |
14 | npm-debug.log*
15 |
16 | # testing
17 | coverage
18 |
--------------------------------------------------------------------------------
/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | const isProd = process.env.NODE_ENV !== 'development';
2 |
3 | module.exports = {
4 | plugins: [
5 | require('postcss-preset-env'),
6 | isProd &&
7 | require('cssnano')({
8 | preset: 'default'
9 | })
10 | ].filter(Boolean)
11 | };
12 |
--------------------------------------------------------------------------------
/src/axes/types.ts:
--------------------------------------------------------------------------------
1 | import type { AutoScaleAxis } from './AutoScaleAxis';
2 | import type { FixedScaleAxis } from './FixedScaleAxis';
3 | import type { StepAxis } from './StepAxis';
4 |
5 | export type AxisType =
6 | | typeof AutoScaleAxis
7 | | typeof FixedScaleAxis
8 | | typeof StepAxis;
9 |
--------------------------------------------------------------------------------
/test/utils/skipable.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Make block definition method skipable.
3 | * @param fn - Jest's block definition method.
4 | * @param skip - Skip test block.
5 | * @returns Skipable block definition methid.
6 | */
7 | export function skipable(fn, skip) {
8 | return skip ? fn.skip : fn;
9 | }
10 |
--------------------------------------------------------------------------------
/sandboxes/line/area/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8],
8 | series: [[5, 9, 7, 8, 5, 3, 5, 4]]
9 | },
10 | {
11 | low: 0,
12 | showArea: true
13 | }
14 | );
15 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-chart/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { PieChart } from 'chartist';
3 |
4 | new PieChart(
5 | '#chart',
6 | {
7 | series: [20, 10, 30, 40]
8 | },
9 | {
10 | donut: true,
11 | donutWidth: 60,
12 | startAngle: 270,
13 | showLabel: true
14 | }
15 | );
16 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { PieChart } from 'chartist';
3 |
4 | const data = {
5 | series: [5, 3, 4]
6 | };
7 |
8 | new PieChart('#chart', data, {
9 | labelInterpolationFnc: value =>
10 | Math.round((+value / data.series.reduce((a, b) => a + b)) * 100) + '%'
11 | });
12 |
--------------------------------------------------------------------------------
/sandboxes/bar/distributed-series/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: ['XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'],
8 | series: [20, 60, 120, 200, 180, 20, 10]
9 | },
10 | {
11 | distributeSeries: true
12 | }
13 | );
14 |
--------------------------------------------------------------------------------
/sandboxes/pie/simple-gauge/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { PieChart } from 'chartist';
3 |
4 | new PieChart(
5 | '#chart',
6 | {
7 | series: [20, 10, 30, 40]
8 | },
9 | {
10 | donut: true,
11 | donutWidth: 60,
12 | startAngle: 270,
13 | total: 200,
14 | showLabel: false
15 | }
16 | );
17 |
--------------------------------------------------------------------------------
/src/utils/types.ts:
--------------------------------------------------------------------------------
1 | export type FilterByKey = T extends Record
2 | ? T
3 | : T extends Partial>
4 | ? T & { [key in K]: T[K] }
5 | : never;
6 |
7 | export type RequiredKeys = T &
8 | Required> & { [key in V]: Required };
9 |
--------------------------------------------------------------------------------
/website/docs/examples/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /examples
3 | description: List of Chartist usage examples.
4 | ---
5 |
6 | import Link from '@docusaurus/Link';
7 | import { docs } from './docs';
8 |
9 | # Examples
10 |
11 |
12 | {docs.map(({ title, slug }, i) => (
13 | -
14 | {title}
15 |
16 | ))}
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/commit.yml:
--------------------------------------------------------------------------------
1 | name: Commit
2 | on:
3 | push:
4 | jobs:
5 | commitlint:
6 | runs-on: ubuntu-latest
7 | name: commitlint
8 | steps:
9 | - name: Checkout the repository
10 | uses: actions/checkout@v3
11 | with:
12 | fetch-depth: 0
13 | - name: Run commitlint
14 | uses: wagoid/commitlint-github-action@v4
15 |
--------------------------------------------------------------------------------
/test/utils/storyshots/viewport.ts:
--------------------------------------------------------------------------------
1 | export const Viewport = {
2 | Default: 'default',
3 | Mobile: 'iPhone X',
4 | MobileLandscape: 'iPhone X landscape',
5 | SmallMobile: 'iPhone SE',
6 | SmallMobileLandscape: 'iPhone SE landscape',
7 | Tablet: 'iPad',
8 | TabletLandscape: 'iPad landscape',
9 | SmallTablet: 'Nexus 7',
10 | SmallTabletLandscape: 'Nexus 7 landscape'
11 | };
12 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked-accumulate-relative/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday'],
8 | series: [
9 | [5, 4, -3, -5],
10 | [5, -4, 3, -5]
11 | ]
12 | },
13 | {
14 | stackBars: true,
15 | stackMode: 'accumulate-relative'
16 | }
17 | );
18 |
--------------------------------------------------------------------------------
/sandboxes/line/simple/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
8 | series: [
9 | [12, 9, 7, 8, 5],
10 | [2, 1, 3.5, 7, 3],
11 | [1, 3, 4, 5, 6]
12 | ]
13 | },
14 | {
15 | fullWidth: true,
16 | chartPadding: {
17 | right: 40
18 | }
19 | }
20 | );
21 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
2 | import { configureActions } from '@storybook/addon-actions';
3 | import faker from 'faker';
4 |
5 | const SEED_VALUE = 584;
6 |
7 | if (process.env.STORYBOOK_STORYSHOTS) {
8 | // Make faker values reproducible.
9 | faker.seed(SEED_VALUE);
10 | }
11 |
12 | configureActions({
13 | depth: 5
14 | });
15 |
16 | export const parameters = {
17 | viewport: {
18 | viewports: INITIAL_VIEWPORTS
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-auto/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, AutoScaleAxis } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | series: [
8 | [
9 | { x: 1, y: 100 },
10 | { x: 2, y: 50 },
11 | { x: 3, y: 25 },
12 | { x: 5, y: 12.5 },
13 | { x: 8, y: 6.25 }
14 | ]
15 | ]
16 | },
17 | {
18 | axisX: {
19 | type: AutoScaleAxis,
20 | onlyInteger: true
21 | }
22 | }
23 | );
24 |
--------------------------------------------------------------------------------
/src/charts/types.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | DataEvent,
3 | OptionsChangedEvent,
4 | DrawEvent,
5 | CreatedEvent
6 | } from '../core';
7 | import type { AnimationEvent } from '../svg';
8 |
9 | export interface BaseChartEventsTypes<
10 | TCreateEvent = CreatedEvent,
11 | TDrawEvents = DrawEvent
12 | > {
13 | data: DataEvent;
14 | options: OptionsChangedEvent;
15 | animationBegin: AnimationEvent;
16 | animationEnd: AnimationEvent;
17 | created: TCreateEvent;
18 | draw: TDrawEvents;
19 | }
20 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/LICENSE-WTFPL:
--------------------------------------------------------------------------------
1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2 | Version 2, December 2004
3 |
4 | Copyright (C) 2004 Sam Hocevar
5 |
6 | Everyone is permitted to copy and distribute verbatim or modified
7 | copies of this license document, and changing it is allowed as long
8 | as the name is changed.
9 |
10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12 |
13 | 0. You just DO WHAT THE FUCK YOU WANT TO.
14 |
--------------------------------------------------------------------------------
/sandboxes/bar/bi-polar-interpolated/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart, BarChartOptions } from 'chartist';
3 |
4 | const data = {
5 | labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'],
6 | series: [[1, 2, 4, 8, 6, -2, -1, -4, -6, -2]]
7 | };
8 |
9 | const options: BarChartOptions = {
10 | high: 10,
11 | low: -10,
12 | axisX: {
13 | labelInterpolationFnc(value, index) {
14 | return index % 2 === 0 ? value : null;
15 | }
16 | }
17 | };
18 |
19 | new BarChart('#chart', data, options);
20 |
--------------------------------------------------------------------------------
/sandboxes/bar/label-position/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
8 | series: [
9 | [5, 4, 3, 7, 5, 10, 3],
10 | [3, 2, 9, 5, 4, 6, 4]
11 | ]
12 | },
13 | {
14 | axisX: {
15 | // On the x-axis start means top and end means bottom
16 | position: 'start'
17 | },
18 | axisY: {
19 | // On the y-axis start means left and end means right
20 | position: 'end'
21 | }
22 | }
23 | );
24 |
--------------------------------------------------------------------------------
/sandboxes/bar/horizontal/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: [
8 | 'Monday',
9 | 'Tuesday',
10 | 'Wednesday',
11 | 'Thursday',
12 | 'Friday',
13 | 'Saturday',
14 | 'Sunday'
15 | ],
16 | series: [
17 | [5, 4, 3, 7, 5, 10, 3],
18 | [3, 2, 9, 5, 4, 6, 4]
19 | ]
20 | },
21 | {
22 | seriesBarDistance: 10,
23 | reverseData: true,
24 | horizontalBars: true,
25 | axisY: {
26 | offset: 70
27 | }
28 | }
29 | );
30 |
--------------------------------------------------------------------------------
/test/storyshots.spec.js:
--------------------------------------------------------------------------------
1 | import { skipable } from './utils/skipable';
2 | import { initStoryshots } from './utils/storyshots';
3 |
4 | const testTimeout = 60 * 1000 * 10;
5 | const config = {
6 | url: 'http://localhost:6006',
7 | setupTimeout: testTimeout,
8 | testTimeout,
9 | getGotoOptions() {
10 | return {
11 | waitUntil: 'networkidle0',
12 | timeout: 0
13 | };
14 | }
15 | };
16 |
17 | const describeWhenLinux = skipable(
18 | describe,
19 | process.platform !== 'linux' || Boolean(process.env.STORYSHOTS_SKIP)
20 | );
21 |
22 | describeWhenLinux('Storyshots', () => {
23 | initStoryshots(config);
24 | });
25 |
--------------------------------------------------------------------------------
/.size-limit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "path": "dist/index.cjs",
4 | "limit": "36.45 kB",
5 | "webpack": false,
6 | "running": false
7 | },
8 | {
9 | "path": "dist/index.cjs",
10 | "limit": "7.45 kB",
11 | "import": "{ BarChart }"
12 | },
13 | {
14 | "path": "dist/index.js",
15 | "limit": "36.2 kB",
16 | "webpack": false,
17 | "running": false
18 | },
19 | {
20 | "path": "dist/index.js",
21 | "limit": "7.4 kB",
22 | "import": "{ BarChart }"
23 | },
24 | {
25 | "path": "dist/index.css",
26 | "limit": "1.3 kB",
27 | "webpack": false,
28 | "running": false
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/sandboxes/line/bipolar-area/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8],
8 | series: [
9 | [1, 2, 3, 1, -2, 0, 1, 0],
10 | [-2, -1, -2, -1, -2.5, -1, -2, -1],
11 | [0, 0, 0, 1, 2, 2.5, 2, 1],
12 | [2.5, 2, 1, 0.5, 1, 0.5, -1, -2.5]
13 | ]
14 | },
15 | {
16 | high: 3,
17 | low: -3,
18 | showArea: true,
19 | showLine: false,
20 | showPoint: false,
21 | fullWidth: true,
22 | axisX: {
23 | showLabel: false,
24 | showGrid: false
25 | }
26 | }
27 | );
28 |
--------------------------------------------------------------------------------
/sandboxes/bar/stacked/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: ['Q1', 'Q2', 'Q3', 'Q4'],
8 | series: [
9 | [800000, 1200000, 1400000, 1300000],
10 | [200000, 400000, 500000, 300000],
11 | [100000, 200000, 400000, 600000]
12 | ]
13 | },
14 | {
15 | stackBars: true,
16 | axisY: {
17 | labelInterpolationFnc: value => +value / 1000 + 'k'
18 | }
19 | }
20 | ).on('draw', data => {
21 | if (data.type === 'bar') {
22 | data.element.attr({
23 | style: 'stroke-width: 30px'
24 | });
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/sandboxes/line/only-integer/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8],
8 | series: [
9 | [1, 2, 3, 1, -2, 0, 1, 0],
10 | [-2, -1, -2, -1, -3, -1, -2, -1],
11 | [0, 0, 0, 1, 2, 3, 2, 1],
12 | [3, 2, 1, 0.5, 1, 0, -1, -3]
13 | ]
14 | },
15 | {
16 | high: 3,
17 | low: -3,
18 | fullWidth: true,
19 | // As this is axis specific we need to tell Chartist to use whole numbers only on the concerned axis
20 | axisY: {
21 | onlyInteger: true,
22 | offset: 20
23 | }
24 | }
25 | );
26 |
--------------------------------------------------------------------------------
/website/docs/api/basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /api/basics
3 | description: List of Chartist basic APIs.
4 | ---
5 |
6 | # List of basic APIs:
7 |
8 | - Charts
9 | - [BarChart](/api/classes/BarChart)
10 | - [LineChart](/api/classes/LineChart)
11 | - [PieChart](/api/classes/PieChart)
12 | - Axes types
13 | - [AutoScaleAxis](/api/classes/AutoScaleAxis)
14 | - [FixedScaleAxis](/api/classes/FixedScaleAxis)
15 | - [StepAxis](/api/classes/StepAxis)
16 | - Svg wrappers
17 | - [Svg](/api/classes/Svg)
18 | - [SvgPath](/api/classes/SvgPath)
19 | - [SvgList](/api/classes/SvgList)
20 | - [Interpolation](/api/namespaces/Interpolation)
21 | - [EventEmitter](/api/classes/EventEmitter)
22 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-smoothing/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, Interpolation } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5],
8 | series: [
9 | [1, 5, 10, 0, 1],
10 | [10, 15, 0, 1, 2]
11 | ]
12 | },
13 | {
14 | // Remove this configuration to see that chart rendered with cardinal spline interpolation
15 | // Sometimes, on large jumps in data values, it's better to use simple smoothing.
16 | lineSmooth: Interpolation.simple({
17 | divisor: 2
18 | }),
19 | fullWidth: true,
20 | chartPadding: {
21 | right: 20
22 | },
23 | low: 0
24 | }
25 | );
26 |
--------------------------------------------------------------------------------
/website/src/components/ContextProvider.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
3 | import useThemeContext from '@theme/hooks/useThemeContext';
4 |
5 | interface IContext {
6 | branch: string;
7 | theme: 'light' | 'dark';
8 | }
9 |
10 | export default function ContextProvider({
11 | children,
12 | }: {
13 | children(context: IContext): ReactNode;
14 | }) {
15 | const ctx = useDocusaurusContext();
16 | const { isDarkTheme } = useThemeContext();
17 | const context = {
18 | branch: ctx.siteConfig.customFields.branch as string,
19 | theme: isDarkTheme ? ('dark' as const) : ('light' as const),
20 | };
21 |
22 | return children(context);
23 | }
24 |
--------------------------------------------------------------------------------
/sandboxes/bar/multiline/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: [
8 | 'First quarter of the year',
9 | 'Second quarter of the year',
10 | 'Third quarter of the year',
11 | 'Fourth quarter of the year'
12 | ],
13 | series: [
14 | [60000, 40000, 80000, 70000],
15 | [40000, 30000, 70000, 65000],
16 | [8000, 3000, 10000, 6000]
17 | ]
18 | },
19 | {
20 | seriesBarDistance: 10,
21 | axisX: {
22 | offset: 60
23 | },
24 | axisY: {
25 | offset: 80,
26 | labelInterpolationFnc: value => value + ' CHF',
27 | scaleMinSpace: 15
28 | }
29 | }
30 | );
31 |
--------------------------------------------------------------------------------
/jest.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "testEnvironment": "jsdom",
3 | "testRegex": "(test|src)/.*\\.spec\\.(jsx?|tsx?)$",
4 | "setupFilesAfterEnv": ["/test/setup.js"],
5 | "transform": {
6 | "^.+\\.(t|j)sx?$": ["@swc/jest", {
7 | "env": {
8 | "targets": {
9 | "node": 14
10 | }
11 | }
12 | }]
13 | },
14 | "moduleNameMapper": {
15 | "^chartist-dev$": "/src",
16 | "^chartist-dev/styles$": "/test/mock/cssModule.js"
17 | },
18 | "collectCoverage": true,
19 | "collectCoverageFrom": [
20 | "src/**/*.{js,jsx,ts,tsx}",
21 | "!**/node_modules/**",
22 | "!**/*.stories.*"
23 | ],
24 | "coverageReporters": [
25 | "lcovonly",
26 | "text"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/sandboxes/line/axis-fixed-and-auto/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import {
3 | LineChart,
4 | AutoScaleAxis,
5 | FixedScaleAxis,
6 | Interpolation
7 | } from 'chartist';
8 |
9 | new LineChart(
10 | '#chart',
11 | {
12 | series: [
13 | [
14 | { x: 1, y: 100 },
15 | { x: 2, y: 50 },
16 | { x: 3, y: 25 },
17 | { x: 5, y: 12.5 },
18 | { x: 8, y: 6.25 }
19 | ]
20 | ]
21 | },
22 | {
23 | axisX: {
24 | type: AutoScaleAxis,
25 | onlyInteger: true
26 | },
27 | axisY: {
28 | type: FixedScaleAxis,
29 | ticks: [0, 50, 75, 87.5, 100],
30 | low: 0
31 | },
32 | lineSmooth: Interpolation.step(),
33 | showPoint: false
34 | }
35 | );
36 |
--------------------------------------------------------------------------------
/src/axes/StepAxis.ts:
--------------------------------------------------------------------------------
1 | import type { ChartRect, AxisOptions } from '../core';
2 | import { AxisUnits, Axis } from './Axis';
3 |
4 | export class StepAxis extends Axis {
5 | private readonly stepLength: number;
6 | public readonly stretch: boolean;
7 |
8 | constructor(
9 | axisUnit: AxisUnits,
10 | _data: unknown,
11 | chartRect: ChartRect,
12 | options: AxisOptions
13 | ) {
14 | const ticks = options.ticks || [];
15 |
16 | super(axisUnit, chartRect, ticks);
17 |
18 | const calc = Math.max(1, ticks.length - (options.stretch ? 1 : 0));
19 | this.stepLength = this.axisLength / calc;
20 | this.stretch = Boolean(options.stretch);
21 | }
22 |
23 | projectValue(_value: unknown, index: number) {
24 | return this.stepLength * index;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/website/docs/api/docs.js:
--------------------------------------------------------------------------------
1 | exports.docs = [
2 | { title: 'Table of Contents', slug: '/api/basics' },
3 | { title: 'BarChart', slug: '/api/classes/BarChart' },
4 | { title: 'LineChart', slug: '/api/classes/LineChart' },
5 | { title: 'PieChart', slug: '/api/classes/PieChart' },
6 | { title: 'AutoScaleAxis', slug: '/api/classes/AutoScaleAxis' },
7 | { title: 'FixedScaleAxis', slug: '/api/classes/FixedScaleAxis' },
8 | { title: 'StepAxis', slug: '/api/classes/StepAxis' },
9 | { title: 'Svg', slug: '/api/classes/Svg' },
10 | { title: 'SvgPath', slug: '/api/classes/SvgPath' },
11 | { title: 'SvgList', slug: '/api/classes/SvgList' },
12 | { title: 'Interpolation', slug: '/api/namespaces/Interpolation' },
13 | { title: 'EventEmitter', slug: '/api/classes/EventEmitter' }
14 | ];
15 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | release:
4 | types: [created]
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | name: Publish package
9 | steps:
10 | - name: Checkout the repository
11 | uses: actions/checkout@v3
12 | - name: Install pnpm
13 | uses: pnpm/action-setup@v2
14 | with:
15 | version: 7
16 | - name: Install Node.js
17 | uses: actions/setup-node@v3
18 | with:
19 | node-version: 16
20 | cache: 'pnpm'
21 | registry-url: 'https://registry.npmjs.org'
22 | - name: Install dependencies
23 | run: pnpm install
24 | - name: Publish
25 | run: pnpm publish --no-git-checks
26 | env:
27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
28 |
--------------------------------------------------------------------------------
/src/axes/StepAxis.spec.ts:
--------------------------------------------------------------------------------
1 | import { StepAxis } from './StepAxis';
2 |
3 | describe('Axes', () => {
4 | describe('StepAxis', () => {
5 | it('should return 0 if options.ticks.length == 1', () => {
6 | const ticks = [1];
7 | const axisUnit = {
8 | pos: 'y',
9 | len: 'height',
10 | dir: 'vertical',
11 | rectStart: 'y2',
12 | rectEnd: 'y1',
13 | rectOffset: 'x1'
14 | } as const;
15 | const data = [[1]];
16 | const chartRect: any = {
17 | y2: 0,
18 | y1: 15,
19 | x1: 50,
20 | x2: 100
21 | };
22 | const options = {
23 | ticks
24 | };
25 | const stepAxis: any = new StepAxis(axisUnit, data, chartRect, options);
26 | expect(stepAxis.stepLength).toEqual(15);
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/core/constants.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This object contains all namespaces used within Chartist.
3 | */
4 | export const namespaces: Record = {
5 | svg: 'http://www.w3.org/2000/svg',
6 | xmlns: 'http://www.w3.org/2000/xmlns/',
7 | xhtml: 'http://www.w3.org/1999/xhtml',
8 | xlink: 'http://www.w3.org/1999/xlink',
9 | ct: 'http://gionkunz.github.com/chartist-js/ct'
10 | };
11 |
12 | /**
13 | * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.
14 | */
15 | export const precision = 8;
16 |
17 | /**
18 | * A map with characters to escape for strings to be safely used as attribute values.
19 | */
20 | export const escapingMap: Record = {
21 | '&': '&',
22 | '<': '<',
23 | '>': '>',
24 | '"': '"',
25 | "'": '''
26 | };
27 |
--------------------------------------------------------------------------------
/sandboxes/pie/custom-labels/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { PieChart, PieChartOptions, ResponsiveOptions } from 'chartist';
3 |
4 | const data = {
5 | labels: ['Bananas', 'Apples', 'Grapes'],
6 | series: [20, 15, 40]
7 | };
8 |
9 | const options: PieChartOptions = {
10 | labelInterpolationFnc: value => String(value)[0]
11 | };
12 |
13 | const responsiveOptions: ResponsiveOptions = [
14 | [
15 | 'screen and (min-width: 640px)',
16 | {
17 | chartPadding: 30,
18 | labelOffset: 100,
19 | labelDirection: 'explode',
20 | labelInterpolationFnc: value => value
21 | }
22 | ],
23 | [
24 | 'screen and (min-width: 1024px)',
25 | {
26 | labelOffset: 80,
27 | chartPadding: 20
28 | }
29 | ]
30 | ];
31 |
32 | new PieChart('#chart', data, options, responsiveOptions);
33 |
--------------------------------------------------------------------------------
/website/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
4 |
5 | ### Installation
6 |
7 | ```
8 | $ pnpm install
9 | ```
10 |
11 | ### Local Development
12 |
13 | ```
14 | $ pnpm start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ### Build
20 |
21 | ```
22 | $ pnpm build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ### Deployment
28 |
29 | ```
30 | $ GIT_USER= USE_SSH=true pnpm deploy
31 | ```
32 |
33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
34 |
--------------------------------------------------------------------------------
/.github/workflows/update-storyshots.yml:
--------------------------------------------------------------------------------
1 | name: Update storyshots
2 | on: workflow_dispatch
3 | jobs:
4 | update-storyshots:
5 | runs-on: ubuntu-latest
6 | name: storyshots
7 | steps:
8 | - name: Checkout the repository
9 | uses: actions/checkout@v3
10 | - name: Install pnpm
11 | uses: pnpm/action-setup@v2
12 | with:
13 | version: 7
14 | - name: Install Node.js
15 | uses: actions/setup-node@v3
16 | with:
17 | node-version: 16
18 | cache: 'pnpm'
19 | - name: Install dependencies
20 | run: pnpm install
21 | - name: Update snapshots
22 | run: pnpm test:storyshots -u
23 | - name: Collect artifacts
24 | uses: actions/upload-artifact@v3
25 | if: always()
26 | with:
27 | name: Updated storyshots
28 | path: test/__image_snapshots__/
29 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
5 | addons: [
6 | '@storybook/addon-docs',
7 | '@storybook/addon-controls',
8 | '@storybook/addon-actions',
9 | '@storybook/addon-viewport'
10 | ],
11 | webpackFinal: async config => {
12 | config.module.rules[0].use = [require.resolve('swc-loader')];
13 | config.module.rules.push({
14 | test: /\.scss$/,
15 | use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'].map(
16 | require.resolve
17 | )
18 | });
19 |
20 | config.resolve.alias['chartist-dev/styles$'] = path.resolve(
21 | __dirname,
22 | '..',
23 | 'src',
24 | 'styles',
25 | 'index.scss'
26 | );
27 | config.resolve.alias['chartist-dev$'] = path.resolve(
28 | __dirname,
29 | '..',
30 | 'src'
31 | );
32 |
33 | return config;
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/sandboxes/line/path-animation/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, easings } from 'chartist';
3 |
4 | const chart = new LineChart(
5 | '#chart',
6 | {
7 | labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
8 | series: [
9 | [1, 5, 2, 5, 4, 3],
10 | [2, 3, 4, 8, 1, 2],
11 | [5, 4, 3, 2, 1, 0.5]
12 | ]
13 | },
14 | {
15 | low: 0,
16 | showArea: true,
17 | showPoint: false,
18 | fullWidth: true
19 | }
20 | );
21 |
22 | chart.on('draw', data => {
23 | if (data.type === 'line' || data.type === 'area') {
24 | data.element.animate({
25 | d: {
26 | begin: 2000 * data.index,
27 | dur: 2000,
28 | from: data.path
29 | .clone()
30 | .scale(1, 0)
31 | .translate(0, data.chartRect.height())
32 | .stringify(),
33 | to: data.path.clone().stringify(),
34 | easing: easings.easeOutQuint
35 | }
36 | });
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Type Checking */
4 | "strict": true,
5 | "strictBindCallApply": true,
6 | "noFallthroughCasesInSwitch": true,
7 | "noImplicitOverride": true,
8 | "noImplicitReturns": true,
9 | "noUnusedLocals": true,
10 | "noUnusedParameters": true,
11 | /* Modules */
12 | "baseUrl": ".",
13 | "module": "esnext",
14 | "moduleResolution": "node",
15 | "resolveJsonModule": true,
16 | "paths": {
17 | "chartist-dev": ["src"]
18 | },
19 | /* Emit */
20 | "declaration": true,
21 | "declarationMap": true,
22 | "inlineSourceMap": true,
23 | "outDir": "dist",
24 | /* Interop Constraints */
25 | "allowSyntheticDefaultImports": true,
26 | "isolatedModules": true,
27 | /* Language and Environment */
28 | "lib": [
29 | "dom",
30 | "esnext"
31 | ],
32 | "target": "esnext",
33 | /* Completeness */
34 | "skipLibCheck": true
35 | },
36 | "include": [
37 | "src"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/sandboxes/line/scatter-random/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, times } from 'chartist';
3 |
4 | const data = times(52).reduce<{
5 | labels: number[];
6 | series: number[][];
7 | }>(
8 | (accData, _, index) => {
9 | accData.labels.push(index + 1);
10 | accData.series.forEach(series => {
11 | series.push(Math.random() * 100);
12 | });
13 |
14 | return accData;
15 | },
16 | {
17 | labels: [],
18 | series: times(4).map(() => [])
19 | }
20 | );
21 |
22 | new LineChart(
23 | '#chart',
24 | data,
25 | {
26 | showLine: false,
27 | axisX: {
28 | labelInterpolationFnc(value, index) {
29 | return index % 13 === 0 ? 'W' + value : null;
30 | }
31 | }
32 | },
33 | [
34 | [
35 | 'screen and (min-width: 640px)',
36 | {
37 | axisX: {
38 | labelInterpolationFnc(value, index) {
39 | return index % 4 === 0 ? 'W' + value : null;
40 | }
41 | }
42 | }
43 | ]
44 | ]
45 | );
46 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Gion Kunz
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/sandboxes/line/data-holes/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
8 | series: [
9 | [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9],
10 | [
11 | 10,
12 | 15,
13 | null,
14 | 12,
15 | null,
16 | 10,
17 | 12,
18 | 15,
19 | null,
20 | null,
21 | 12,
22 | null,
23 | 14,
24 | null,
25 | null,
26 | null
27 | ],
28 | [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null],
29 | [
30 | { x: 3, y: 3 },
31 | { x: 4, y: 3 },
32 | { x: 5, y: undefined },
33 | { x: 6, y: 4 },
34 | { x: 7, y: null },
35 | { x: 8, y: 4 },
36 | { x: 9, y: 4 }
37 | ]
38 | ]
39 | },
40 | {
41 | fullWidth: true,
42 | chartPadding: {
43 | right: 10
44 | },
45 | low: 0
46 | }
47 | );
48 |
--------------------------------------------------------------------------------
/src/core/lang.spec.ts:
--------------------------------------------------------------------------------
1 | import { quantity } from './lang';
2 |
3 | describe('Core', () => {
4 | describe('Lang', () => {
5 | describe('quantity', () => {
6 | it('should return value for numbers', () => {
7 | expect(quantity(100)).toEqual({ value: 100 });
8 | expect(quantity(0)).toEqual({ value: 0 });
9 | expect(quantity(NaN)).toEqual({ value: NaN });
10 | expect(quantity(null)).toEqual({ value: 0 });
11 | expect(quantity(undefined)).toEqual({ value: NaN });
12 | });
13 |
14 | it('should return value without unit from string', () => {
15 | expect(quantity('100')).toEqual({ value: 100, unit: undefined });
16 | expect(quantity('0')).toEqual({ value: 0, unit: undefined });
17 | });
18 |
19 | it('should return value and unit from string', () => {
20 | expect(quantity('100%')).toEqual({ value: 100, unit: '%' });
21 | expect(quantity('100 %')).toEqual({ value: 100, unit: '%' });
22 | expect(quantity('0px')).toEqual({ value: 0, unit: 'px' });
23 | });
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/website/docs/what-is-it-made-for.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /docs/what-is-it-made-for
3 | description: What is Chartist made for?
4 | ---
5 |
6 | # What is it made for?
7 |
8 | Chartist's goal is to provide a simple, lightweight and unintrusive library to responsively craft charts on your website.
9 | It's important to understand that one of the main intentions of Chartist is to rely on standards rather than providing
10 | it's own solution to a problem which is already solved by those standards. We need to leverage the power of browsers
11 | today and say good bye to the idea of solving all problems ourselves.
12 |
13 | Chartist works with inline-SVG and therefore leverages the power of the DOM to provide parts of its functionality. This
14 | also means that Chartist does not provide it's own event handling, labels, behaviors or anything else that can just be
15 | done with plain HTML, JavaScript and CSS. The single and only responsibility of Chartist is to help you drawing "Simple
16 | responsive Charts" using inline-SVG in the DOM, CSS to style and JavaScript to provide an API for configuring your charts.
17 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Chartist
2 |
3 | - [Issues and Bugs](#issue)
4 | - [Submission Guidelines](#submit)
5 |
6 | ## Found an Issue?
7 |
8 | If you find a bug in the source code or a mistake in the documentation, you can help us by
9 | submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
10 | with a fix.
11 |
12 | ## Pre-requisites
13 |
14 | You will need the following to run a local development enviroment.
15 |
16 | - Node.js & npm
17 | - pnpm (`npm install -g pnpm`)
18 | - Text editor of your choice
19 |
20 | ## How to Run a Local Distribution
21 |
22 | 1. `cd` into your local copy of the repository.
23 | 2. Run `pnpm i` to install dependencies located in `package.json`.
24 | 5. Run `pnpm start:storybook` to start Storybook, or run `pnpm jest --watch` to run tests in watch mode. Congrats, you should now be able to see your local copy of the Chartist testbed.
25 |
26 | ## Submission Guidelines
27 |
28 | If you are creating a Pull Request, fork the repository and make any changes on the `develop` branch.
29 |
--------------------------------------------------------------------------------
/website/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sandboxes/bar/overlapping-bars/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart, BarChartOptions, ResponsiveOptions } from 'chartist';
3 |
4 | const data = {
5 | labels: [
6 | 'Jan',
7 | 'Feb',
8 | 'Mar',
9 | 'Apr',
10 | 'Mai',
11 | 'Jun',
12 | 'Jul',
13 | 'Aug',
14 | 'Sep',
15 | 'Oct',
16 | 'Nov',
17 | 'Dec'
18 | ],
19 | series: [
20 | [5, 4, 3, 7, 5, 10, 3, 4, 8, 10, 6, 8],
21 | [3, 2, 9, 5, 4, 6, 4, 6, 7, 8, 7, 4]
22 | ]
23 | };
24 |
25 | const options = {
26 | seriesBarDistance: 15
27 | };
28 |
29 | const responsiveOptions: ResponsiveOptions = [
30 | [
31 | 'screen and (min-width: 641px) and (max-width: 1024px)',
32 | {
33 | seriesBarDistance: 10,
34 | axisX: {
35 | labelInterpolationFnc: value => value
36 | }
37 | }
38 | ],
39 | [
40 | 'screen and (max-width: 640px)',
41 | {
42 | seriesBarDistance: 5,
43 | axisX: {
44 | labelInterpolationFnc: value => String(value)[0]
45 | }
46 | }
47 | ]
48 | ];
49 |
50 | new BarChart('#chart', data, options, responsiveOptions);
51 |
--------------------------------------------------------------------------------
/website/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #7a77ff;
10 | --ifm-color-primary-dark: #5552ff;
11 | --ifm-color-primary-darker: #433fff;
12 | --ifm-color-primary-darkest: #0c07ff;
13 | --ifm-color-primary-light: #9f9cff;
14 | --ifm-color-primary-lighter: #b1afff;
15 | --ifm-color-primary-lightest: #e8e7ff;
16 | --ifm-code-font-size: 95%;
17 | }
18 |
19 | .docusaurus-highlight-code-line {
20 | background-color: rgba(0, 0, 0, 0.1);
21 | display: block;
22 | margin: 0 calc(-1 * var(--ifm-pre-padding));
23 | padding: 0 var(--ifm-pre-padding);
24 | }
25 |
26 | html[data-theme='dark'] .docusaurus-highlight-code-line {
27 | background-color: rgba(0, 0, 0, 0.3);
28 | }
29 |
30 | .logo {
31 | float: right;
32 | }
33 |
34 | @media (max-width: 768px) {
35 | .logo {
36 | float: none;
37 | display: block;
38 | margin: 0 auto;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/extend.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Simple recursive object extend
3 | * @param target Target object where the source will be merged into
4 | * @param sources This object (objects) will be merged into target and then target is returned
5 | * @return An object that has the same reference as target but is extended and merged with the properties of source
6 | */
7 | export function extend(target: T): T;
8 | export function extend(target: T, a: A): T & A;
9 | export function extend(target: T, a: A, b: B): T & A & B;
10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
11 | export function extend(target: any = {}, ...sources: any[]) {
12 | for (let i = 0; i < sources.length; i++) {
13 | const source = sources[i];
14 | for (const prop in source) {
15 | const sourceProp = source[prop];
16 | if (
17 | typeof sourceProp === 'object' &&
18 | sourceProp !== null &&
19 | !(sourceProp instanceof Array)
20 | ) {
21 | target[prop] = extend(target[prop], sourceProp);
22 | } else {
23 | target[prop] = sourceProp;
24 | }
25 | }
26 | }
27 |
28 | return target;
29 | }
30 |
--------------------------------------------------------------------------------
/src/core/lang.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified.
3 | * @return Returns the passed number value with unit.
4 | */
5 | export function ensureUnit(value: T, unit: string) {
6 | if (typeof value === 'number') {
7 | return value + unit;
8 | }
9 |
10 | return value;
11 | }
12 |
13 | /**
14 | * Converts a number or string to a quantity object.
15 | * @return Returns an object containing the value as number and the unit as string.
16 | */
17 | export function quantity(input: T) {
18 | if (typeof input === 'string') {
19 | const match = /^(\d+)\s*(.*)$/g.exec(input);
20 | return {
21 | value: match ? +match[1] : 0,
22 | unit: match?.[2] || undefined
23 | };
24 | }
25 |
26 | return {
27 | value: Number(input)
28 | };
29 | }
30 |
31 | /**
32 | * Generates a-z from a number 0 to 26
33 | * @param n A number from 0 to 26 that will result in a letter a-z
34 | * @return A character from a-z based on the input number n
35 | */
36 | export function alphaNumerate(n: number) {
37 | // Limit to a-z
38 | return String.fromCharCode(97 + (n % 26));
39 | }
40 |
--------------------------------------------------------------------------------
/sandboxes/line/data-fill-holes/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, Interpolation } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
8 | series: [
9 | [5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9],
10 | [
11 | 10,
12 | 15,
13 | null,
14 | 12,
15 | null,
16 | 10,
17 | 12,
18 | 15,
19 | null,
20 | null,
21 | 12,
22 | null,
23 | 14,
24 | null,
25 | null,
26 | null
27 | ],
28 | [null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null],
29 | [
30 | { x: 3, y: 3 },
31 | { x: 4, y: 3 },
32 | { x: 5, y: undefined },
33 | { x: 6, y: 4 },
34 | { x: 7, y: null },
35 | { x: 8, y: 4 },
36 | { x: 9, y: 4 }
37 | ]
38 | ]
39 | },
40 | {
41 | fullWidth: true,
42 | chartPadding: {
43 | right: 10
44 | },
45 | lineSmooth: Interpolation.cardinal({
46 | fillHoles: true
47 | }),
48 | low: 0
49 | }
50 | );
51 |
--------------------------------------------------------------------------------
/sandboxes/line/modify-drawing/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, Svg } from 'chartist';
3 |
4 | const chart = new LineChart('#chart', {
5 | labels: [1, 2, 3, 4, 5],
6 | series: [[12, 9, 7, 8, 5]]
7 | });
8 |
9 | // Listening for draw events that get emitted by the Chartist chart
10 | chart.on('draw', data => {
11 | // If the draw event was triggered from drawing a point on the line chart
12 | if (data.type === 'point') {
13 | // We are creating a new path SVG element that draws a triangle around the point coordinates
14 | const triangle = new Svg(
15 | 'path',
16 | {
17 | d: [
18 | 'M',
19 | data.x,
20 | data.y - 15,
21 | 'L',
22 | data.x - 15,
23 | data.y + 8,
24 | 'L',
25 | data.x + 15,
26 | data.y + 8,
27 | 'z'
28 | ].join(' '),
29 | style: 'fill-opacity: 1'
30 | },
31 | 'ct-area'
32 | );
33 |
34 | // With data.element we get the Chartist SVG wrapper and we can replace the original point drawn by Chartist with our newly created triangle
35 | data.element.replace(triangle);
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/sandboxes/bar/with-circle-modify-drawing/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart, Svg, getMultiValue } from 'chartist';
3 |
4 | // Create a simple bi-polar bar chart
5 | const chart = new BarChart(
6 | '#chart',
7 | {
8 | labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'],
9 | series: [[1, 2, 4, 8, 6, -2, -1, -4, -6, -2]]
10 | },
11 | {
12 | high: 10,
13 | low: -10,
14 | axisX: {
15 | labelInterpolationFnc: (value, index) => (index % 2 === 0 ? value : null)
16 | }
17 | }
18 | );
19 |
20 | // Listen for draw events on the bar chart
21 | chart.on('draw', data => {
22 | // If this draw event is of type bar we can use the data to create additional content
23 | if (data.type === 'bar') {
24 | // We use the group element of the current series to append a simple circle with the bar peek coordinates and a circle radius that is depending on the value
25 | data.group.append(
26 | new Svg(
27 | 'circle',
28 | {
29 | cx: data.x2,
30 | cy: data.y2,
31 | r: Math.abs(Number(getMultiValue(data.value))) * 2 + 5
32 | },
33 | 'ct-slice-pie'
34 | )
35 | );
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/website/sidebars.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | const { docs } = require('./docs/docs');
4 | const { docs: api } = require('./docs/api/docs');
5 | const { docs: examples } = require('./docs/examples/docs');
6 |
7 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
8 | const sidebars = {
9 | docsSidebar: [
10 | {
11 | type: 'doc',
12 | id: 'index',
13 | label: 'Quickstart'
14 | },
15 | ...docs.map(({ slug, title }) => ({
16 | /** @type {'doc'} */
17 | type: 'doc',
18 | id: slug.replace('/docs/', ''),
19 | label: title
20 | }))
21 | ],
22 | apiSidebar: [
23 | ...api.map(({ slug, title }) => ({
24 | /** @type {'doc'} */
25 | type: 'doc',
26 | id: slug.replace('/', ''),
27 | label: title
28 | })),
29 | {
30 | type: 'doc',
31 | id: 'api/index'
32 | }
33 | ],
34 | examplesSidebar: [
35 | {
36 | type: 'doc',
37 | id: 'examples/index',
38 | label: 'Table of Contents'
39 | },
40 | ...examples.map(({ slug, title }) => ({
41 | /** @type {'doc'} */
42 | type: 'doc',
43 | id: slug.replace('/', ''),
44 | label: title
45 | }))
46 | ]
47 | };
48 |
49 | module.exports = sidebars;
50 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - main
7 | jobs:
8 | test:
9 | runs-on: ubuntu-latest
10 | strategy:
11 | matrix:
12 | stage:
13 | - unit
14 | - storyshots
15 | fail-fast: false
16 | name: ${{ matrix.stage }} tests
17 | steps:
18 | - name: Checkout the repository
19 | uses: actions/checkout@v3
20 | - name: Install pnpm
21 | uses: pnpm/action-setup@v2
22 | with:
23 | version: 7
24 | - name: Install Node.js
25 | uses: actions/setup-node@v3
26 | with:
27 | node-version: 16
28 | cache: 'pnpm'
29 | - name: Install dependencies
30 | run: pnpm install
31 | - name: Run tests
32 | run: pnpm test:${{ matrix.stage }}
33 | - name: Collect coverage
34 | uses: codecov/codecov-action@v3
35 | if: "success() && matrix.stage == 'unit'"
36 | with:
37 | files: ./coverage/lcov.info
38 | fail_ci_if_error: true
39 | - name: Collect artifacts
40 | uses: actions/upload-artifact@v3
41 | if: "failure() && matrix.stage != 'unit'"
42 | with:
43 | name: Image snapshots (${{ matrix.stage }})
44 | path: test/__image_snapshots__/
45 |
--------------------------------------------------------------------------------
/website/docs/whats-new-in-v1.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /docs/whats-new-in-v1
3 | description: What's new in Chartist v1?
4 | ---
5 |
6 | # What's new in v1?
7 |
8 | ## ESM
9 |
10 | Now Chartist is truly an ES module and exposes its API through the exports, thus making Chartist [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking).
11 |
12 | ### Migration from v0.11
13 |
14 | - Each property of Chartist object now is named export.
15 | - Chart classes were renamed.
16 | - Easing object now is named export.
17 |
18 | ```js
19 | const Chartist = require('chartist')
20 |
21 | new Chartist.Bar(/* ... */);
22 | new Chartist.Line(/* ... */);
23 | new Chartist.Pie(/* ... */);
24 | new Chartist.Svg(/* ... */);
25 | Chartist.Svg.Easing
26 | // ...
27 |
28 | // ->
29 |
30 | import { BarChart, LineChart, PieChart, Svg, easings } from 'chartist'
31 |
32 | new BarChart(/* ... */)
33 | new LineChart(/* ... */)
34 | new PieChart(/* ... */)
35 | new Svg(/* ... */)
36 | easings
37 | // ...
38 | ```
39 |
40 | ## TypeScript
41 |
42 | Chartist was rewritten and fully typed with TypeScript.
43 |
44 | ### Some of exposed types
45 |
46 | ```ts
47 | import type {
48 | BarChartData,
49 | BarChartOptions,
50 | LineChartData,
51 | LineChartOptions,
52 | PieChartData,
53 | PieChartOptions
54 | } from 'chartist'
55 | ```
56 |
--------------------------------------------------------------------------------
/sandboxes/line/timeseries/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, FixedScaleAxis } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | series: [
8 | {
9 | name: 'series-1',
10 | data: [
11 | { x: new Date(143134652600), y: 53 },
12 | { x: new Date(143234652600), y: 40 },
13 | { x: new Date(143340052600), y: 45 },
14 | { x: new Date(143366652600), y: 40 },
15 | { x: new Date(143410652600), y: 20 },
16 | { x: new Date(143508652600), y: 32 },
17 | { x: new Date(143569652600), y: 18 },
18 | { x: new Date(143579652600), y: 11 }
19 | ]
20 | },
21 | {
22 | name: 'series-2',
23 | data: [
24 | { x: new Date(143134652600), y: 53 },
25 | { x: new Date(143234652600), y: 35 },
26 | { x: new Date(143334652600), y: 30 },
27 | { x: new Date(143384652600), y: 30 },
28 | { x: new Date(143568652600), y: 10 }
29 | ]
30 | }
31 | ]
32 | },
33 | {
34 | axisX: {
35 | type: FixedScaleAxis,
36 | divisor: 5,
37 | labelInterpolationFnc: value =>
38 | new Date(value).toLocaleString(undefined, {
39 | month: 'short',
40 | day: 'numeric'
41 | })
42 | }
43 | }
44 | );
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: "🚀 Feature Request"
2 | description: "I have a specific suggestion!"
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: Thanks for taking the time to suggest a new feature! Please fill out this form as completely as possible.
8 |
9 | - type: checkboxes
10 | id: input1
11 | attributes:
12 | label: Would you like to work on this feature?
13 | options:
14 | - label: Check this if you would like to implement a PR, we are more than happy to help you go through the process.
15 |
16 | - type: textarea
17 | attributes:
18 | label: What problem are you trying to solve?
19 | description: |
20 | A concise description of what the problem is.
21 | placeholder: |
22 | I have an issue when [...]
23 | validations:
24 | required: true
25 |
26 | - type: textarea
27 | attributes:
28 | label: Describe the solution you'd like
29 | validations:
30 | required: true
31 |
32 | - type: textarea
33 | attributes:
34 | label: Describe alternatives you've considered
35 |
36 | - type: textarea
37 | attributes:
38 | label: Documentation, Adoption, Migration Strategy
39 | description: |
40 | If you can, explain how users will be able to use this and how it might be documented. Maybe a mock-up?
41 |
--------------------------------------------------------------------------------
/.github/workflows/website.yml:
--------------------------------------------------------------------------------
1 | name: Website
2 | on:
3 | push:
4 | branches:
5 | - main
6 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
7 | permissions:
8 | contents: read
9 | pages: write
10 | id-token: write
11 | # Allow one concurrent deployment
12 | concurrency:
13 | group: "pages"
14 | cancel-in-progress: true
15 | jobs:
16 | deploy:
17 | environment:
18 | name: github-pages
19 | url: ${{ steps.deployment.outputs.page_url }}
20 | runs-on: ubuntu-latest
21 | name: deploy website
22 | steps:
23 | - name: Checkout the repository
24 | uses: actions/checkout@v3
25 | - name: Install pnpm
26 | uses: pnpm/action-setup@v2
27 | with:
28 | version: 7
29 | - name: Install Node.js
30 | uses: actions/setup-node@v3
31 | with:
32 | node-version: 16
33 | cache: 'pnpm'
34 | - name: Install dependencies
35 | run: pnpm install
36 | - name: Build website
37 | run: pnpm build
38 | working-directory: ./website
39 | - name: Setup Pages
40 | uses: actions/configure-pages@v2
41 | - name: Upload artifact
42 | uses: actions/upload-pages-artifact@v1
43 | with:
44 | path: './website/build'
45 | - name: Deploy to GitHub Pages
46 | id: deployment
47 | uses: actions/deploy-pages@v1
48 |
--------------------------------------------------------------------------------
/src/axes/FixedScaleAxis.spec.ts:
--------------------------------------------------------------------------------
1 | import { FixedScaleAxis } from './FixedScaleAxis';
2 |
3 | describe('Axes', () => {
4 | describe('FixedScaleAxis', () => {
5 | it('should order the tick array', () => {
6 | const ticks = [10, 5, 0, -5, -10];
7 | const axisUnit = {
8 | pos: 'y',
9 | len: 'height',
10 | dir: 'vertical',
11 | rectStart: 'y2',
12 | rectEnd: 'y1',
13 | rectOffset: 'x1'
14 | } as const;
15 | const data = [
16 | [
17 | { x: 1, y: 10 },
18 | { x: 2, y: 5 },
19 | { x: 3, y: -5 }
20 | ]
21 | ];
22 | const chartRect: any = {
23 | padding: {
24 | top: 15,
25 | right: 15,
26 | bottom: 5,
27 | left: 10
28 | },
29 | y2: 15,
30 | y1: 141,
31 | x1: 50,
32 | x2: 269
33 | };
34 | const options = {
35 | offset: 40,
36 | position: 'start' as const,
37 | labelOffset: { x: 0, y: 0 },
38 | showLabel: true,
39 | showGrid: true,
40 | scaleMinSpace: 20,
41 | onlyInteger: false,
42 | ticks
43 | };
44 | const fsaxis: any = new FixedScaleAxis(
45 | axisUnit,
46 | data,
47 | chartRect,
48 | options
49 | );
50 | expect(fsaxis.ticks).toEqual([-10, -5, 0, 5, 10]);
51 | });
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/website/src/prism-theme.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plain: {
3 | color: '#f7f2ea',
4 | backgroundColor: '#453D3F'
5 | },
6 | styles: [
7 | {
8 | types: ['prolog', 'constant', 'builtin'],
9 | style: {
10 | color: '#F05B4F'
11 | }
12 | },
13 | {
14 | types: ['inserted', 'function'],
15 | style: {
16 | color: '#F05B4F'
17 | }
18 | },
19 | {
20 | types: ['deleted'],
21 | style: {
22 | color: 'rgb(255, 85, 85)'
23 | }
24 | },
25 | {
26 | types: ['changed'],
27 | style: {
28 | color: 'rgb(255, 184, 108)'
29 | }
30 | },
31 | {
32 | types: ['punctuation', 'symbol'],
33 | style: {
34 | color: '#f7f2ea'
35 | }
36 | },
37 | {
38 | types: ['number'],
39 | style: {
40 | color: '#F4C63D'
41 | }
42 | },
43 | {
44 | types: ['string', 'char', 'tag', 'selector'],
45 | style: {
46 | color: '#F4C63D'
47 | }
48 | },
49 | {
50 | types: ['keyword', 'variable'],
51 | style: {
52 | color: '#F05B4F',
53 | fontStyle: 'italic'
54 | }
55 | },
56 | {
57 | types: ['comment'],
58 | style: {
59 | color: '#7b6d70'
60 | }
61 | },
62 | {
63 | types: ['attr-name'],
64 | style: {
65 | color: '#F4C63D'
66 | }
67 | }
68 | ]
69 | };
70 |
--------------------------------------------------------------------------------
/src/axes/FixedScaleAxis.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | ChartRect,
3 | AxisOptions,
4 | NormalizedSeries,
5 | NormalizedSeriesPrimitiveValue
6 | } from '../core';
7 | import { getMultiValue, getHighLow } from '../core/data';
8 | import { times } from '../utils';
9 | import { AxisUnits, Axis } from './Axis';
10 |
11 | export class FixedScaleAxis extends Axis {
12 | public override readonly range: {
13 | min: number;
14 | max: number;
15 | };
16 |
17 | constructor(
18 | axisUnit: AxisUnits,
19 | data: NormalizedSeries[],
20 | chartRect: ChartRect,
21 | options: AxisOptions
22 | ) {
23 | const highLow = options.highLow || getHighLow(data, options, axisUnit.pos);
24 | const divisor = options.divisor || 1;
25 | const ticks = (
26 | options.ticks ||
27 | times(
28 | divisor,
29 | index => highLow.low + ((highLow.high - highLow.low) / divisor) * index
30 | )
31 | ).sort((a, b) => Number(a) - Number(b));
32 | const range = {
33 | min: highLow.low,
34 | max: highLow.high
35 | };
36 |
37 | super(axisUnit, chartRect, ticks);
38 |
39 | this.range = range;
40 | }
41 |
42 | projectValue(value: NormalizedSeriesPrimitiveValue) {
43 | const finalValue = Number(getMultiValue(value, this.units.pos));
44 |
45 | return (
46 | (this.axisLength * (finalValue - this.range.min)) /
47 | (this.range.max - this.range.min)
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/axes/AutoScaleAxis.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | ChartRect,
3 | AxisOptions,
4 | Bounds,
5 | NormalizedSeries,
6 | NormalizedSeriesPrimitiveValue
7 | } from '../core';
8 | import { getBounds, getHighLow, getMultiValue } from '../core';
9 | import { AxisUnits, Axis } from './Axis';
10 |
11 | export class AutoScaleAxis extends Axis {
12 | private readonly bounds: Bounds;
13 | public override readonly range: {
14 | min: number;
15 | max: number;
16 | };
17 |
18 | constructor(
19 | axisUnit: AxisUnits,
20 | data: NormalizedSeries[],
21 | chartRect: ChartRect,
22 | options: AxisOptions
23 | ) {
24 | // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options
25 | const highLow = options.highLow || getHighLow(data, options, axisUnit.pos);
26 | const bounds = getBounds(
27 | chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart],
28 | highLow,
29 | options.scaleMinSpace || 20,
30 | options.onlyInteger
31 | );
32 | const range = {
33 | min: bounds.min,
34 | max: bounds.max
35 | };
36 |
37 | super(axisUnit, chartRect, bounds.values);
38 |
39 | this.bounds = bounds;
40 | this.range = range;
41 | }
42 |
43 | projectValue(value: NormalizedSeriesPrimitiveValue) {
44 | const finalValue = Number(getMultiValue(value, this.units.pos));
45 |
46 | return (
47 | (this.axisLength * (finalValue - this.bounds.min)) / this.bounds.range
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/sandboxes/bar/extreme-responsive/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { BarChart, noop } from 'chartist';
3 |
4 | new BarChart(
5 | '#chart',
6 | {
7 | labels: ['Quarter 1', 'Quarter 2', 'Quarter 3', 'Quarter 4'],
8 | series: [
9 | [5, 4, 3, 7],
10 | [3, 2, 9, 5],
11 | [1, 5, 8, 4],
12 | [2, 3, 4, 6],
13 | [4, 1, 2, 1]
14 | ]
15 | },
16 | {
17 | // Default mobile configuration
18 | stackBars: true,
19 | axisX: {
20 | labelInterpolationFnc: value =>
21 | String(value)
22 | .split(/\s+/)
23 | .map(word => word[0])
24 | .join('')
25 | },
26 | axisY: {
27 | offset: 20
28 | }
29 | },
30 | [
31 | // Options override for media > 400px
32 | [
33 | 'screen and (min-width: 400px)',
34 | {
35 | reverseData: true,
36 | horizontalBars: true,
37 | axisX: {
38 | labelInterpolationFnc: noop
39 | },
40 | axisY: {
41 | offset: 60
42 | }
43 | }
44 | ],
45 | // Options override for media > 800px
46 | [
47 | 'screen and (min-width: 800px)',
48 | {
49 | stackBars: false,
50 | seriesBarDistance: 10
51 | }
52 | ],
53 | // Options override for media > 1000px
54 | [
55 | 'screen and (min-width: 1000px)',
56 | {
57 | reverseData: false,
58 | horizontalBars: false,
59 | seriesBarDistance: 15
60 | }
61 | ]
62 | ]
63 | );
64 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: "🐛 Bug Report"
2 | description: "If something isn't working as expected."
3 | title: "[Bug]: "
4 | labels: ["bug"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: Thanks for taking the time to file a bug report! Please fill out this form as completely as possible.
9 |
10 | - type: checkboxes
11 | id: input1
12 | attributes:
13 | label: Would you like to work on a fix?
14 | options:
15 | - label: Check this if you would like to implement a PR, we are more than happy to help you go through the process.
16 |
17 | - type: textarea
18 | attributes:
19 | label: Current and expected behavior
20 | description: A clear and concise description of what the library is doing and what you would expect.
21 | validations:
22 | required: true
23 |
24 | - type: input
25 | attributes:
26 | label: Reproduction
27 | description: |
28 | Please provide issue reproduction.
29 | You can give a link to a repository with the reproduction or make a [sandbox](https://codesandbox.io/) and reproduce the issue there.
30 | validations:
31 | required: true
32 |
33 | - type: input
34 | attributes:
35 | label: Chartist version
36 | description: Which version of Chartist are you using?
37 | placeholder: v0.0.0
38 | validations:
39 | required: true
40 |
41 | - type: textarea
42 | attributes:
43 | label: Possible solution
44 | description: If you have suggestions on a fix for the bug.
45 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-responsive/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, LineChartOptions, ResponsiveOptions } from 'chartist';
3 |
4 | /* Add a basic data series with six labels and values */
5 | const data = {
6 | labels: ['1', '2', '3', '4', '5', '6'],
7 | series: [
8 | {
9 | data: [1, 2, 3, 5, 8, 13]
10 | }
11 | ]
12 | };
13 |
14 | /* Set some base options (settings will override the default settings in js *see default settings*). We are adding a basic label interpolation function for the xAxis labels. */
15 | const options: LineChartOptions = {
16 | axisX: {
17 | labelInterpolationFnc: value => 'Calendar Week ' + value
18 | }
19 | };
20 |
21 | /* Now we can specify multiple responsive settings that will override the base settings based on order and if the media queries match. In this example we are changing the visibility of dots and lines as well as use different label interpolations for space reasons. */
22 | const responsiveOptions: ResponsiveOptions = [
23 | [
24 | 'screen and (min-width: 641px) and (max-width: 1024px)',
25 | {
26 | showPoint: false,
27 | axisX: {
28 | labelInterpolationFnc: value => 'Week ' + value
29 | }
30 | }
31 | ],
32 | [
33 | 'screen and (max-width: 640px)',
34 | {
35 | showLine: false,
36 | axisX: {
37 | labelInterpolationFnc: value => 'W' + value
38 | }
39 | }
40 | ]
41 | ];
42 |
43 | /* Initialize the chart with the above settings */
44 | new LineChart('#chart', data, options, responsiveOptions);
45 |
--------------------------------------------------------------------------------
/src/interpolation/none.ts:
--------------------------------------------------------------------------------
1 | import type { SegmentData } from '../core';
2 | import { getMultiValue } from '../core';
3 | import { SvgPath } from '../svg';
4 |
5 | export interface NoneInterpolationOptions {
6 | fillHoles?: boolean;
7 | }
8 |
9 | /**
10 | * This interpolation function does not smooth the path and the result is only containing lines and no curves.
11 | *
12 | * @example
13 | * ```ts
14 | * const chart = new LineChart('.ct-chart', {
15 | * labels: [1, 2, 3, 4, 5],
16 | * series: [[1, 2, 8, 1, 7]]
17 | * }, {
18 | * lineSmooth: Interpolation.none({
19 | * fillHoles: false
20 | * })
21 | * });
22 | * ```
23 | */
24 | export function none(options?: NoneInterpolationOptions) {
25 | const finalOptions = {
26 | fillHoles: false,
27 | ...options
28 | };
29 |
30 | return function noneInterpolation(
31 | pathCoordinates: number[],
32 | valueData: SegmentData[]
33 | ) {
34 | const path = new SvgPath();
35 | let hole = true;
36 |
37 | for (let i = 0; i < pathCoordinates.length; i += 2) {
38 | const currX = pathCoordinates[i];
39 | const currY = pathCoordinates[i + 1];
40 | const currData = valueData[i / 2];
41 |
42 | if (getMultiValue(currData.value) !== undefined) {
43 | if (hole) {
44 | path.move(currX, currY, false, currData);
45 | } else {
46 | path.line(currX, currY, false, currData);
47 | }
48 |
49 | hole = false;
50 | } else if (!finalOptions.fillHoles) {
51 | hole = true;
52 | }
53 | }
54 |
55 | return path;
56 | };
57 | }
58 |
--------------------------------------------------------------------------------
/scripts/styles.cjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs').promises;
4 | const path = require('path');
5 | const sass = require('sass');
6 | const postcss = require('postcss');
7 |
8 | const { plugins } = require('../postcss.config.cjs');
9 | const pkg = require('../package.json');
10 |
11 | const cwd = process.cwd();
12 | const input = process.argv[2];
13 | const output = pkg.style;
14 | const sourceMapOutput = output.replace('.css', '.css.map');
15 |
16 | async function compile() {
17 | let styles;
18 |
19 | styles = sass.compile(input, {
20 | sourceMap: true
21 | });
22 |
23 | styles.sourceMap.sources = styles.sourceMap.sources.map(_ =>
24 | _.replace(cwd, '')
25 | );
26 |
27 | styles = await postcss(plugins).process(styles.css, {
28 | from: input,
29 | to: output,
30 | map: {
31 | prev: styles.sourceMap
32 | }
33 | });
34 |
35 | const map = styles.map.toString();
36 | const css =
37 | styles.css + `\n/*# sourceMappingURL=${path.basename(sourceMapOutput)} */`;
38 |
39 | await fs.mkdir(path.dirname(output), {
40 | recursive: true
41 | });
42 | await Promise.all([
43 | fs.writeFile(output, css),
44 | fs.writeFile(sourceMapOutput, map)
45 | ]);
46 | }
47 |
48 | async function copySrc() {
49 | const srcDir = path.dirname(input);
50 | const distDir = path.dirname(output);
51 | const srcFiles = await fs.readdir(srcDir);
52 |
53 | await Promise.all(
54 | srcFiles.map(file =>
55 | fs.copyFile(path.join(srcDir, file), path.join(distDir, file))
56 | )
57 | );
58 | }
59 |
60 | Promise.all([compile(), copySrc()]);
61 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import swc from 'rollup-plugin-swc';
2 | import { nodeResolve } from '@rollup/plugin-node-resolve';
3 | import { terser } from 'rollup-plugin-terser';
4 | import pkg from './package.json';
5 |
6 | const extensions = ['.js', '.ts', '.tsx'];
7 | const external = _ => /node_modules/.test(_) && !/@swc\/helpers/.test(_);
8 | const plugins = (targets, minify) =>
9 | [
10 | nodeResolve({
11 | extensions
12 | }),
13 | swc({
14 | jsc: {
15 | parser: {
16 | syntax: 'typescript'
17 | },
18 | externalHelpers: true
19 | },
20 | env: {
21 | targets
22 | },
23 | module: {
24 | type: 'es6'
25 | },
26 | sourceMaps: true
27 | }),
28 | minify && terser()
29 | ].filter(Boolean);
30 |
31 | export default [
32 | {
33 | input: pkg.main,
34 | plugins: plugins('defaults, not ie 11, not ie_mob 11'),
35 | external,
36 | output: {
37 | file: pkg.publishConfig.main,
38 | format: 'cjs',
39 | exports: 'named',
40 | sourcemap: true
41 | }
42 | },
43 | {
44 | input: pkg.main,
45 | plugins: plugins('defaults, not ie 11, not ie_mob 11', true),
46 | external: () => false,
47 | output: {
48 | file: pkg.unpkg,
49 | format: 'umd',
50 | name: 'Chartist',
51 | exports: 'named',
52 | sourcemap: true
53 | }
54 | },
55 | {
56 | input: pkg.main,
57 | plugins: plugins('defaults and supports es6-module'),
58 | external,
59 | output: {
60 | file: pkg.publishConfig.module,
61 | format: 'es',
62 | sourcemap: true
63 | }
64 | }
65 | ];
66 |
--------------------------------------------------------------------------------
/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "website",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids",
15 | "typecheck": "tsc"
16 | },
17 | "dependencies": {
18 | "@algolia/client-search": "^4.11.0",
19 | "@docusaurus/core": "2.0.0-beta.14",
20 | "@docusaurus/preset-classic": "2.0.0-beta.14",
21 | "@docusaurus/theme-search-algolia": "^2.0.0-beta.9",
22 | "@mdx-js/react": "^1.6.21",
23 | "@svgr/webpack": "^6.0.0",
24 | "clsx": "^1.1.1",
25 | "file-loader": "^6.2.0",
26 | "git-branch": "^2.0.1",
27 | "prism-react-renderer": "^1.2.1",
28 | "react": "^17.0.1",
29 | "react-dom": "^17.0.1",
30 | "url-loader": "^4.1.1"
31 | },
32 | "devDependencies": {
33 | "@docusaurus/module-type-aliases": "2.0.0-beta.14",
34 | "@tsconfig/docusaurus": "^1.0.4",
35 | "@types/react": "^17.0.36",
36 | "docusaurus-plugin-typedoc": "^0.17.4",
37 | "typedoc": "^0.23.0",
38 | "typedoc-plugin-markdown": "^3.12.1",
39 | "typescript": "^4.3.5",
40 | "webpack": "^5.64.2"
41 | },
42 | "browserslist": {
43 | "production": [
44 | ">0.5%",
45 | "not dead",
46 | "not op_mini all"
47 | ],
48 | "development": [
49 | "last 1 chrome version",
50 | "last 1 firefox version",
51 | "last 1 safari version"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/svg/types.ts:
--------------------------------------------------------------------------------
1 | import type { SegmentData } from '../core';
2 | import type { easings } from './animation';
3 | import type { Svg } from './Svg';
4 |
5 | export interface BasePathParams {
6 | x: number;
7 | y: number;
8 | }
9 |
10 | export type MoveParams = BasePathParams;
11 |
12 | export type LineParams = BasePathParams;
13 |
14 | export interface CurveParams extends BasePathParams {
15 | x1: number;
16 | y1: number;
17 | x2: number;
18 | y2: number;
19 | }
20 |
21 | export interface ArcParams extends BasePathParams {
22 | rx: number;
23 | ry: number;
24 | xAr: number;
25 | lAf: number;
26 | sf: number;
27 | }
28 |
29 | export type PathParams = MoveParams | LineParams | CurveParams | ArcParams;
30 |
31 | export type PathCommand = {
32 | command: string;
33 | data?: SegmentData;
34 | } & T;
35 |
36 | export interface SvgPathOptions {
37 | accuracy?: number;
38 | }
39 |
40 | export type Attributes = Record;
41 |
42 | export interface AnimationDefinition {
43 | id?: string;
44 | easing?: number[] | keyof typeof easings;
45 | calcMode?: 'discrete' | 'linear' | 'paced' | 'spline';
46 | restart?: 'always' | 'whenNotActive' | 'never';
47 | repeatCount?: number | 'indefinite';
48 | repeatDur?: string | 'indefinite';
49 | keySplines?: string;
50 | keyTimes?: string;
51 | fill?: string;
52 | min?: number | string;
53 | max?: number | string;
54 | begin?: number | string;
55 | end?: number | string;
56 | dur: number | string;
57 | from: number | string;
58 | to: number | string;
59 | }
60 |
61 | export interface AnimationEvent {
62 | element: Svg;
63 | animate: Element;
64 | params: AnimationDefinition;
65 | }
66 |
--------------------------------------------------------------------------------
/src/utils/functional.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Helps to simplify functional style code
3 | * @param n This exact value will be returned by the noop function
4 | * @return The same value that was provided to the n parameter
5 | */
6 | export const noop = (n: T) => n;
7 |
8 | /**
9 | * Functional style helper to produce array with given length initialized with undefined values
10 | */
11 | export function times(length: number): undefined[];
12 | export function times(
13 | length: number,
14 | filler: (index: number) => T
15 | ): T[];
16 | export function times(
17 | length: number,
18 | filler?: (index: number) => T
19 | ) {
20 | return Array.from({ length }, filler ? (_, i) => filler(i) : () => void 0);
21 | }
22 |
23 | /**
24 | * Sum helper to be used in reduce functions
25 | */
26 | export const sum = (previous: number, current: number) =>
27 | previous + (current ? current : 0);
28 |
29 | /**
30 | * Map for multi dimensional arrays where their nested arrays will be mapped in serial. The output array will have the length of the largest nested array. The callback function is called with variable arguments where each argument is the nested array value (or undefined if there are no more values).
31 | *
32 | * For example:
33 | * @example
34 | * ```ts
35 | * const data = [[1, 2], [3], []];
36 | * serialMap(data, cb);
37 | *
38 | * // where cb will be called 2 times
39 | * // 1. call arguments: (1, 3, undefined)
40 | * // 2. call arguments: (2, undefined, undefined)
41 | * ```
42 | */
43 | export const serialMap = (array: T[][], callback: (...args: T[]) => K) =>
44 | times(Math.max(...array.map(element => element.length)), index =>
45 | callback(...array.map(element => element[index]))
46 | );
47 |
--------------------------------------------------------------------------------
/sandboxes/line/series-override/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, Interpolation } from 'chartist';
3 |
4 | new LineChart(
5 | '#chart',
6 | {
7 | labels: ['1', '2', '3', '4', '5', '6', '7', '8'],
8 | // Naming the series with the series object array notation
9 | series: [
10 | {
11 | name: 'series-1',
12 | data: [5, 2, -4, 2, 0, -2, 5, -3]
13 | },
14 | {
15 | name: 'series-2',
16 | data: [4, 3, 5, 3, 1, 3, 6, 4]
17 | },
18 | {
19 | name: 'series-3',
20 | data: [2, 4, 3, 1, 4, 5, 3, 2]
21 | }
22 | ]
23 | },
24 | {
25 | fullWidth: true,
26 | // Within the series options you can use the series names
27 | // to specify configuration that will only be used for the
28 | // specific series.
29 | series: {
30 | 'series-1': {
31 | lineSmooth: Interpolation.step()
32 | },
33 | 'series-2': {
34 | lineSmooth: Interpolation.simple(),
35 | showArea: true
36 | },
37 | 'series-3': {
38 | showPoint: false
39 | }
40 | }
41 | },
42 | [
43 | // You can even use responsive configuration overrides to
44 | // customize your series configuration even further!
45 | [
46 | 'screen and (max-width: 320px)',
47 | {
48 | series: {
49 | 'series-1': {
50 | lineSmooth: Interpolation.none()
51 | },
52 | 'series-2': {
53 | lineSmooth: Interpolation.none(),
54 | showArea: false
55 | },
56 | 'series-3': {
57 | lineSmooth: Interpolation.none(),
58 | showPoint: true
59 | }
60 | }
61 | }
62 | ]
63 | ]
64 | );
65 |
--------------------------------------------------------------------------------
/src/core/data/serialize.spec.ts:
--------------------------------------------------------------------------------
1 | import { serialize, deserialize } from './serialize';
2 |
3 | describe('Core', () => {
4 | describe('Data', () => {
5 | describe('Serialize', () => {
6 | it('should serialize and deserialize regular strings', () => {
7 | const input = 'String test';
8 | expect(input).toMatch(deserialize(serialize(input)));
9 | });
10 |
11 | it('should serialize and deserialize strings with critical characters', () => {
12 | const input = 'String test with critical characters " < > \' & &';
13 | expect(input).toMatch(deserialize(serialize(input)));
14 | });
15 |
16 | it('should serialize and deserialize numbers', () => {
17 | const input = 12345.6789;
18 | expect(input).toEqual(deserialize(serialize(input)));
19 | });
20 |
21 | it('should serialize and deserialize dates', () => {
22 | const input = new Date(0);
23 | expect(+input).toEqual(+new Date(deserialize(serialize(input))));
24 | });
25 |
26 | it('should serialize and deserialize complex object types', () => {
27 | const input = {
28 | a: {
29 | b: 100,
30 | c: 'String test',
31 | d: 'String test with critical characters " < > \' & &',
32 | e: {
33 | f: 'String test'
34 | }
35 | }
36 | };
37 |
38 | expect(input).toEqual(deserialize(serialize(input)));
39 | });
40 |
41 | it('should serialize and deserialize null, undefined and NaN', () => {
42 | expect(null).toEqual(deserialize(serialize(null)));
43 | expect(undefined).toEqual(deserialize(serialize(undefined)));
44 | expect(deserialize(serialize(NaN))).toBeNaN();
45 | });
46 | });
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["eslint:recommended", "plugin:prettier/recommended"],
3 | "parser": "@babel/eslint-parser",
4 | "parserOptions": {
5 | "ecmaVersion": "latest",
6 | "requireConfigFile": false
7 | },
8 | "env": {
9 | "es6": true,
10 | "browser": true,
11 | "node": true
12 | },
13 | "rules": {
14 | "no-console": 2,
15 | "curly": 2,
16 | "dot-notation": 1,
17 | "eqeqeq": 2,
18 | "no-alert": 2,
19 | "no-caller": 2,
20 | "no-eval": 2,
21 | "no-extra-bind": 2,
22 | "no-implied-eval": 2,
23 | "no-multi-spaces": 2,
24 | "no-with": 2,
25 | "no-shadow": 2,
26 | "no-shadow-restricted-names": 2,
27 | "brace-style": ["error", "1tbs"],
28 | "camelcase": 2,
29 | "comma-style": ["error", "last"],
30 | "eol-last": 2,
31 | "key-spacing": 2,
32 | "new-cap": 1,
33 | "no-array-constructor": 2,
34 | "no-mixed-spaces-and-tabs": 2,
35 | "no-multiple-empty-lines": 2,
36 | "semi-spacing": 2,
37 | "no-spaced-func": 2,
38 | "no-trailing-spaces": 2,
39 | "space-before-blocks": 2,
40 | "spaced-comment": 1,
41 | "no-var": 2
42 | },
43 | "overrides": [
44 | {
45 | "files": ["**/*.ts"],
46 | "parser": "@typescript-eslint/parser",
47 | "plugins": ["@typescript-eslint"],
48 | "extends": ["plugin:@typescript-eslint/recommended"]
49 | },
50 | {
51 | "files": ["test/**/*.{js,ts}", "*.spec.{js,ts}", "*.stories.{js,ts}"],
52 | "plugins": [
53 | "jest",
54 | "testing-library",
55 | "jest-dom"
56 | ],
57 | "extends": ["plugin:jest-dom/recommended"],
58 | "env": {
59 | "jest/globals": true
60 | },
61 | "rules": {
62 | "no-console": 0,
63 | "no-shadow": 0,
64 | "@typescript-eslint/no-explicit-any": 0
65 | }
66 | }
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/test/mock/dom.ts:
--------------------------------------------------------------------------------
1 | export type Fixture = ReturnType;
2 |
3 | export let container: HTMLDivElement | null = null;
4 |
5 | const getBoundingClientRect = SVGElement.prototype.getBoundingClientRect;
6 |
7 | export function mockDom() {
8 | if (!container) {
9 | container = document.createElement('div');
10 | container.setAttribute('data-fixture-container', `${+new Date()}`);
11 | document.body.appendChild(container);
12 | }
13 | }
14 |
15 | export function destroyMockDom() {
16 | if (container) {
17 | document.body.removeChild(container);
18 | container = null;
19 | }
20 | }
21 |
22 | export function addMockWrapper(fixture: string) {
23 | const wrapper = document.createElement('div');
24 | wrapper.innerHTML += fixture;
25 | container?.appendChild(wrapper);
26 | return {
27 | wrapper,
28 | container,
29 | fixture
30 | };
31 | }
32 |
33 | export function mockDomRects() {
34 | // @ts-expect-error Mock DOM API.
35 | SVGElement.prototype.getBoundingClientRect = () => ({
36 | x: 0,
37 | y: 0,
38 | width: 500,
39 | height: 500,
40 | top: 0,
41 | right: 0,
42 | bottom: 0,
43 | left: 0
44 | });
45 |
46 | Object.defineProperties(SVGElement.prototype, {
47 | clientWidth: {
48 | configurable: true,
49 | get: () => 500
50 | },
51 | clientHeight: {
52 | configurable: true,
53 | get: () => 500
54 | }
55 | });
56 | }
57 |
58 | export function destroyMockDomRects() {
59 | SVGElement.prototype.getBoundingClientRect = getBoundingClientRect;
60 |
61 | // Redefine clientWidth and clientHeight properties from the prototype of SVGElement
62 | const ElementPrototype = Object.getPrototypeOf(SVGElement.prototype);
63 | Object.defineProperties(SVGElement.prototype, {
64 | clientWidth: Object.getOwnPropertyDescriptor(
65 | ElementPrototype,
66 | 'clientWidth'
67 | )!,
68 | clientHeight: Object.getOwnPropertyDescriptor(
69 | ElementPrototype,
70 | 'clientHeight'
71 | )!
72 | });
73 | }
74 |
--------------------------------------------------------------------------------
/sandboxes/line/simple-svg-animation/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { LineChart, easings } from 'chartist';
3 |
4 | const chart = new LineChart(
5 | '#chart',
6 | {
7 | labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
8 | series: [
9 | [12, 4, 2, 8, 5, 4, 6, 2, 3, 3, 4, 6],
10 | [4, 8, 9, 3, 7, 2, 10, 5, 8, 1, 7, 10]
11 | ]
12 | },
13 | {
14 | low: 0,
15 | showLine: false,
16 | axisX: {
17 | showLabel: false,
18 | offset: 0
19 | },
20 | axisY: {
21 | showLabel: false,
22 | offset: 0
23 | }
24 | }
25 | );
26 |
27 | // Let's put a sequence number aside so we can use it in the event callbacks
28 | let seq = 0;
29 |
30 | // Once the chart is fully created we reset the sequence
31 | chart.on('created', () => {
32 | seq = 0;
33 | });
34 |
35 | // On each drawn element by Chartist we use the Svg API to trigger SMIL animations
36 | chart.on('draw', data => {
37 | if (data.type === 'point') {
38 | // If the drawn element is a line we do a simple opacity fade in. This could also be achieved using CSS3 animations.
39 | data.element.animate({
40 | opacity: {
41 | // The delay when we like to start the animation
42 | begin: seq++ * 80,
43 | // Duration of the animation
44 | dur: 500,
45 | // The value where the animation should start
46 | from: 0,
47 | // The value where it should end
48 | to: 1
49 | },
50 | x1: {
51 | begin: seq++ * 80,
52 | dur: 500,
53 | from: data.x - 100,
54 | to: data.x,
55 | // You can specify an easing function name or use easing functions from `easings` directly
56 | easing: easings.easeOutQuart
57 | }
58 | });
59 | }
60 | });
61 |
62 | let timerId: any;
63 |
64 | // For the sake of the example we update the chart every time it's created with a delay of 8 seconds
65 | chart.on('created', () => {
66 | if (timerId) {
67 | clearTimeout(timerId);
68 | }
69 |
70 | timerId = setTimeout(chart.update.bind(chart), 8000);
71 | });
72 |
--------------------------------------------------------------------------------
/.github/workflows/checks.yml:
--------------------------------------------------------------------------------
1 | name: Checks
2 | on:
3 | pull_request:
4 | branches:
5 | - main
6 | jobs:
7 | size:
8 | runs-on: ubuntu-latest
9 | name: size-limit
10 | steps:
11 | - name: Checkout the repository
12 | uses: actions/checkout@v3
13 | - name: Install pnpm
14 | uses: pnpm/action-setup@v2
15 | with:
16 | version: 7
17 | - name: Install Node.js
18 | uses: actions/setup-node@v3
19 | with:
20 | node-version: 16
21 | cache: 'pnpm'
22 | - name: Check size
23 | uses: andresz1/size-limit-action@master
24 | with:
25 | github_token: ${{ secrets.GITHUB_TOKEN }}
26 | storybook:
27 | runs-on: ubuntu-latest
28 | name: storybook
29 | steps:
30 | - name: Checkout the repository
31 | uses: actions/checkout@v3
32 | - name: Install pnpm
33 | uses: pnpm/action-setup@v2
34 | with:
35 | version: 7
36 | - name: Install Node.js
37 | uses: actions/setup-node@v3
38 | with:
39 | node-version: 16
40 | cache: 'pnpm'
41 | - name: Install dependencies
42 | run: pnpm install
43 | - name: Check storybook
44 | run: pnpm build:storybook
45 | editorconfig:
46 | runs-on: ubuntu-latest
47 | name: editorconfig
48 | steps:
49 | - name: Checkout the repository
50 | uses: actions/checkout@v3
51 | - name: Check editorconfig
52 | uses: editorconfig-checker/action-editorconfig-checker@v1
53 | website:
54 | runs-on: ubuntu-latest
55 | name: website
56 | steps:
57 | - name: Checkout the repository
58 | uses: actions/checkout@v3
59 | - name: Install pnpm
60 | uses: pnpm/action-setup@v2
61 | with:
62 | version: 7
63 | - name: Install Node.js
64 | uses: actions/setup-node@v3
65 | with:
66 | node-version: 16
67 | cache: 'pnpm'
68 | - name: Install dependencies
69 | run: pnpm install
70 | - name: Check website
71 | run: pnpm build
72 | working-directory: ./website
73 |
--------------------------------------------------------------------------------
/src/core/data/data.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | Multi,
3 | AxisName,
4 | FlatSeriesValue,
5 | Series,
6 | SeriesObject
7 | } from '../types';
8 | import { safeHasProperty, getNumberOrUndefined } from '../../utils';
9 |
10 | /**
11 | * Get meta data of a specific value in a series.
12 | */
13 | export function getMetaData(
14 | seriesData: FlatSeriesValue | Series | SeriesObject,
15 | index: number
16 | ) {
17 | const value = Array.isArray(seriesData)
18 | ? seriesData[index]
19 | : safeHasProperty(seriesData, 'data')
20 | ? seriesData.data[index]
21 | : null;
22 | return safeHasProperty(value, 'meta') ? value.meta : undefined;
23 | }
24 |
25 | /**
26 | * Checks if a value is considered a hole in the data series.
27 | * @returns True if the value is considered a data hole
28 | */
29 | export function isDataHoleValue(value: unknown): value is null | undefined;
30 | export function isDataHoleValue(value: unknown) {
31 | return (
32 | value === null ||
33 | value === undefined ||
34 | (typeof value === 'number' && isNaN(value))
35 | );
36 | }
37 |
38 | /**
39 | * Checks if value is array of series objects.
40 | */
41 | export function isArrayOfSeries(
42 | value: unknown
43 | ): value is (Series | SeriesObject)[] {
44 | return (
45 | Array.isArray(value) &&
46 | value.every(_ => Array.isArray(_) || safeHasProperty(_, 'data'))
47 | );
48 | }
49 |
50 | /**
51 | * Checks if provided value object is multi value (contains x or y properties)
52 | */
53 | export function isMultiValue(value: unknown): value is Multi {
54 | return (
55 | typeof value === 'object' &&
56 | value !== null &&
57 | (Reflect.has(value, 'x') || Reflect.has(value, 'y'))
58 | );
59 | }
60 |
61 | /**
62 | * Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`.
63 | */
64 | export function getMultiValue(
65 | value: Multi | number | unknown,
66 | dimension: AxisName = 'y'
67 | ) {
68 | if (isMultiValue(value) && safeHasProperty(value, dimension)) {
69 | return getNumberOrUndefined(value[dimension]);
70 | } else {
71 | return getNumberOrUndefined(value);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/sandboxes/pie/donut-animation/index.ts:
--------------------------------------------------------------------------------
1 | import 'chartist/dist/index.css';
2 | import { PieChart, easings, AnimationDefinition } from 'chartist';
3 |
4 | const chart = new PieChart(
5 | '#chart',
6 | {
7 | series: [10, 20, 50, 20, 5, 50, 15],
8 | labels: [1, 2, 3, 4, 5, 6, 7]
9 | },
10 | {
11 | donut: true,
12 | showLabel: false
13 | }
14 | );
15 |
16 | chart.on('draw', data => {
17 | if (data.type === 'slice') {
18 | // Get the total path length in order to use for dash array animation
19 | const pathLength = data.element
20 | .getNode()
21 | .getTotalLength();
22 |
23 | // Set a dasharray that matches the path length as prerequisite to animate dashoffset
24 | data.element.attr({
25 | 'stroke-dasharray': pathLength + 'px ' + pathLength + 'px'
26 | });
27 |
28 | // Create animation definition while also assigning an ID to the animation for later sync usage
29 | const animationDefinition: Record = {
30 | 'stroke-dashoffset': {
31 | id: 'anim' + data.index,
32 | dur: 1000,
33 | from: -pathLength + 'px',
34 | to: '0px',
35 | easing: easings.easeOutQuint,
36 | // We need to use `fill: 'freeze'` otherwise our animation will fall back to initial (not visible)
37 | fill: 'freeze'
38 | }
39 | };
40 |
41 | // If this was not the first slice, we need to time the animation so that it uses the end sync event of the previous animation
42 | if (data.index !== 0) {
43 | animationDefinition['stroke-dashoffset'].begin =
44 | 'anim' + (data.index - 1) + '.end';
45 | }
46 |
47 | // We need to set an initial value before the animation starts as we are not in guided mode which would do that for us
48 | data.element.attr({
49 | 'stroke-dashoffset': -pathLength + 'px'
50 | });
51 |
52 | // We can't use guided mode as the animations need to rely on setting begin manually
53 | data.element.animate(animationDefinition, false);
54 | }
55 | });
56 |
57 | let timerId: any;
58 |
59 | // For the sake of the example we update the chart every time it's created with a delay of 8 seconds
60 | chart.on('created', () => {
61 | if (timerId) {
62 | clearTimeout(timerId);
63 | }
64 |
65 | timerId = setTimeout(chart.update.bind(chart), 10000);
66 | });
67 |
--------------------------------------------------------------------------------
/test/utils/storyshots/storybook.js:
--------------------------------------------------------------------------------
1 | import { spawn } from 'child_process';
2 |
3 | import { createServer } from 'http-server';
4 | import del from 'del';
5 |
6 | const STORYBOOK_STATIC = 'storybook-static';
7 | const errorMatcher = /ERR!|Error:|ERROR in|UnhandledPromiseRejectionWarning/;
8 |
9 | /**
10 | * Run storybook static build.
11 | * @param options - Build options.
12 | * @param [options.env] - Environment variables.
13 | * @param [options.verbose] - Print verbose messages.
14 | * @returns Build process promise.
15 | */
16 | export async function buildStorybook({ env = {}, verbose = false }) {
17 | return new Promise((resolve, reject) => {
18 | const buildProcess = spawn('build-storybook', [], {
19 | cwd: process.cwd(),
20 | env: {
21 | ...process.env,
22 | NODE_ENV: 'production',
23 | ...env
24 | },
25 | detached: true
26 | });
27 | const onData = data => {
28 | const message = data.toString('utf8');
29 |
30 | if (verbose) {
31 | process.stdout.write(message);
32 | }
33 |
34 | if (errorMatcher.test(message)) {
35 | reject(new Error(message));
36 | }
37 | };
38 |
39 | buildProcess.on('exit', (code, signal) => {
40 | if (code === 0) {
41 | resolve();
42 | return;
43 | }
44 |
45 | reject(new Error(`Exit code: ${code || signal || 'unknown'}`));
46 | });
47 | buildProcess.stdout.on('data', onData);
48 | buildProcess.stderr.on('data', onData);
49 | });
50 | }
51 |
52 | /**
53 | * Build static and start storybook server.
54 | * @param options - Storybook build and start options.
55 | * @returns Server controls.
56 | */
57 | export function startStorybook(options) {
58 | const { url, skipBuild } = options;
59 | const parsedUrl = new URL(url);
60 | const server = createServer({
61 | root: STORYBOOK_STATIC
62 | });
63 |
64 | return {
65 | async start() {
66 | if (!skipBuild) {
67 | await buildStorybook(options);
68 | }
69 |
70 | await new Promise(resolve => {
71 | server.listen(
72 | parseInt(parsedUrl.port, 10),
73 | parsedUrl.hostname,
74 | resolve
75 | );
76 | });
77 | },
78 | async stop() {
79 | server.close();
80 |
81 | if (!skipBuild) {
82 | await del(STORYBOOK_STATIC);
83 | }
84 | }
85 | };
86 | }
87 |
--------------------------------------------------------------------------------
/src/utils/utils.ts:
--------------------------------------------------------------------------------
1 | import type { FilterByKey } from './types';
2 |
3 | /**
4 | * This function safely checks if an objects has an owned property.
5 | * @param target The object where to check for a property
6 | * @param property The property name
7 | * @returns Returns true if the object owns the specified property
8 | */
9 | export function safeHasProperty(
10 | target: T,
11 | property: K
12 | ): target is FilterByKey;
13 | export function safeHasProperty(target: unknown, property: string) {
14 | return (
15 | target !== null &&
16 | typeof target === 'object' &&
17 | Reflect.has(target, property)
18 | );
19 | }
20 |
21 | /**
22 | * Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite.
23 | */
24 | export function isNumeric(value: number): true;
25 | export function isNumeric(value: unknown): boolean;
26 | export function isNumeric(value: unknown) {
27 | return value !== null && isFinite(value as number);
28 | }
29 |
30 | /**
31 | * Returns true on all falsey values except the numeric value 0.
32 | */
33 | export function isFalseyButZero(
34 | value: unknown
35 | ): value is undefined | null | false | '' {
36 | return !value && value !== 0;
37 | }
38 |
39 | /**
40 | * Returns a number if the passed parameter is a valid number or the function will return undefined. On all other values than a valid number, this function will return undefined.
41 | */
42 | export function getNumberOrUndefined(value: number): number;
43 | export function getNumberOrUndefined(value: unknown): number | undefined;
44 | export function getNumberOrUndefined(value: unknown) {
45 | return isNumeric(value) ? Number(value) : undefined;
46 | }
47 |
48 | /**
49 | * Checks if value is array of arrays or not.
50 | */
51 | export function isArrayOfArrays(data: unknown): data is unknown[][] {
52 | if (!Array.isArray(data)) {
53 | return false;
54 | }
55 |
56 | return data.every(Array.isArray);
57 | }
58 |
59 | /**
60 | * Loop over array.
61 | */
62 | export function each(
63 | list: T[],
64 | callback: (item: T, index: number, itemIndex: number) => void,
65 | reverse = false
66 | ) {
67 | let index = 0;
68 |
69 | list[reverse ? 'reduceRight' : 'reduce'](
70 | (_, item, itemIndex) => callback(item, index++, itemIndex),
71 | void 0
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/src/core/optionsProvider.ts:
--------------------------------------------------------------------------------
1 | import type { EventEmitter } from '../event';
2 | import type { OptionsChangedEvent, ResponsiveOptions } from './types';
3 | import { extend } from '../utils';
4 |
5 | export interface OptionsProvider {
6 | removeMediaQueryListeners(): void;
7 | getCurrentOptions(): T;
8 | }
9 |
10 | /**
11 | * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches
12 | * @param options Options set by user
13 | * @param responsiveOptions Optional functions to add responsive behavior to chart
14 | * @param eventEmitter The event emitter that will be used to emit the options changed events
15 | * @return The consolidated options object from the defaults, base and matching responsive options
16 | */
17 | export function optionsProvider(
18 | options: T,
19 | responsiveOptions: ResponsiveOptions | undefined,
20 | eventEmitter: EventEmitter
21 | ): OptionsProvider {
22 | let currentOptions: T;
23 | const mediaQueryListeners: MediaQueryList[] = [];
24 |
25 | function updateCurrentOptions(mediaEvent?: Event) {
26 | const previousOptions = currentOptions;
27 | currentOptions = extend({}, options);
28 |
29 | if (responsiveOptions) {
30 | responsiveOptions.forEach(responsiveOption => {
31 | const mql = window.matchMedia(responsiveOption[0]);
32 | if (mql.matches) {
33 | currentOptions = extend(currentOptions, responsiveOption[1]);
34 | }
35 | });
36 | }
37 |
38 | if (eventEmitter && mediaEvent) {
39 | eventEmitter.emit>('optionsChanged', {
40 | previousOptions,
41 | currentOptions
42 | });
43 | }
44 | }
45 |
46 | function removeMediaQueryListeners() {
47 | mediaQueryListeners.forEach(mql =>
48 | mql.removeEventListener('change', updateCurrentOptions)
49 | );
50 | }
51 |
52 | if (!window.matchMedia) {
53 | throw new Error(
54 | "window.matchMedia not found! Make sure you're using a polyfill."
55 | );
56 | } else if (responsiveOptions) {
57 | responsiveOptions.forEach(responsiveOption => {
58 | const mql = window.matchMedia(responsiveOption[0]);
59 | mql.addEventListener('change', updateCurrentOptions);
60 | mediaQueryListeners.push(mql);
61 | });
62 | }
63 | // Execute initially without an event argument so we get the correct options
64 | updateCurrentOptions();
65 |
66 | return {
67 | removeMediaQueryListeners,
68 | getCurrentOptions() {
69 | return currentOptions;
70 | }
71 | };
72 | }
73 |
--------------------------------------------------------------------------------
/src/core/data/serialize.ts:
--------------------------------------------------------------------------------
1 | import { escapingMap } from '../constants';
2 |
3 | /**
4 | * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap.
5 | * If called with null or undefined the function will return immediately with null or undefined.
6 | */
7 | export function serialize(data: number | string | object): string;
8 | export function serialize(
9 | data: number | string | object | null | undefined | unknown
10 | ): string | null | undefined;
11 | export function serialize(
12 | data: number | string | object | null | undefined | unknown
13 | ) {
14 | let serialized = '';
15 |
16 | if (data === null || data === undefined) {
17 | return data;
18 | } else if (typeof data === 'number') {
19 | serialized = '' + data;
20 | } else if (typeof data === 'object') {
21 | serialized = JSON.stringify({ data: data });
22 | } else {
23 | serialized = String(data);
24 | }
25 |
26 | return Object.keys(escapingMap).reduce(
27 | (result, key) => result.replaceAll(key, escapingMap[key]),
28 | serialized
29 | );
30 | }
31 |
32 | /**
33 | * This function de-serializes a string previously serialized with Chartist.serialize. The string will always be unescaped using Chartist.escapingMap before it's returned. Based on the input value the return type can be Number, String or Object. JSON.parse is used with try / catch to see if the unescaped string can be parsed into an Object and this Object will be returned on success.
34 | */
35 | export function deserialize(
36 | data: string
37 | ): T;
38 | export function deserialize(
39 | data: string | null | undefined
40 | ): T | null | undefined;
41 | export function deserialize(data: unknown) {
42 | if (typeof data !== 'string') {
43 | return data;
44 | }
45 |
46 | if (data === 'NaN') {
47 | return NaN;
48 | }
49 |
50 | data = Object.keys(escapingMap).reduce(
51 | (result, key) => result.replaceAll(escapingMap[key], key),
52 | data
53 | );
54 |
55 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
56 | let parsedData: any = data;
57 |
58 | if (typeof data === 'string') {
59 | try {
60 | parsedData = JSON.parse(data);
61 | parsedData = parsedData.data !== undefined ? parsedData.data : parsedData;
62 | } catch (e) {
63 | /* Ingore */
64 | }
65 | }
66 |
67 | return parsedData;
68 | }
69 |
--------------------------------------------------------------------------------
/src/svg/SvgList.ts:
--------------------------------------------------------------------------------
1 | import { Svg } from './Svg';
2 |
3 | type SvgMethods = Exclude<
4 | keyof Svg,
5 | | 'constructor'
6 | | 'parent'
7 | | 'querySelector'
8 | | 'querySelectorAll'
9 | | 'replace'
10 | | 'append'
11 | | 'classes'
12 | | 'height'
13 | | 'width'
14 | >;
15 |
16 | type SvgListMethods = {
17 | [method in SvgMethods]: (...args: Parameters