[
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": [\"airbnb-base\"],\n  \"rules\": {\n    \"no-console\": \"warn\",\n    \"indent\": [\"warn\", 2],\n    \"no-new\": \"off\",\n    \"class-methods-use-this\":\"warn\"\n  },\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"mocha\": true\n  }\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ncustom: https://sponsor.cat/timqian.eth\ngithub: timqian # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: timqian # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**Screenshot**\nIf applicable, add screenshots to help explain your problem.\n\n**How to reproduce**\ncode to reproduce the bug (Codepen link preferred)\n\n**Additional context**\nAdd any other context about the problem here.\n\n<!--\n  To support us solving this issue, please consider either\n    - fund this issue on issuehunt after you create it: issuehunt.io/r/timqian/chart.xkcd?tab=idle\n    - be a patron of timqian: patreon.com/timqian\n>\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/chart-request.md",
    "content": "---\nname: Chart request\nabout: Suggest a new chart type for chart.xkcd\ntitle: \"[new chart]: \"\nlabels: new chart\nassignees: ''\n\n---\n\n**Chart type**\n\n**Example of how the chart looks in other chart libs**\n\n- link\n\n- screenshot\n\n<!--\n  To support us building this chart, please consider either\n    - be a patron of timqian: patreon.com/timqian\n    - fund this issue on issuehunt after you create it: issuehunt.io/r/timqian/chart.xkcd?tab=idle\n>\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n\n<!--\n  To support us for adding this feature, please consider either\n    - be a patron of timqian: patreon.com/timqian\n    - fund this issue on issuehunt after you create it: issuehunt.io/r/timqian/chart.xkcd?tab=idle\n>\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "**Related issue**\n\nFix #issueNumber\n\n**Screenshot before and after this change**\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "name: Node CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [8.x, 10.x, 12.x]\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - name: npm install, build, and test\n      run: |\n        npm install\n        npm run build --if-present\n      env:\n        CI: true\n"
  },
  {
    "path": ".gitignore",
    "content": ".cache\nnode_modules\ndist\n/docs-dist\n/previous-works\n/assets\n/insprations.md\n.DS_Store\n.idea/"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) egoist <0x142857@gmail.com> (https://github.com/egoist)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "contributing.md",
    "content": "> drafting\n\n# Contributing\n\nBefore contributing to chart.xkcd you'll need a few things:\n\n- install npm\n\n## Setup\n\n```bash\n# install dependencies\nnpm i\n```\n\n```bash\n# start examples (example/npm)\nnpm start\n```\n\nThen you can open `localhost:1234` to see the examples, and you can start to edit the code. Thanks to [parcel](), the website will be auto updated when you make changes.\n\n## Layout\n\n- [docs](./docs): Documentation used to generate timqian.com/chart.xkcd\n- [examples](./examples): Examples showing how to use chart.xkcd. The npm example is also used for developing and debug features for now.\n- [src](./src): where the meat locates\n\n## Releases\n\nNotes for myself:\n\n- before building chart.xkcd, shut down parcel server\n- `npm run release`(TODO)\n"
  },
  {
    "path": "docs/01-intro.md",
    "content": "---\ntitle: Introduction\n---\n\n<!-- Chart.xkcd is an xkcd styled chart library. Not like most chart libs out there do precise plots. The rough, seemingly hand drawn nature of the graph provides a visual hint as to the imprecision of the results. It is useful in some cases.\n\nWhen precise numbers\n\n\nWe already have lots of great chart libraries like [chart.js](), [echart](), [chartist-js](https://github.com/gionkunz/chartist-js) etc. One of the problems I've had with them is  that everything they draw is so precise and perfect. Sometimes I want the plots looks less precise to d -->\n\nChart.xkcd is a chart library plots \"sketchy\", \"cartoony\" or \"hand-drawn\" styled charts.\n\n[![donate](https://flat.badgen.net/badge/support%20me/donate/?color=e85b46)](https://patreon.com/timqian)\n[![slack](https://flat.badgen.net/badge/chat%20with%20us/slack/green)](https://join.slack.com/t/t9tio/shared_invite/enQtNjgzMzkwMDM0NTE3LTE5ZTUzYjU4Y2I0YzRiZjNkYTkzMzE1ZmM0NDdmYzRlZmMxNGY1MzZlN2EwYjYyNWVlMWY0Nzk2MDBhNWZlY2I)\n[![stars](https://flat.badgen.net/github/stars/timqian/chart.xkcd?icon=github)](https://github.com/timqian/chart.xkcd)\n[![npm](https://flat.badgen.net/npm/v/chart.xkcd/?color=fb3e44)](https://www.npmjs.com/package/chart.xkcd)\n[![jsdelivr](https://data.jsdelivr.com/v1/package/npm/chart.xkcd/badge)](https://www.jsdelivr.com/package/npm/chart.xkcd)\n\n## Sponsors\n\n[Madao](https://madao.me/) | [Become a sponsor](https://www.patreon.com/timqian)\n"
  },
  {
    "path": "docs/02-getting-started.md",
    "content": "---\ntitle: Getting started\n---\n\nIt's easy to get started with chart.xkcd. All that's required is the script included in your page along with a single `<svg>` node to render the chart.\n\nIn the following example we create a line chart.\n\n<p class=\"codepen\" data-height=\"424\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"GRKqLaL\" style=\"height: 424px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd example\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/GRKqLaL/\">\n  chart.xkcd example</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n**JS part of the example**\n\n```javascript\n  const svg = document.querySelector('.line-chart')\n  new chartXkcd.Line(svg, {\n    title: '',\n    xLabel: '',\n    yLabel: '',\n    data: {...},\n    options: {},\n  });\n```\n\n## Parameters description\n\n- `title`: optional title of the chart\n- `xLabel`: optional x label of the chart\n- `yLabel`: optional y label of the chart\n- `data`: the data you want to visulize\n- `options`: optional configurations to customize how the chart looks\n"
  },
  {
    "path": "docs/03-install.md",
    "content": "---\ntitle: Installation\n---\n\nYou can install chart.xkcd via script tag in HTML or via npm\n\n## Via Script Tag\n\n```js\n<script src=\"https://cdn.jsdelivr.net/npm/chart.xkcd@1.1/dist/chart.xkcd.min.js\" integrity=\"sha256-NkH6G4XRcQ5Bsfs7O6yh9mw1SJLEOJWCtWqko6VjF34=\" crossorigin=\"anonymous\"></script>\n<script>\n    const myChart = new chartXkcd.Line(svg, {...});\n</script>\n```\n\n## Via npm\n\n**Install**\n\n```bash\nnpm i chart.xkcd\n```\n\n**Usage**\n\n```js\nimport chartXkcd from 'chart.xkcd';\nconst myChart = new chartXkcd.Line(svg, {...});\n```\n\n**Other ways**\n\n- React wrapper: [chart.xkcd-react](https://github.com/obiwankenoobi/chart.xkcd-react) <br/>\n- Vue wrapper:\n    - [chart.xkcd-vue](https://github.com/shiyiya/chart.xkcd-vue)\n    - [chart.xkcd-vue-wrapper](https://github.com/wistcc/chart.xkcd-vue-wrapper)\n"
  },
  {
    "path": "docs/04-line.md",
    "content": "---\ntitle: Line chart\n---\n\nLine chart displays series of data points in the form of lines. It can be used to show trend data, or comparison of different data sets.\n\n<p class=\"codepen\" data-height=\"424\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"GRKqLaL\" style=\"height: 424px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd example\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/GRKqLaL/\">\n  chart.xkcd example</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\nconst lineChart = new chartXkcd.Line(svg, {\n  title: 'Monthly income of an indie developer', // optional\n  xLabel: 'Month', // optional\n  yLabel: '$ Dollars', // optional\n  data: {\n    labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n    datasets: [{\n      label: 'Plan',\n      data: [30, 70, 200, 300, 500, 800, 1500, 2900, 5000, 8000],\n    }, {\n      label: 'Reality',\n      data: [0, 1, 30, 70, 80, 100, 50, 80, 40, 150],\n    }],\n  },\n  options: { // optional\n    yTickCount: 3,\n    legendPosition: chartXkcd.config.positionType.upLeft\n  }\n})\n```\n\n## Customize chart by defining options\n\n- `yTickCount`: customize tick numbers you want to see on the y axis (default `3`)\n- `showLegend`: display legend near chart (default `true`)\n- `legendPosition`: specify where you want to place the legend. (default `chartXkcd.config.positionType.upLeft`)\n  Possible values:\n    - up left: `chartXkcd.config.positionType.upLeft`\n    - up right: `chartXkcd.config.positionType.upRight`\n    - bottom left: `chartXkcd.config.positionType.downLeft`\n    - bottom right: `chartXkcd.config.positionType.downRight`\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)"
  },
  {
    "path": "docs/05-XY.md",
    "content": "---\ntitle: XY chart\n---\n\nXY chart is used to plot points by specifying their XY coordinates.\n\nYou can also plot XY line chart by connecting the points.\n\n<p class=\"codepen\" data-height=\"445\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"ExYZvZY\" style=\"height: 445px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd XY\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/ExYZvZY/\">\n  chart.xkcd XY</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\n  const svg = document.querySelector('.xy-chart');\n\n  new chartXkcd.XY(svg, {\n    title: 'Pokemon farms', //optional\n    xLabel: 'Coordinate', //optional\n    yLabel: 'Count', //optional\n    data: {\n      datasets: [{\n        label: 'Pikachu',\n        data: [{ x: 3, y: 10 }, { x: 4, y: 122 }, { x: 10, y: 100 }, { x: 1, y: 2 }, { x: 2, y: 4 }],\n      }, {\n        label: 'Squirtle',\n        data: [{ x: 3, y: 122 }, { x: 4, y: 212 }, { x: -3, y: 100 }, { x: 1, y: 1 }, { x: 1.5, y: 12 }],\n      }],\n    },\n    options: { //optional\n      xTickCount: 5,\n      yTickCount: 5,\n      legendPosition: chartXkcd.config.positionType.upRight,\n      showLine: false,\n      timeFormat: undefined,\n      dotSize: 1,\n    },\n  });\n```\n\n## Customize XY chart by defining options\n\n- `xTickCount`: customize tick numbers you want to see on the x axis (default `3`)\n- `yTickCount`: customize tick numbers you want to see on the y axis (default `3`)\n- `showLegend`: display legend near chart (default `true`)\n- `legendPosition`: specify where you want to place the legend (default `chartXkcd.config.positionType.upLeft`)\n  Possible values:\n    - up left: `chartXkcd.config.positionType.upLeft`\n    - up right: `chartXkcd.config.positionType.upLeft`\n    - bottom left: `chartXkcd.config.positionType.downLeft`\n    - bottom right: `chartXkcd.config.positionType.downRight`\n- `showLine`: connect the points with lines (default: `false`)\n- `timeFormat`: specify the time format if the x values are time (default `undefined`)\n  chart.xkcd use [dayjs](https://github.com/iamkun/dayjs) to format time, you can find the all the available formats [here](https://github.com/iamkun/dayjs/blob/dev/docs/en/API-reference.md#list-of-all-available-formats)\n- `dotSize`: you can change size of the dots if you want (default `1`)\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)\n\n**Another example of XY chart: XY line chart with `timeFormat`**\n\n<p class=\"codepen\" data-height=\"472\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"ZEzLJaN\" style=\"height: 472px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd XY line\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/ZEzLJaN/\">\n  chart.xkcd XY line</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n"
  },
  {
    "path": "docs/06-bar.md",
    "content": "---\ntitle: Bar chart\n---\n\nA bar chart provides a way of showing data values represented as vertical bars\n\n<p class=\"codepen\" data-height=\"509\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"QWLERdG\" style=\"height: 509px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd bar\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/QWLERdG/\">\n  chart.xkcd bar</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\nconst barChart = new chartXkcd.Bar(svg, {\n  title: 'github stars VS patron number', // optional\n  // xLabel: '', // optional\n  // yLabel: '', // optional\n  data: {\n    labels: ['github stars', 'patrons'],\n    datasets: [{\n      data: [100, 2],\n    }],\n  },\n  options: { // optional\n    yTickCount: 2,\n  },\n});\n```\n\n## Customize chart by defining options\n\n- `yTickCount`: customize tick numbers you want to see on the y axis\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)"
  },
  {
    "path": "docs/07-stacked-bar.md",
    "content": "---\ntitle: Stacked bar chart\n---\n\nA stacked bar chart provides a way of showing data values represented as vertical bars\n\n<p class=\"codepen\" data-height=\"429\" data-theme-id=\"default\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"KKwPrEm\" style=\"height: 429px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd stacked bar\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/KKwPrEm\">\n  chart.xkcd stacked bar</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\nnew chartXkcd.StackedBar(svg, {\n  title: 'Issues and PR Submissions',\n  xLabel: 'Month',\n  yLabel: 'Count',\n  data: {\n    labels: ['Jan', 'Feb', 'Mar', 'April', 'May'],\n    datasets: [{\n      label: 'Issues',\n      data: [12, 19, 11, 29, 17],\n    }, {\n      label: 'PRs',\n      data: [3, 5, 2, 4, 1],\n    }, {\n      label: 'Merges',\n      data: [2, 3, 0, 1, 1],\n    }],\n  },\n});\n```\n\n## Customize chart by defining options\n\n- `yTickCount`: customize tick numbers you want to see on the y axis\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)\n- `showLegend`: display legend near chart (default `true`)\n- `legendPosition`: specify where you want to place the legend (default `chartXkcd.config.positionType.upLeft`)\n  Possible values:\n    - up left: `chartXkcd.config.positionType.upLeft`\n    - up right: `chartXkcd.config.positionType.upLeft`\n    - bottom left: `chartXkcd.config.positionType.downLeft`\n    - bottom right: `chartXkcd.config.positionType.downRight`"
  },
  {
    "path": "docs/08-pie.md",
    "content": "---\ntitle: Pie/Doughnut chart\n---\n\n<p class=\"codepen\" data-height=\"470\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"VwZjOPR\" style=\"height: 470px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd pie\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/VwZjOPR/\">\n  chart.xkcd pie</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\nconst pieChart = new chartXkcd.Pie(svg, {\n  title: 'What Tim is made of', // optional\n  data: {\n    labels: ['a', 'b', 'e', 'f', 'g'],\n    datasets: [{\n      data: [500, 200, 80, 90, 100],\n    }],\n  },\n  options: { // optional\n    innerRadius: 0.5,\n    legendPosition: chartXkcd.config.positionType.upRight,\n  },\n});\n```\n\n## Customize chart by defining options\n\n- `innerRadius`: specify empty pie chart radius (default: `0.5`)\n  - Want a pie chart? set `innerRadius` to `0`\n- `showLegend`: display legend near chart (default `true`)\n- `legendPosition`: specify where you want to place the legend. (default `chartXkcd.config.positionType.upLeft`)\n  Possible values:\n    - up left: `chartXkcd.config.positionType.upLeft`\n    - up right: `chartXkcd.config.positionType.upLeft`\n    - bottom left: `chartXkcd.config.positionType.downLeft`\n    - bottom right: `chartXkcd.config.positionType.downRight`\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)"
  },
  {
    "path": "docs/09-radar.md",
    "content": "---\ntitle: Radar chart\n---\n\n<p class=\"codepen\" data-height=\"434\" data-theme-id=\"light\" data-default-tab=\"result\" data-user=\"timqian\" data-slug-hash=\"VwZQBoj\" style=\"height: 434px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"chart.xkcd radar\">\n  <span>See the Pen <a href=\"https://codepen.io/timqian/pen/VwZQBoj/\">\n  chart.xkcd radar</a> by timqian (<a href=\"https://codepen.io/timqian\">@timqian</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n\n## JS part\n\n```js\nconst radar = new chartXkcd.Radar(svg, {\n  title: 'Letters in random words', // optional\n  data: {\n    labels: ['c', 'h', 'a', 'r', 't'],\n    datasets: [{\n      label: 'ccharrrt', // optional\n      data: [2, 1, 1, 3, 1],\n    }, {\n      label: 'chhaart', // optional\n      data: [1, 2, 2, 1, 1],\n    }],\n  },\n  options: { // optional\n    showLegend: true,\n    dotSize: .8,\n    showLabels: true,\n    legendPosition: chartXkcd.config.positionType.upRight,\n  },\n});\n```\n\n## Customize chart by defining options\n\n- `showLabels`: display labels near every line (default `false`)\n- `ticksCount`: customize tick numbers you want to see on the main line (default `3`)\n- `dotSize`: you can change size of the dots if you want (default `1`)\n- `showLegend`: display legend near chart (default `false`)\n- `legendPosition`: specify where you want to place the legend. (default `chartXkcd.config.positionType.upLeft`)\n  Possible values:\n    - up left: `chartXkcd.config.positionType.upLeft`\n    - up right: `chartXkcd.config.positionType.upRight`\n    - bottom left: `chartXkcd.config.positionType.downLeft`\n    - bottom right: `chartXkcd.config.positionType.downRight`\n- `dataColors`: array of colors for different datasets\n- `fontFamily`: customize font family used in the chart\n- `unxkcdify`: disable xkcd effect (default `false`)\n- `strokeColor`: stroke colors (default `black`)\n- `backgroundColor`: color for BG (default `white`)"
  },
  {
    "path": "examples/example.html",
    "content": "<html>\n    <head>\n      <meta name=\"viewport\" content=\"initial-scale=1.0, width=device-width\" />\n      <link href=\"https://fonts.googleapis.com/css?family=ZCOOL+KuaiLe&display=swap\" rel=\"stylesheet\">\n    </head>\n  <body>\n    <h1><a href=\"https://github.com/timqian/chart.xkcd/tree/master/examples\">Source code of the examples</a></h1>\n    <br/>\n\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"bar-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"stacked-bar-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"pie-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"line-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"xyline-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"xyline-chart2\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"radar-chart\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"line-chart-cus\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"line-chart-unxkcdify\"></svg></div>\n    <div style=\"width: 400px; height: 300px; display: inline-block;\"><svg class=\"line-chart-dark\"></svg></div>\n\n    <script src=\"./index.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/index.js",
    "content": "// import chartXkcd from 'chart.xkcd';\n// import chartXkcd from '../../dist/chart.xkcd';\nimport chartXkcd from '../src';\n\nconst svg = document.querySelector('.bar-chart');\n\nnew chartXkcd.Bar(svg, {\n  title: 'Github stars VS patron number',\n  xLabel: 'Month',\n  yLabel: 'Count',\n  data: {\n    labels: ['github stars', 'patrons'],\n    datasets: [{\n      data: [100, 2],\n    }],\n  },\n  // options: {\n  //   yTickCount: 2,\n  //   // unxkcdify: true,\n  //   // strokeColor: 'white',\n  //   // backgroundColor: 'black',\n  // },\n});\n\nconst svgStackedBar = document.querySelector('.stacked-bar-chart');\nnew chartXkcd.StackedBar(svgStackedBar, {\n  title: 'Issues and PR Submissions',\n  xLabel: 'Month',\n  yLabel: 'Count',\n  data: {\n    labels: ['Jan', 'Feb', 'Mar', 'April', 'May'],\n    datasets: [{\n      label: 'Issues',\n      data: [12, 19, 11, 29, 17],\n    }, {\n      label: 'PRs',\n      data: [3, 5, 2, 4, 1],\n    }, {\n      label: 'Merges',\n      data: [2, 3, 0, 1, 1],\n    }],\n  },\n  // options: {\n  // showLegend: true,\n  //   yTickCount: 2,\n  //   // unxkcdify: true,\n  //   // strokeColor: 'white',\n  //   // backgroundColor: 'black',\n  // },\n});\n\nconst svgPie = document.querySelector('.pie-chart');\nnew chartXkcd.Pie(svgPie, {\n  title: 'What Tim is made of',\n  data: {\n    labels: ['a', 'b', 'e', 'f', 'g'],\n    datasets: [{\n      data: [500, 200, 80, 90, 100],\n    }],\n  },\n  options: {\n    innerRadius: 0.6,\n    legendPosition: chartXkcd.config.positionType.upRight,\n    // showLegend: true,\n    // unxkcdify: true,\n    // strokeColor: 'white',\n    // backgroundColor: 'black',\n  },\n});\n\nconst svgLine = document.querySelector('.line-chart');\nnew chartXkcd.Line(svgLine, {\n  title: 'Monthly income of an indie developer',\n  xLabel: 'Month',\n  yLabel: '$ Dollars',\n  data: {\n    labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n    datasets: [{\n      label: 'Plan',\n      data: [30, 70, 200, 300, 500, 800, 1500, 2900, 5000, 8000],\n    }, {\n      label: 'Reality',\n      data: [0, 1, 30, 70, 80, 100, 50, 80, 40, 150],\n    }],\n  },\n  options: {\n    // unxkcdify: true,\n    // strokeColor: 'black',\n    // backgroundColor: 'white',\n  },\n});\n\nconst svgXY = document.querySelector('.xyline-chart');\nnew chartXkcd.XY(svgXY, {\n  title: 'stars',\n  xLabel: 'wo',\n  yLabel: 'Stars count',\n  data: {\n    datasets: [{\n      label: 'timqian',\n      data: [{ x: 3, y: 10 }, { x: 4, y: 122 }, { x: 10, y: 180 }, { x: 1, y: 2 }, { x: 2, y: 4 }],\n    }, {\n      label: 'wewean',\n      data: [{ x: 3, y: 122 }, { x: 4, y: 212 }, { x: -3, y: 100 }, { x: 1, y: 1 }, { x: 1.5, y: 12 }],\n    }],\n  },\n  options: {\n    xTickCount: 5,\n    yTickCount: 5,\n    legendPosition: chartXkcd.config.positionType.downRight,\n    showLine: false,\n    // showLegend: true,\n    // unxkcdify: true,\n    // strokeColor: 'blue',\n    // backgroundColor: 'black',\n\n  },\n});\n\nconst svgXY2 = document.querySelector('.xyline-chart2');\nnew chartXkcd.XY(svgXY2, {\n  title: 'Github star history',\n  xLabel: 'Month',\n  yLabel: 'Stars abc',\n  data: {\n    datasets: [{\n      label: 'timqian/chart.xkcd',\n      data: [{ x: '2015-03-01', y: 0 }, { x: '2015-04-01', y: 2 }, { x: '2015-05-01', y: 4 }, { x: '2015-06-01', y: 10 }, { x: '2015-07-01', y: 122 }],\n    }, {\n      label: 'timqian/star-history',\n      data: [{ x: '2015-01-01', y: 0 }, { x: '2015-03-01', y: 1 }, { x: '2015-04-01', y: 12 }, { x: '2015-05-01', y: 122 }, { x: '2015-06-01', y: 212 }],\n    }],\n  },\n  options: {\n    xTickCount: 3,\n    yTickCount: 4,\n    legendPosition: chartXkcd.config.positionType.upLeft,\n    showLine: true,\n    timeFormat: 'MM/DD/YYYY',\n    dotSize: 0.5,\n    // unxkcdify: true,\n    // strokeColor: 'white',\n    // backgroundColor: 'black',\n  },\n});\n\nconst svgRadar = document.querySelector('.radar-chart');\nnew chartXkcd.Radar(svgRadar, {\n  title: 'Radar',\n  data: {\n    labels: ['c', 'h', 'a', 'r', 't'],\n    datasets: [{\n      label: 'ccharrrt',\n      data: [2, 1, 1, 3, 1],\n    }, {\n      label: 'chhaart',\n      data: [1, 2, 2, 1, 1],\n    }],\n  },\n  options: {\n    showLegend: true,\n    dotSize: 0.8,\n    showLabels: true,\n    legendPosition: chartXkcd.config.positionType.upRight,\n    // unxkcdify: true,\n    // strokeColor: 'white',\n    // backgroundColor: 'black',\n  },\n});\n\nconst svgLineCus = document.querySelector('.line-chart-cus');\nnew chartXkcd.Line(svgLineCus, {\n  title: 'Customize Font & colors (定制外观)',\n  xLabel: 'this is x label',\n  yLabel: 'y label',\n  data: {\n    labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n    datasets: [{\n      label: 'font',\n      data: [30, 70, 200, 300, 500, 800, 100, 290, 500, 300],\n    }, {\n      label: 'color',\n      data: [0, 1, 30, 70, 80, 100, 500, 80, 40, 250],\n    }],\n  },\n  options: {\n    fontFamily: 'ZCOOL KuaiLe',\n    dataColors: ['black', '#aaa'],\n    legendPosition: chartXkcd.config.positionType.upRight,\n    // strokeColor: 'white',\n    // backgroundColor: 'black',\n  },\n});\n\n\nconst svgLineUnxkcdify = document.querySelector('.line-chart-unxkcdify');\nnew chartXkcd.Line(svgLineUnxkcdify, {\n  title: 'Unxkcdify',\n  xLabel: 'this is x label',\n  yLabel: 'y label',\n  data: {\n    labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n    datasets: [{\n      label: 'font',\n      data: [30, 70, 200, 300, 500, 800, 100, 290, 500, 300],\n    }, {\n      label: 'color',\n      data: [0, 1, 30, 70, 80, 100, 500, 80, 40, 250],\n    }],\n  },\n  options: {\n    unxkcdify: true,\n    // strokeColor: 'white',\n    // backgroundColor: 'black',\n  },\n});\n\nconst svgDark = document.querySelector('.line-chart-dark');\nnew chartXkcd.XY(svgDark, {\n  title: 'stars',\n  xLabel: 'wo',\n  yLabel: 'Stars count',\n  data: {\n    datasets: [{\n      label: 'timqian',\n      data: [{ x: 3, y: 10 }, { x: 4, y: 122 }, { x: 10, y: 180 }, { x: 1, y: 2 }, { x: 2, y: 4 }],\n    }, {\n      label: 'wewean',\n      data: [{ x: 3, y: 122 }, { x: 4, y: 212 }, { x: -3, y: 100 }, { x: 1, y: 1 }, { x: 1.5, y: 12 }],\n    }],\n  },\n  options: {\n    xTickCount: 5,\n    yTickCount: 5,\n    legendPosition: chartXkcd.config.positionType.downRight,\n    showLine: false,\n    // unxkcdify: true,\n    strokeColor: 'white',\n    backgroundColor: 'black',\n\n  },\n});\n"
  },
  {
    "path": "examples/readme.md",
    "content": "## Preview\n\nhttps://timqian.com/chart.xkcd/example.html\n\n## Try it yourself\n\n1. clone this repo\n1. `npm install`\n2. `npm start`\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"chart.xkcd\",\n  \"version\": \"1.1.15\",\n  \"description\": \"xkcd style chart lib\",\n  \"jsdelivr\": \"dist/chart.xkcd.min.js\",\n  \"unpkg\": \"dist/chart.xkcd.min.js\",\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist/*\"\n  ],\n  \"scripts\": {\n    \"buildUmd\": \"parcel build src/index.js --target browser --out-file chart.xkcd.min.js --no-source-maps --experimental-scope-hoisting --global chartXkcd\",\n    \"build\": \"parcel build src/index.js --target node --bundle-node-modules --no-source-maps --experimental-scope-hoisting\",\n    \"start\": \"parcel examples/example.html\",\n    \"prepublishOnly\": \"rm -rf dist && npm run buildUmd && npm run build\",\n    \"genDoc\": \"~/go/bin/static-docs --in docs --out docs-dist --title Chart.xkcd --subtitle 'xkcd styled chart lib'\",\n    \"genExample\": \"parcel build examples/example.html --out-dir docs-dist --public-url /chart.xkcd\",\n    \"deployDoc\": \"npm run genDoc && npm run genExample && gh-pages -d docs-dist\",\n    \"lint\": \"./node_modules/.bin/eslint ./src\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/timqian/chart.xkcd\"\n  },\n  \"homepage\": \"https://timqian.com/chart.xkcd\",\n  \"keywords\": [\n    \"chart\",\n    \"graph\",\n    \"xkcd\",\n    \"hand-drawn\"\n  ],\n  \"author\": \"timqian\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"eslint\": \"^6.2.1\",\n    \"eslint-config-airbnb-base\": \"^14.0.0\",\n    \"eslint-plugin-import\": \"^2.18.2\",\n    \"gh-pages\": \"^2.1.1\",\n    \"parcel-bundler\": \"^1.12.4\"\n  },\n  \"dependencies\": {\n    \"d3-axis\": \"^1.0.12\",\n    \"d3-scale\": \"^3.2.0\",\n    \"d3-selection\": \"^1.4.1\",\n    \"d3-shape\": \"^1.3.7\",\n    \"dayjs\": \"^1.8.17\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "[![](https://raw.githubusercontent.com/timqian/images/master/20190819131226.gif)](https://timqian.com/chart.xkcd/)\n\n> [Who is using chart.xkcd?](https://github.com/timqian/chart.xkcd/issues/14)\n\n## About\n\nChart.xkcd is a chart library that plots “sketchy”, “cartoony” or “hand-drawn” styled charts.\n\nCheck out the [documentation](https://timqian.com/chart.xkcd/) for more instructions and links, or try out the [examples](https://timqian.com/chart.xkcd/example.html), or chat with us in [Slack](https://join.slack.com/t/t9tio/shared_invite/enQtNjgzMzkwMDM0NTE3LTE5ZTUzYjU4Y2I0YzRiZjNkYTkzMzE1ZmM0NDdmYzRlZmMxNGY1MzZlN2EwYjYyNWVlMWY0Nzk2MDBhNWZlY2I)\n\n## Sponsors\n\n[琚致远](https://github.com/juzhiyuan) | [Bytebase](https://bytebase.com/) | [Madao](https://madao.me/) | [SecondState](https://bit.ly/3gfWwps)\n\n[Become a sponsor](https://github.com/sponsors/timqian)\n\n## Quick start\n\nIt’s easy to get started with chart.xkcd. All that’s required is the script included in your page along with a single `<svg>` node to render the chart.\n\nIn the following example we create a line chart.\n\n> **[Preview and edit on codepen](https://codepen.io/timqian/pen/GRKqLaL)**\n\n```html\n<svg class=\"line-chart\"></svg>\n<script src=\"https://cdn.jsdelivr.net/npm/chart.xkcd@1/dist/chart.xkcd.min.js\"></script>\n<script>\n  const svg = document.querySelector('.line-chart')\n\n  new chartXkcd.Line(svg, {\n    title: 'Monthly income of an indie developer',\n    xLabel: 'Month',\n    yLabel: '$ Dollars',\n    data: {\n      labels:['1', '2', '3', '4', '5', '6','7', '8', '9', '10'],\n      datasets: [{\n        label: 'Plan',\n        data: [30, 70, 200, 300, 500 ,800, 1500, 2900, 5000, 8000],\n      }, {\n        label: 'Reality',\n        data: [0, 1, 30, 70, 80, 100, 50, 80, 40, 150],\n      }]\n    },\n    options: {}\n  });\n</script>\n```\n\n## Contributing\n\n- Code: read the [contributing.md](./contributing.md) file\n- Financial:\n  - [Become a patron](https://www.patreon.com/timqian) - chart.xkcd is an MIT-licensed open source project with its ongoing development made possible entirely by the support of my patrons. If you like this tool, please consider supporting my work by becoming a patron.\n  - [Fund issues on issuehunt](https://issuehunt.io/r/timqian/chart.xkcd?tab=idle) - Issues on chart.xkcd can be funded by anyone and the money will be distributed to contributors.\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=timqian/chart.xkcd&type=Date)](https://star-history.com/#timqian/chart.xkcd&Date)\n"
  },
  {
    "path": "src/Bar.js",
    "content": "import select from 'd3-selection/src/select';\nimport mouse from 'd3-selection/src/mouse';\nimport scaleBand from 'd3-scale/src/band';\nimport scaleLinear from 'd3-scale/src/linear';\n\nimport addAxis from './utils/addAxis';\nimport addLabels from './utils/addLabels';\nimport Tooltip from './components/Tooltip';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = {\n  top: 50, right: 30, bottom: 50, left: 50,\n};\n\nclass Bar {\n  constructor(svg, {\n    title, xLabel, yLabel, data: { labels, datasets }, options,\n  }) {\n    this.options = {\n      unxkcdify: false,\n      yTickCount: 3,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      ...options,\n    };\n    if (title) {\n      this.title = title;\n      margin.top = 60;\n    }\n    if (xLabel) {\n      this.xLabel = xLabel;\n      margin.bottom = 50;\n    }\n    if (yLabel) {\n      this.yLabel = yLabel;\n      margin.left = 70;\n    }\n    this.data = {\n      labels,\n      datasets,\n    };\n    this.filter = 'url(#xkcdify)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n\n    this.svgEl = select(svg)\n      .style('stroke-width', '3')\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n\n    this.svgEl.selectAll('*').remove();\n\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${margin.left},${margin.top})`);\n    this.width = this.svgEl.attr('width') - margin.left - margin.right;\n    this.height = this.svgEl.attr('height') - margin.top - margin.bottom;\n\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    if (this.xLabel) addLabels.xLabel(this.svgEl, this.xLabel, this.options.strokeColor);\n    if (this.yLabel) addLabels.yLabel(this.svgEl, this.yLabel, this.options.strokeColor);\n\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: 'tooltip',\n      items: [{ color: 'red', text: 'weweyang: 12' }, { color: 'blue', text: 'timqian: 13' }],\n      position: { x: 30, y: 30, type: config.positionType.upRight },\n      unxkcdify: this.options.unxkcdify,\n      backgroundColor: this.options.backgroundColor,\n      strokeColor: this.options.strokeColor,\n    });\n\n    const xScale = scaleBand()\n      .range([0, this.width])\n      .domain(this.data.labels)\n      .padding(0.4);\n\n    const allData = this.data.datasets\n      .reduce((pre, cur) => pre.concat(cur.data), []);\n\n    const yScale = scaleLinear()\n      .domain([0, Math.max(...allData)])\n      .range([this.height, 0]);\n\n    const graphPart = this.chart.append('g');\n\n    // axis\n    addAxis.xAxis(graphPart, {\n      xScale,\n      tickCount: 3,\n      moveDown: this.height,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n    addAxis.yAxis(graphPart, {\n      yScale,\n      tickCount: this.options.yTickCount || 3,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n\n    // Bars\n    graphPart.selectAll('.xkcd-chart-bar')\n      .data(this.data.datasets[0].data)\n      .enter()\n      .append('rect')\n      .attr('class', 'xkcd-chart-bar')\n      .attr('x', (d, i) => xScale(this.data.labels[i]))\n      .attr('width', xScale.bandwidth())\n      .attr('y', (d) => yScale(d))\n      .attr('height', (d) => this.height - yScale(d))\n      .attr('fill', 'none')\n      .attr('pointer-events', 'all')\n      .attr('stroke', this.options.strokeColor)\n      .attr('stroke-width', 3)\n      .attr('rx', 2)\n      // .attr('cursor','crosshair')\n      .attr('filter', this.filter)\n      .on('mouseover', (d, i, nodes) => {\n        select(nodes[i]).attr('fill', this.options.dataColors[i]);\n        // select(nodes[i]).attr('fill', 'url(#hatch00)');\n        tooltip.show();\n      })\n      .on('mouseout', (d, i, nodes) => {\n        select(nodes[i]).attr('fill', 'none');\n        tooltip.hide();\n      })\n      .on('mousemove', (d, i, nodes) => {\n        const tipX = mouse(nodes[i])[0] + margin.left + 10;\n        const tipY = mouse(nodes[i])[1] + margin.top + 10;\n\n        let tooltipPositionType = config.positionType.downRight;\n        if (tipX > this.width / 2 && tipY < this.height / 2) {\n          tooltipPositionType = config.positionType.downLeft;\n        } else if (tipX > this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upLeft;\n        } else if (tipX < this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upRight;\n        }\n        tooltip.update({\n          title: this.data.labels[i],\n          items: [{\n            color: this.options.dataColors[i],\n            text: `${this.data.datasets[0].label || ''}: ${d}`,\n          }],\n          position: {\n            x: tipX,\n            y: tipY,\n            type: tooltipPositionType,\n          },\n        });\n      });\n  }\n\n  // TODO: update chart\n  update() {\n\n  }\n}\n\nexport default Bar;\n"
  },
  {
    "path": "src/Line.js",
    "content": "import line from 'd3-shape/src/line';\nimport { monotoneX } from 'd3-shape/src/curve/monotone';\nimport select from 'd3-selection/src/select';\nimport mouse from 'd3-selection/src/mouse';\nimport { point as scalePoint } from 'd3-scale/src/band';\nimport scaleLinear from 'd3-scale/src/linear';\n\nimport addAxis from './utils/addAxis';\nimport addLabels from './utils/addLabels';\nimport Tooltip from './components/Tooltip';\nimport addLegend from './utils/addLegend';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = {\n  top: 50, right: 30, bottom: 50, left: 50,\n};\n\nclass Line {\n  constructor(svg, {\n    title, xLabel, yLabel, data: { labels, datasets }, options,\n  }) {\n    this.options = {\n      unxkcdify: false,\n      yTickCount: 3,\n      legendPosition: config.positionType.upLeft,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      showLegend: true,\n      ...options,\n    };\n    if (title) {\n      this.title = title;\n      margin.top = 60;\n    }\n    if (xLabel) {\n      this.xLabel = xLabel;\n      margin.bottom = 50;\n    }\n    if (yLabel) {\n      this.yLabel = yLabel;\n      margin.left = 70;\n    }\n    this.data = {\n      labels,\n      datasets,\n    };\n    this.filter = 'url(#xkcdify)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n\n    this.svgEl = select(svg)\n      .style('stroke-width', '3')\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n    this.svgEl.selectAll('*').remove();\n\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${margin.left},${margin.top})`);\n    this.width = this.svgEl.attr('width') - margin.left - margin.right;\n    this.height = this.svgEl.attr('height') - margin.top - margin.bottom;\n\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    if (this.xLabel) addLabels.xLabel(this.svgEl, this.xLabel, this.options.strokeColor);\n    if (this.yLabel) addLabels.yLabel(this.svgEl, this.yLabel, this.options.strokeColor);\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: '',\n      items: [{ color: 'red', text: 'weweyang' }, { color: 'blue', text: 'timqian' }],\n      position: { x: 60, y: 60, type: config.positionType.downRight },\n      unxkcdify: this.options.unxkcdify,\n      backgroundColor: this.options.backgroundColor,\n      strokeColor: this.options.strokeColor,\n    });\n\n    const xScale = scalePoint()\n      .domain(this.data.labels)\n      .range([0, this.width]);\n\n    const allData = this.data.datasets\n      .reduce((pre, cur) => pre.concat(cur.data), []);\n\n    const yScale = scaleLinear()\n      .domain([Math.min(...allData), Math.max(...allData)])\n      .range([this.height, 0]);\n\n    const graphPart = this.chart.append('g')\n      .attr('pointer-events', 'all');\n\n    // axis\n    addAxis.xAxis(graphPart, {\n      xScale,\n      tickCount: 3,\n      moveDown: this.height,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n    addAxis.yAxis(graphPart, {\n      yScale,\n      tickCount: this.options.yTickCount || 3,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n\n    this.svgEl.selectAll('.domain')\n      .attr('filter', this.filter);\n\n    const theLine = line()\n      .x((d, i) => xScale(this.data.labels[i]))\n      .y((d) => yScale(d))\n      .curve(monotoneX);\n\n    graphPart.selectAll('.xkcd-chart-line')\n      .data(this.data.datasets)\n      .enter()\n      .append('path')\n      .attr('class', 'xkcd-chart-line')\n      .attr('d', (d) => theLine(d.data))\n      .attr('fill', 'none')\n      .attr('stroke', (d, i) => this.options.dataColors[i])\n      .attr('filter', this.filter);\n\n    // hover effect\n    const verticalLine = graphPart.append('line')\n      .attr('x1', 30)\n      .attr('y1', 0)\n      .attr('x2', 30)\n      .attr('y2', this.height)\n      .attr('stroke', '#aaa')\n      .attr('stroke-width', 1.5)\n      .attr('stroke-dasharray', '7,7')\n      .style('visibility', 'hidden');\n\n    const circles = this.data.datasets.map((dataset, i) => graphPart\n      .append('circle')\n      .style('stroke', this.options.dataColors[i])\n      .style('fill', this.options.dataColors[i])\n      .attr('r', 3.5)\n      .style('visibility', 'hidden'));\n\n    graphPart.append('rect')\n      .attr('width', this.width)\n      .attr('height', this.height)\n      .attr('fill', 'none')\n      // .attr('stroke', 'black')\n      .on('mouseover', () => {\n        circles.forEach((circle) => circle.style('visibility', 'visible'));\n        verticalLine.style('visibility', 'visible');\n        tooltip.show();\n      })\n      .on('mouseout', () => {\n        circles.forEach((circle) => circle.style('visibility', 'hidden'));\n        verticalLine.style('visibility', 'hidden');\n        tooltip.hide();\n      })\n      .on('mousemove', (d, i, nodes) => {\n        const tipX = mouse(nodes[i])[0] + margin.left + 10;\n        const tipY = mouse(nodes[i])[1] + margin.top + 10;\n\n        const labelXs = this.data.labels.map((label) => xScale(label) + margin.left);\n        const mouseLableDistances = labelXs.map(\n          (labelX) => Math.abs(labelX - mouse(nodes[i])[0] - margin.left),\n        );\n        const mostNearLabelIndex = mouseLableDistances.indexOf(Math.min(...mouseLableDistances));\n\n        verticalLine\n          .attr('x1', xScale(this.data.labels[mostNearLabelIndex]))\n          .attr('x2', xScale(this.data.labels[mostNearLabelIndex]));\n\n        this.data.datasets.forEach((dataset, j) => {\n          circles[j]\n            .style('visibility', 'visible')\n            .attr('cx', xScale(this.data.labels[mostNearLabelIndex]))\n            .attr('cy', yScale(dataset.data[mostNearLabelIndex]));\n        });\n\n        const tooltipItems = this.data.datasets.map((dataset, j) => ({\n          color: this.options.dataColors[j],\n          text: `${this.data.datasets[j].label || ''}: ${this.data.datasets[j].data[mostNearLabelIndex]}`,\n        }));\n\n        let tooltipPositionType = config.positionType.downRight;\n        if (tipX > this.width / 2 && tipY < this.height / 2) {\n          tooltipPositionType = config.positionType.downLeft;\n        } else if (tipX > this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upLeft;\n        } else if (tipX < this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upRight;\n        }\n\n        tooltip.update({\n          title: this.data.labels[mostNearLabelIndex],\n          items: tooltipItems,\n          position: {\n            x: tipX,\n            y: tipY,\n            type: tooltipPositionType,\n          },\n        });\n      });\n\n    // Legend\n    if (this.options.showLegend) {\n      const legendItems = this.data.datasets\n        .map((dataset, i) => ({\n          color: this.options.dataColors[i],\n          text: dataset.label,\n        }));\n\n      addLegend(graphPart, {\n        items: legendItems,\n        position: this.options.legendPosition,\n        unxkcdify: this.options.unxkcdify,\n        parentWidth: this.width,\n        parentHeight: this.height,\n        backgroundColor: this.options.backgroundColor,\n        strokeColor: this.options.strokeColor,\n      });\n    }\n  }\n\n  // TODO: update chart\n  update() {\n  }\n}\n\nexport default Line;\n"
  },
  {
    "path": "src/Pie.js",
    "content": "import select from 'd3-selection/src/select';\nimport mouse from 'd3-selection/src/mouse';\nimport pie from 'd3-shape/src/pie';\nimport arc from 'd3-shape/src/arc';\nimport Tooltip from './components/Tooltip';\nimport addLegend from './utils/addLegend';\nimport addLabels from './utils/addLabels';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = 50;\n\nclass Pie {\n  constructor(svg, {\n    title, data: { labels, datasets }, options,\n  }) {\n    this.options = {\n      unxkcdify: false,\n      innerRadius: 0.5,\n      legendPosition: config.positionType.upLeft,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      showLegend: true,\n      ...options,\n    };\n    this.title = title;\n    this.data = {\n      labels,\n      datasets,\n    };\n    this.filter = 'url(#xkcdify-pie)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n\n    this.svgEl = select(svg)\n      .style('stroke-width', '3')\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n    this.svgEl.selectAll('*').remove();\n\n    this.width = this.svgEl.attr('width');\n    this.height = this.svgEl.attr('height');\n\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${this.width / 2},${this.height / 2})`);\n\n\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) {\n      addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    }\n\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: 'tooltip',\n      items: [{ color: 'red', text: 'weweyang: 12' }, { color: 'blue', text: 'timqian: 13' }],\n      position: { x: 30, y: 30, type: config.positionType.upRight },\n      unxkcdify: this.options.unxkcdify,\n      strokeColor: this.options.strokeColor,\n      backgroundColor: this.options.backgroundColor,\n    });\n\n    const radius = Math.min(this.width, this.height) / 2 - margin;\n\n    const thePie = pie();\n\n    const dataReady = thePie(this.data.datasets[0].data);\n\n    const theArc = arc()\n      .innerRadius(radius\n        * (this.options.innerRadius === undefined ? 0.5 : this.options.innerRadius))\n      .outerRadius(radius);\n\n    this.chart.selectAll('.xkcd-chart-arc')\n      .data(dataReady)\n      .enter()\n      .append('path')\n      .attr('class', '.xkcd-chart-arc')\n      .attr('d', theArc)\n      .attr('fill', 'none')\n      .attr('stroke', this.options.strokeColor)\n      .attr('stroke-width', 2)\n      .attr('fill', (d, i) => this.options.dataColors[i])\n      .attr('filter', this.filter)\n      // .attr(\"fill-opacity\", 0.6)\n      .on('mouseover', (d, i, nodes) => {\n        select(nodes[i]).attr('fill-opacity', 0.6);\n        tooltip.show();\n      })\n      .on('mouseout', (d, i, nodes) => {\n        select(nodes[i]).attr('fill-opacity', 1);\n        tooltip.hide();\n      })\n      .on('mousemove', (d, i, nodes) => {\n        const tipX = mouse(nodes[i])[0] + (this.width / 2) + 10;\n        const tipY = mouse(nodes[i])[1] + (this.height / 2) + 10;\n\n        tooltip.update({\n          title: this.data.labels[i],\n          items: [{\n            color: this.options.dataColors[i],\n            text: `${this.data.datasets[0].label || ''}: ${d.data}`,\n          }],\n          position: {\n            x: tipX,\n            y: tipY,\n            type: config.positionType.downRight,\n          },\n        });\n      });\n\n    // Legend\n    const legendItems = this.data.datasets[0].data\n      .map((data, i) => ({ color: this.options.dataColors[i], text: this.data.labels[i] }));\n\n    // move legend down to prevent overlaping with title\n    const legendG = this.svgEl.append('g')\n      .attr('transform', 'translate(0, 30)');\n\n    if (this.options.showLegend) {\n      addLegend(legendG, {\n        items: legendItems,\n        position: this.options.legendPosition,\n        unxkcdify: this.options.unxkcdify,\n        parentWidth: this.width,\n        parentHeight: this.height,\n        strokeColor: this.options.strokeColor,\n        backgroundColor: this.options.backgroundColor,\n      });\n    }\n  }\n\n  // TODO: update chart\n  update() {\n  }\n}\n\nexport default Pie;\n"
  },
  {
    "path": "src/Radar.js",
    "content": "import select from 'd3-selection/src/select';\nimport line from 'd3-shape/src/line';\nimport curveLinearClosed from 'd3-shape/src/curve/linearClosed';\nimport scaleLinear from 'd3-scale/src/linear';\nimport addLegend from './utils/addLegend';\nimport addLabels from './utils/addLabels';\nimport Tooltip from './components/Tooltip';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = 50;\nconst angleOffset = -Math.PI / 2;\nconst areaOpacity = 0.2;\n\nclass Radar {\n  constructor(svg, {\n    title,\n    data: { labels, datasets },\n    options,\n  }) {\n    this.options = {\n      showLabels: false,\n      ticksCount: 3,\n      showLegend: false,\n      legendPosition: config.positionType.upLeft,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      dotSize: 1,\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      ...options,\n    };\n    this.title = title;\n    this.data = {\n      labels,\n      datasets,\n    };\n    // TODO: find the longest dataset or throw an error for inconsistent datasets\n    this.directionsCount = datasets[0].data.length;\n    this.filter = 'url(#xkcdify-pie)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n    this.svgEl = select(svg)\n      .style('stroke-width', '3')\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n    this.svgEl.selectAll('*').remove();\n\n    this.width = this.svgEl.attr('width');\n    this.height = this.svgEl.attr('height');\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${this.width / 2},${this.height / 2})`);\n\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) {\n      addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    }\n\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: '',\n      items: [],\n      position: { x: 0, y: 0, type: config.positionType.downRight },\n      unxkcdify: this.options.unxkcdify,\n      strokeColor: this.options.strokeColor,\n      backgroundColor: this.options.backgroundColor,\n    });\n\n    const dotInitSize = 3.5 * (this.options.dotSize || 1);\n    const dotHoverSize = 6 * (this.options.dotSize || 1);\n    const radius = Math.min(this.width, this.height) / 2 - margin;\n    const angleStep = (Math.PI * 2) / this.directionsCount;\n\n    const allDataValues = this.data.datasets\n      .reduce((acc, cur) => acc.concat(cur.data), []);\n    const maxValue = Math.max(...allDataValues);\n    const allMaxData = Array(this.directionsCount).fill(maxValue);\n    const valueScale = scaleLinear()\n      .domain([0, maxValue])\n      .range([0, radius]);\n    const getX = (d, i) => valueScale(d) * Math.cos(angleStep * i + angleOffset);\n    const getY = (d, i) => valueScale(d) * Math.sin(angleStep * i + angleOffset);\n\n    const theLine = line()\n      .x(getX)\n      .y(getY)\n      .curve(curveLinearClosed);\n\n    // grid\n    const ticks = valueScale.ticks(this.options.ticksCount || 3);\n    const grid = this.chart.append('g')\n      .attr('class', 'xkcd-chart-radar-grid')\n      .attr('stroke-width', '1')\n      .attr('filter', this.filter);\n\n    grid.selectAll('.xkcd-chart-radar-level')\n      .data(ticks)\n      .enter()\n      .append('path')\n      .attr('class', 'xkcd-chart-radar-level')\n      .attr('d', (d) => theLine(Array(this.directionsCount).fill(d)))\n      .style('fill', 'none')\n      .attr('stroke', this.options.strokeColor)\n      .attr('stroke-dasharray', '7,7');\n\n    grid.selectAll('.xkcd-chart-radar-line')\n      .data(allMaxData)\n      .enter()\n      .append('line')\n      .attr('class', '.xkcd-chart-radar-line')\n      .attr('stroke', this.options.strokeColor)\n      .attr('x1', 0)\n      .attr('y1', 0)\n      .attr('x2', getX)\n      .attr('y2', getY);\n\n    grid.selectAll('.xkcd-chart-radar-tick')\n      .data(ticks)\n      .enter()\n      .append('text')\n      .attr('class', 'xkcd-chart-radar-tick')\n      .attr('x', (d) => getX(d, 0))\n      .attr('y', (d) => getY(d, 0))\n      .style('font-size', '16')\n      .style('fill', this.options.strokeColor)\n      .attr('text-anchor', 'end')\n      .attr('dx', '-.125em')\n      .attr('dy', '.35em')\n      .text((d) => d);\n\n    if (this.options.showLabels) {\n      grid.selectAll('.xkcd-chart-radar-label')\n        .data(allMaxData.map((d) => d * 1.15))\n        .enter()\n        .append('text')\n        .attr('class', 'xkcd-chart-radar-label')\n        .style('font-size', '16')\n        .style('fill', this.options.strokeColor)\n        .attr('x', (d, i) => (radius + 10) * Math.cos(angleStep * i + angleOffset))\n        .attr('y', (d, i) => (radius + 10) * Math.sin(angleStep * i + angleOffset))\n        .attr('dy', '.35em')\n        .attr('text-anchor', (d, i, nodes) => {\n          const node = select(nodes[i]);\n          let anchor = 'start';\n\n          if (node.attr('x') < 0) {\n            anchor = 'end';\n          }\n\n          return anchor;\n        })\n        .text((d, i) => this.data.labels[i]);\n    }\n\n    // layers\n    const layers = this.chart.selectAll('.xkcd-chart-radar-group')\n      .data(this.data.datasets)\n      .enter()\n      .append('g')\n      .attr('class', 'xkcd-chart-radar-group')\n      .attr('filter', this.filter)\n      .attr('stroke', (d, i) => this.options.dataColors[i])\n      .attr('fill', (d, i) => this.options.dataColors[i]);\n\n    layers.selectAll('circle')\n      .data((dataset) => dataset.data)\n      .enter()\n      .append('circle')\n      .attr('r', dotInitSize)\n      .attr('cx', getX)\n      .attr('cy', getY)\n      .attr('pointer-events', 'all')\n      .on('mouseover', (d, i, nodes) => {\n        select(nodes[i]).attr('r', dotHoverSize);\n\n        const tipX = getX(d, i) + this.width / 2;\n        const tipY = getY(d, i) + this.height / 2;\n        let tooltipPositionType = config.positionType.downRight;\n        if (tipX > this.width / 2 && tipY < this.height / 2) {\n          tooltipPositionType = config.positionType.downLeft;\n        } else if (tipX > this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upLeft;\n        } else if (tipX < this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upRight;\n        }\n        tooltip.update({\n          title: this.data.labels[i],\n          items: this.data.datasets.map((dataset, datasetIndex) => ({\n            color: this.options.dataColors[datasetIndex],\n            text: `${dataset.label || ''}: ${dataset.data[i]}`,\n          })),\n          position: {\n            x: tipX,\n            y: tipY,\n            type: tooltipPositionType,\n          },\n        });\n        tooltip.show();\n      })\n      .on('mouseout', (d, i, nodes) => {\n        select(nodes[i]).attr('r', dotInitSize);\n\n        tooltip.hide();\n      });\n\n    layers.selectAll('path')\n      .data((dataset) => ([dataset.data]))\n      .enter()\n      .append('path')\n      .attr('d', theLine)\n      .attr('pointer-events', 'none')\n      .style('fill-opacity', areaOpacity);\n\n    // legend\n    if (this.options.showLegend) {\n      const legendItems = this.data.datasets\n        .map((data, i) => ({ color: this.options.dataColors[i], text: data.label || '' }));\n\n      // move legend down to prevent overlaping with title\n      const legendG = this.svgEl.append('g')\n        .attr('transform', 'translate(0, 30)');\n\n      addLegend(legendG, {\n        items: legendItems,\n        position: this.options.legendPosition,\n        unxkcdify: this.options.unxkcdify,\n        parentWidth: this.width,\n        parentHeight: this.height,\n        backgroundColor: this.options.backgroundColor,\n        strokeColor: this.options.strokeColor,\n      });\n    }\n  }\n\n  update() {\n  }\n}\n\nexport default Radar;\n"
  },
  {
    "path": "src/StackedBar.js",
    "content": "import select from 'd3-selection/src/select';\nimport mouse from 'd3-selection/src/mouse';\nimport scaleBand from 'd3-scale/src/band';\nimport scaleLinear from 'd3-scale/src/linear';\n\nimport addAxis from './utils/addAxis';\nimport addLabels from './utils/addLabels';\nimport Tooltip from './components/Tooltip';\nimport addLegend from './utils/addLegend';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = {\n  top: 50, right: 30, bottom: 50, left: 50,\n};\n\nclass StackedBar {\n  constructor(svg, {\n    title, xLabel, yLabel, data: { labels, datasets }, options,\n  }) {\n    this.options = {\n      unxkcdify: false,\n      yTickCount: 3,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      legendPosition: config.positionType.upLeft,\n      showLegend: true,\n      ...options,\n    };\n    if (title) {\n      this.title = title;\n      margin.top = 60;\n    }\n    if (xLabel) {\n      this.xLabel = xLabel;\n      margin.bottom = 50;\n    }\n    if (yLabel) {\n      this.yLabel = yLabel;\n      margin.left = 70;\n    }\n    this.data = {\n      labels,\n      datasets,\n    };\n    this.filter = 'url(#xkcdify)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n\n    this.svgEl = select(svg)\n      .style('stroke-width', '3')\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n\n    this.svgEl.selectAll('*').remove();\n\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${margin.left},${margin.top})`);\n    this.width = this.svgEl.attr('width') - margin.left - margin.right;\n    this.height = this.svgEl.attr('height') - margin.top - margin.bottom;\n\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    if (this.xLabel) addLabels.xLabel(this.svgEl, this.xLabel, this.options.strokeColor);\n    if (this.yLabel) addLabels.yLabel(this.svgEl, this.yLabel, this.options.strokeColor);\n\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: 'tooltip',\n      items: [{ color: 'red', text: 'weweyang: 12' }, { color: 'blue', text: 'timqian: 13' }],\n      position: { x: 30, y: 30, type: config.positionType.upRight },\n      unxkcdify: this.options.unxkcdify,\n      backgroundColor: this.options.backgroundColor,\n      strokeColor: this.options.strokeColor,\n    });\n\n    const xScale = scaleBand()\n      .range([0, this.width])\n      .domain(this.data.labels)\n      .padding(0.4);\n\n    const allCols = this.data.datasets\n      .reduce((r, a) => a.data.map((b, i) => (r[i] || 0) + b), []);\n\n    const yScale = scaleLinear()\n      .domain([0, Math.max(...allCols)])\n      .range([this.height, 0]);\n\n    const graphPart = this.chart.append('g');\n\n    // axis\n    addAxis.xAxis(graphPart, {\n      xScale,\n      tickCount: 3,\n      moveDown: this.height,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n    addAxis.yAxis(graphPart, {\n      yScale,\n      tickCount: this.options.yTickCount || 3,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n\n    // Merge all the lists into a single list, and store the\n    // offests in a corresponding list.  Use dataLength to\n    // track how many total columns there should be.\n    const mergedData = this.data.datasets\n      .reduce((pre, cur) => pre.concat(cur.data), []);\n\n    const dataLength = this.data.datasets[0].data.length;\n\n    const offsets = this.data.datasets\n      .reduce((r, x, i) => {\n        if (i > 0) {\n          r.push(x.data.map((y, j) => this.data.datasets[i - 1].data[j] + r[i - 1][j]));\n        } else {\n          r.push(new Array(x.data.length).fill(0));\n        }\n        return r;\n      }, []).flat();\n\n    // Bars\n    graphPart.selectAll('.xkcd-chart-stacked-bar')\n      .data(mergedData)\n      .enter()\n      .append('rect')\n      .attr('class', 'xkcd-chart-stacked-bar')\n      .attr('x', (d, i) => xScale(this.data.labels[i % dataLength]))\n      .attr('width', xScale.bandwidth())\n      .attr('y', (d, i) => yScale(d + offsets[i]))\n      .attr('height', (d) => this.height - yScale(d))\n      .attr('fill', (d, i) => this.options.dataColors[Math.floor(i / dataLength)])\n      .attr('pointer-events', 'all')\n      .attr('stroke', this.options.strokeColor)\n      .attr('stroke-width', 3)\n      .attr('rx', 2)\n      .attr('filter', this.filter)\n      .on('mouseover', () => tooltip.show())\n      .on('mouseout', () => tooltip.hide())\n      .on('mousemove', (d, i, nodes) => {\n        const tipX = mouse(nodes[i])[0] + margin.left + 10;\n        const tipY = mouse(nodes[i])[1] + margin.top + 10;\n\n        const tooltipItems = this.data.datasets.map((dataset, j) => ({\n          color: this.options.dataColors[j],\n          text: `${this.data.datasets[j].label || ''}: ${this.data.datasets[j].data[i % dataLength]}`,\n        })).reverse();\n\n        let tooltipPositionType = config.positionType.downRight;\n        if (tipX > this.width / 2 && tipY < this.height / 2) {\n          tooltipPositionType = config.positionType.downLeft;\n        } else if (tipX > this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upLeft;\n        } else if (tipX < this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upRight;\n        }\n\n        tooltip.update({\n          title: this.data.labels[i],\n          items: tooltipItems,\n          position: {\n            x: tipX,\n            y: tipY,\n            type: tooltipPositionType,\n          },\n        });\n      });\n\n    if (this.options.showLegend) {\n      const legendItems = this.data.datasets.map((dataset, j) => ({\n        color: this.options.dataColors[j],\n        text: `${this.data.datasets[j].label || ''}`,\n      })).reverse();\n\n      addLegend(graphPart, {\n        items: legendItems,\n        position: this.options.legendPosition,\n        unxkcdify: this.options.unxkcdify,\n        parentWidth: this.width,\n        parentHeight: this.height,\n        strokeColor: this.options.strokeColor,\n        backgroundColor: this.options.backgroundColor,\n      });\n    }\n  }\n\n  // TODO: update chart\n  update() {\n\n  }\n}\n\nexport default StackedBar;\n"
  },
  {
    "path": "src/XY.js",
    "content": "import line from 'd3-shape/src/line';\nimport { monotoneX } from 'd3-shape/src/curve/monotone';\nimport select from 'd3-selection/src/select';\nimport scaleLinear from 'd3-scale/src/linear';\nimport scaleTime from 'd3-scale/src/time';\nimport dayjs from 'dayjs';\n\nimport addAxis from './utils/addAxis';\nimport addLabels from './utils/addLabels';\nimport Tooltip from './components/Tooltip';\nimport addLegend from './utils/addLegend';\nimport addFont from './utils/addFont';\nimport addFilter from './utils/addFilter';\nimport colors from './utils/colors';\nimport config from './config';\n\nconst margin = {\n  top: 50, right: 30, bottom: 50, left: 50,\n};\n\nclass XY {\n  constructor(svg, {\n    title, xLabel, yLabel, data: { datasets }, options,\n  }) {\n    this.options = {\n      unxkcdify: false,\n      dotSize: 1,\n      showLine: false,\n      timeFormat: '',\n      xTickCount: 3,\n      yTickCount: 3,\n      legendPosition: config.positionType.upLeft,\n      dataColors: colors,\n      fontFamily: 'xkcd',\n      strokeColor: 'black',\n      backgroundColor: 'white',\n      showLegend: true,\n      ...options,\n    };\n    // TODO: extract a function?\n    if (title) {\n      this.title = title;\n      margin.top = 60;\n    }\n    if (xLabel) {\n      this.xLabel = xLabel;\n      margin.bottom = 50;\n    }\n    if (yLabel) {\n      this.yLabel = yLabel;\n      margin.left = 70;\n    }\n    this.data = {\n      datasets,\n    };\n\n    this.filter = 'url(#xkcdify)';\n    this.fontFamily = this.options.fontFamily || 'xkcd';\n    if (this.options.unxkcdify) {\n      this.filter = null;\n      this.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n    }\n\n    this.svgEl = select(svg)\n      .style('stroke-width', 3)\n      .style('font-family', this.fontFamily)\n      .style('background', this.options.backgroundColor)\n      .attr('width', svg.parentElement.clientWidth)\n      .attr('height', Math.min((svg.parentElement.clientWidth * 2) / 3, window.innerHeight));\n    this.svgEl.selectAll('*').remove();\n\n    this.chart = this.svgEl.append('g')\n      .attr('transform',\n        `translate(${margin.left},${margin.top})`);\n\n    this.width = this.svgEl.attr('width') - margin.left - margin.right;\n    this.height = this.svgEl.attr('height') - margin.top - margin.bottom;\n    addFont(this.svgEl);\n    addFilter(this.svgEl);\n    this.render();\n  }\n\n  render() {\n    if (this.title) addLabels.title(this.svgEl, this.title, this.options.strokeColor);\n    if (this.xLabel) addLabels.xLabel(this.svgEl, this.xLabel, this.options.strokeColor);\n    if (this.yLabel) addLabels.yLabel(this.svgEl, this.yLabel, this.options.strokeColor);\n\n    const tooltip = new Tooltip({\n      parent: this.svgEl,\n      title: '',\n      items: [{ color: 'red', text: 'weweyang' }, { color: 'blue', text: 'timqian' }],\n      position: { x: 60, y: 60, type: config.positionType.dowfnRight },\n      unxkcdify: this.options.unxkcdify,\n      strokeColor: this.options.strokeColor,\n      backgroundColor: this.options.backgroundColor,\n    });\n\n    if (this.options.timeFormat) {\n      this.data.datasets.forEach((dataset) => {\n        dataset.data.forEach((d) => {\n          // eslint-disable-next-line no-param-reassign\n          d.x = dayjs(d.x);\n        });\n      });\n    }\n\n    const allData = this.data.datasets\n      .reduce((pre, cur) => pre.concat(cur.data), []);\n\n    const allDataX = allData.map((d) => d.x);\n    const allDataY = allData.map((d) => d.y);\n\n    let xScale = scaleLinear()\n      .domain([Math.min(...allDataX), Math.max(...allDataX)])\n      .range([0, this.width]);\n\n    if (this.options.timeFormat) {\n      xScale = scaleTime()\n        .domain([Math.min(...allDataX), Math.max(...allDataX)])\n        .range([0, this.width]);\n    }\n\n    const yScale = scaleLinear()\n      .domain([Math.min(...allDataY), Math.max(...allDataY)])\n      .range([this.height, 0]);\n\n    const graphPart = this.chart.append('g')\n      .attr('pointer-events', 'all');\n\n    // axis\n    addAxis.xAxis(graphPart, {\n      xScale,\n      tickCount: this.options.xTickCount === undefined ? 3 : this.options.xTickCount,\n      moveDown: this.height,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n    addAxis.yAxis(graphPart, {\n      yScale,\n      tickCount: this.options.yTickCount === undefined ? 3 : this.options.yTickCount,\n      fontFamily: this.fontFamily,\n      unxkcdify: this.options.unxkcdify,\n      stroke: this.options.strokeColor,\n    });\n\n    // lines\n    if (this.options.showLine) {\n      const theLine = line()\n        .x((d) => xScale(d.x))\n        .y((d) => yScale(d.y))\n        .curve(monotoneX);\n\n      graphPart.selectAll('.xkcd-chart-xyline')\n        .data(this.data.datasets)\n        .enter()\n        .append('path')\n        .attr('class', 'xkcd-chart-xyline')\n        .attr('d', (d) => theLine(d.data))\n        .attr('fill', 'none')\n        .attr('stroke', (d, i) => (this.options.dataColors[i]))\n        .attr('filter', this.filter);\n    }\n\n    // dots\n    const dotInitSize = 3.5 * (this.options.dotSize === undefined ? 1 : this.options.dotSize);\n    const dotHoverSize = 6 * (this.options.dotSize === undefined ? 1 : this.options.dotSize);\n    graphPart.selectAll('.xkcd-chart-xycircle-group')\n      .data(this.data.datasets)\n      .enter()\n      .append('g')\n      .attr('class', '.xkcd-chart-xycircle-group')\n      .attr('filter', this.filter)\n      .attr('xy-group-index', (d, i) => i)\n      .selectAll('.xkcd-chart-xycircle-circle')\n      .data((dataset) => dataset.data)\n      .enter()\n      .append('circle')\n      .style('stroke', (d, i, nodes) => {\n        // FIXME: here I want to pass xyGroupIndex down to the circles by reading parent attrs\n        // It might have perfomance issue with a large dataset, not sure there are better ways\n        const xyGroupIndex = Number(select(nodes[i].parentElement).attr('xy-group-index'));\n        return this.options.dataColors[xyGroupIndex];\n      })\n      .style('fill', (d, i, nodes) => {\n        const xyGroupIndex = Number(select(nodes[i].parentElement).attr('xy-group-index'));\n        return this.options.dataColors[xyGroupIndex];\n      })\n      .attr('r', dotInitSize)\n      .attr('cx', (d) => xScale(d.x))\n      .attr('cy', (d) => yScale(d.y))\n      .attr('pointer-events', 'all')\n      .on('mouseover', (d, i, nodes) => {\n        const xyGroupIndex = Number(select(nodes[i].parentElement).attr('xy-group-index'));\n        select(nodes[i])\n          .attr('r', dotHoverSize);\n\n        const tipX = xScale(d.x) + margin.left + 5;\n        const tipY = yScale(d.y) + margin.top + 5;\n        let tooltipPositionType = config.positionType.downRight;\n        if (tipX > this.width / 2 && tipY < this.height / 2) {\n          tooltipPositionType = config.positionType.downLeft;\n        } else if (tipX > this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upLeft;\n        } else if (tipX < this.width / 2 && tipY > this.height / 2) {\n          tooltipPositionType = config.positionType.upRight;\n        }\n        tooltip.update({\n          title: this.options.timeFormat ? dayjs(this.data.datasets[xyGroupIndex].data[i].x).format(this.options.timeFormat) : `${this.data.datasets[xyGroupIndex].data[i].x}`,\n          items: [{\n            color: this.options.dataColors[xyGroupIndex],\n            text: `${this.data.datasets[xyGroupIndex].label || ''}: ${d.y}`,\n          }],\n          position: {\n            x: tipX,\n            y: tipY,\n            type: tooltipPositionType,\n          },\n        });\n        tooltip.show();\n      })\n      .on('mouseout', (d, i, nodes) => {\n        select(nodes[i])\n          .attr('r', dotInitSize);\n\n        tooltip.hide();\n      });\n\n    // Legend\n    if (this.options.showLegend) {\n      const legendItems = this.data.datasets.map(\n        (dataset, i) => ({\n          color: this.options.dataColors[i],\n          text: dataset.label,\n        }),\n      );\n\n      addLegend(graphPart, {\n        items: legendItems,\n        position: this.options.legendPosition,\n        unxkcdify: this.options.unxkcdify,\n        parentWidth: this.width,\n        parentHeight: this.height,\n        strokeColor: this.options.strokeColor,\n        backgroundColor: this.options.backgroundColor,\n      });\n    }\n  }\n\n  // TODO: update chart\n  update() {\n  }\n}\n\nexport default XY;\n"
  },
  {
    "path": "src/components/Tooltip.js",
    "content": "/* eslint-disable no-underscore-dangle */\nimport config from '../config';\n\nclass Tooltip {\n  /**\n   *\n   * @param {String} parent\n   * @param {String} title\n   * @param {Array} items\n   * @param {Object} position\n   * @example\n   * {\n   *    parent: {}, // a d3 selection component\n   *    title: 'tooltip title',\n   *    items:[{\n   *      color: 'red',\n   *      text: 'tim: 13'\n   *    }],\n   *    position: {\n   *      type: 'upleft'\n   *      x: 100,\n   *      y: 230,\n   *    }\n   * }\n   */\n  constructor({\n    parent, title, items, position, unxkcdify, backgroundColor, strokeColor,\n  }) {\n    this.title = title;\n    this.items = items;\n    this.position = position;\n    this.filter = !unxkcdify ? 'url(#xkcdify)' : null;\n    this.backgroundColor = backgroundColor;\n    this.strokeColor = strokeColor;\n\n    this.svg = parent.append('svg')\n      .attr('x', this._getUpLeftX())\n      .attr('y', this._getUpLeftY())\n      .style('visibility', 'hidden');\n\n    this.tipBackground = this.svg.append('rect')\n      .style('fill', this.backgroundColor)\n      .attr('fill-opacity', 0.9)\n      .attr('stroke', strokeColor) // FIXME: find a good way to calculate boder color form this.strokeColor\n      .attr('stroke-width', 2)\n      .attr('rx', 5)\n      .attr('ry', 5)\n      .attr('filter', this.filter)\n      .attr('width', this._getBackgroundWidth())\n      .attr('height', this._getBackgroundHeight())\n      .attr('x', 5)\n      .attr('y', 5);\n\n    this.tipTitle = this.svg.append('text')\n      .style('font-size', 15)\n      .style('font-weight', 'bold')\n      .style('fill', this.strokeColor)\n      .attr('x', 15)\n      .attr('y', 25)\n      .text(title);\n\n    this.tipItems = items.map((item, i) => {\n      const g = this._generateTipItem(item, i);\n      return g;\n    });\n  }\n\n  show() {\n    this.svg.style('visibility', 'visible');\n  }\n\n  hide() {\n    this.svg.style('visibility', 'hidden');\n  }\n\n  // update tooltip position / content\n  update({ title, items, position }) {\n    if (title && title !== this.title) {\n      this.title = title;\n      this.tipTitle.text(title);\n    }\n\n    if (items && JSON.stringify(items) !== JSON.stringify(this.items)) {\n      this.items = items;\n\n      this.tipItems.forEach((g) => g.svg.remove());\n\n      this.tipItems = this.items.map((item, i) => {\n        const g = this._generateTipItem(item, i);\n        return g;\n      });\n\n      const maxWidth = Math.max(\n        ...this.tipItems.map((item) => item.width),\n        this.tipTitle.node().getBBox().width,\n      );\n\n      this.tipBackground\n        .attr('width', maxWidth + 15)\n        .attr('height', this._getBackgroundHeight());\n    }\n\n    if (position) {\n      this.position = position;\n      this.svg.attr('x', this._getUpLeftX());\n      this.svg.attr('y', this._getUpLeftY());\n    }\n  }\n\n  _generateTipItem(item, i) {\n    const svg = this.svg.append('svg');\n\n    svg.append('rect')\n      .style('fill', item.color)\n      .attr('width', 8)\n      .attr('height', 8)\n      .attr('rx', 2)\n      .attr('ry', 2)\n      .attr('filter', this.filter)\n      .attr('x', 15)\n      .attr('y', 37 + 20 * i);\n\n    svg.append('text')\n      .style('font-size', '15')\n      .style('fill', this.strokeColor)\n      .attr('x', 15 + 12)\n      .attr('y', 37 + 20 * i + 8)\n      .text(item.text);\n\n    const bbox = svg.node().getBBox();\n    const width = bbox.width + 15;\n    const height = bbox.height + 10;\n    return {\n      svg,\n      width,\n      height,\n    };\n  }\n\n  _getBackgroundWidth() {\n    const maxItemLength = this.items.reduce(\n      (pre, cur) => (pre > cur.text.length ? pre : cur.text.length), 0,\n    );\n    const maxLength = Math.max(maxItemLength, this.title.length);\n\n    return maxLength * 7.4 + 25;\n  }\n\n  _getBackgroundHeight() {\n    const rows = this.items.length + 1;\n    return rows * 20 + 10;\n  }\n\n  _getUpLeftX() {\n    if (this.position.type === config.positionType.upRight\n      || this.position.type === config.positionType.downRight) {\n      return this.position.x;\n    }\n    return this.position.x - this._getBackgroundWidth() - 20;\n  }\n\n  _getUpLeftY() {\n    if (this.position.type === config.positionType.downLeft\n      || this.position.type === config.positionType.downRight) {\n      return this.position.y;\n    }\n    return this.position.y - this._getBackgroundHeight() - 20;\n  }\n}\n\nexport default Tooltip;\n"
  },
  {
    "path": "src/config.js",
    "content": "const config = {\n  positionType: {\n    upLeft: 1,\n    upRight: 2,\n    downLeft: 3,\n    downRight: 4,\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "src/index.js",
    "content": "import Bar from './Bar';\nimport StackedBar from './StackedBar';\nimport Pie from './Pie';\nimport Line from './Line';\nimport XY from './XY';\nimport Radar from './Radar';\nimport config from './config';\n\nmodule.exports = {\n  config, Bar, StackedBar, Pie, Line, XY, Radar,\n};\n"
  },
  {
    "path": "src/utils/addAxis.js",
    "content": "import { axisBottom, axisLeft } from 'd3-axis/src/axis';\n\nconst yAxis = (parent, {\n  yScale, tickCount, fontFamily, unxkcdify, stroke,\n}) => {\n  parent\n    .append('g')\n    .call(\n      axisLeft(yScale)\n        .tickSize(1)\n        .tickPadding(10)\n        .ticks(tickCount, 's'),\n    );\n\n  parent.selectAll('.domain')\n    .attr('filter', !unxkcdify ? 'url(#xkcdify)' : null)\n    .style('stroke', stroke);\n\n  parent.selectAll('.tick > text')\n    .style('font-family', fontFamily)\n    .style('font-size', '16')\n    .style('fill', stroke);\n};\n\nconst xAxis = (parent, {\n  xScale, tickCount, moveDown, fontFamily, unxkcdify, stroke,\n}) => {\n  parent\n    .append('g')\n    .attr('transform', `translate(0,${moveDown})`)\n    .call(\n      axisBottom(xScale)\n        .tickSize(0)\n        .tickPadding(6)\n        .ticks(tickCount),\n    );\n\n  parent.selectAll('.domain')\n    .attr('filter', !unxkcdify ? 'url(#xkcdify)' : null)\n    .style('stroke', stroke);\n\n  parent.selectAll('.tick > text')\n    .style('font-family', fontFamily)\n    .style('font-size', '16')\n    .style('fill', stroke);\n};\n\nexport default {\n  xAxis, yAxis,\n};\n"
  },
  {
    "path": "src/utils/addFilter.js",
    "content": "export default function addFilter(parent) {\n  parent.append('filter')\n    .attr('id', 'xkcdify')\n    .attr('filterUnits', 'userSpaceOnUse')\n    .attr('x', -5)\n    .attr('y', -5)\n    .attr('width', '100%')\n    .attr('height', '100%')\n    .call((f) => f.append('feTurbulence')\n      .attr('type', 'fractalNoise')\n      .attr('baseFrequency', '0.05')\n      .attr('result', 'noise'))\n    .call((f) => f.append('feDisplacementMap')\n      .attr('scale', '5')\n      .attr('xChannelSelector', 'R')\n      .attr('yChannelSelector', 'G')\n      .attr('in', 'SourceGraphic')\n      .attr('in2', 'noise'));\n\n  parent.append('filter')\n    .attr('id', 'xkcdify-pie')\n    .call((f) => f.append('feTurbulence')\n      .attr('type', 'fractalNoise')\n      .attr('baseFrequency', '0.05')\n      .attr('result', 'noise'))\n    .call((f) => f.append('feDisplacementMap')\n      .attr('scale', '5')\n      .attr('xChannelSelector', 'R')\n      .attr('yChannelSelector', 'G')\n      .attr('in', 'SourceGraphic')\n      .attr('in2', 'noise'));\n\n  // TODO bar chart hatch effect\n  // parent.append('pattern')\n  //   .attr('id', 'hatch00')\n  //   .attr('patternUnits', 'userSpaceOnUse')\n  //   .attr('x', 0)\n  //   .attr('y', 0)\n  //   .attr('width', 10)\n  //   .attr('height', 10)\n  //   .call((f) => f.append('path')\n  //     .attr('d', 'M3,0 l7,7 l0,-2 l-5,-5 l-2,0 M0,7 l3,3 l2,0 l-5,-5 l0,2')\n  //     .attr('fill', colors[1])\n  //     .attr('stroke', 'none'));\n}\n"
  },
  {
    "path": "src/utils/addFont.js",
    "content": "export default function addFont(parent) {\n  parent.append('defs')\n    .append('style')\n    .attr('type', 'text/css')\n    .text(`@font-face {\n      font-family: \"xkcd\";\n      src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff');\n    }`);\n}\n"
  },
  {
    "path": "src/utils/addLabels.js",
    "content": "const title = (parent, text, fill) => {\n  parent\n    .append('text')\n    .style('font-size', '20')\n    .style('font-weight', 'bold')\n    .style('fill', fill)\n    .attr('x', '50%')\n    .attr('y', 30)\n    .attr('text-anchor', 'middle')\n    .text(text);\n};\n\nconst xLabel = (parent, text, fill) => {\n  parent\n    .append('text')\n    .style('font-size', 17)\n    .style('fill', fill)\n    .attr('x', '50%')\n    .attr('y', parent.attr('height') - 10)\n    .attr('text-anchor', 'middle')\n    .text(text);\n};\n\nconst yLabel = (parent, text, fill) => {\n  parent\n    .append('text')\n    .attr('text-anchor', 'end')\n    .attr('dy', '.75em')\n    .attr('transform', 'rotate(-90)')\n    .style('font-size', 17)\n    .style('fill', fill)\n    .text(text)\n    .attr('y', 6)\n    .call((f) => {\n      const textLength = f.node().getComputedTextLength();\n      f.attr('x', 0 - (parent.attr('height') / 2) + (textLength / 2));\n    });\n};\n\nexport default {\n  title, xLabel, yLabel,\n};\n"
  },
  {
    "path": "src/utils/addLegend.js",
    "content": "import config from '../config';\n\nexport default async function addLegend(parent, {\n  items, position, unxkcdify, parentWidth, parentHeight, strokeColor, backgroundColor,\n}) {\n  const filter = !unxkcdify ? 'url(#xkcdify)' : null;\n\n  const legend = parent.append('svg');\n  const backgroundLayer = legend.append('svg');\n  const textLayer = legend.append('svg');\n\n  items.forEach((item, i) => {\n    textLayer.append('rect')\n      .style('fill', item.color)\n      .attr('width', 8)\n      .attr('height', 8)\n      .attr('filter', filter)\n      .attr('rx', 2)\n      .attr('ry', 2)\n      .attr('x', 15)\n      .attr('y', 17 + 20 * i);\n\n    textLayer.append('text')\n      .style('font-size', '15')\n      .style('fill', strokeColor)\n      .attr('x', 15 + 12)\n      .attr('y', 17 + 20 * i + 8)\n      .text(item.text);\n  });\n\n  // wait for textLayer to render, a bit wired\n  await new Promise(resolve => setTimeout(resolve, 10))\n\n  const bbox = textLayer.node().getBBox();\n  const backgroundWidth = bbox.width + 15;\n  const backgroundHeight = bbox.height + 10;\n\n  let legendX = 0;\n  let legendY = 0;\n  if (\n    position === config.positionType.downLeft\n    || position === config.positionType.downRight\n  ) {\n    legendY = parentHeight - backgroundHeight - 13;\n  }\n  if (\n    position === config.positionType.upRight\n    || position === config.positionType.downRight\n  ) {\n    legendX = parentWidth - backgroundWidth - 13;\n  }\n\n  // add background\n  backgroundLayer.append('rect')\n    .style('fill', backgroundColor)\n    .attr('filter', filter)\n    .attr('fill-opacity', 0.85)\n    .attr('stroke', strokeColor)\n    .attr('stroke-width', 2)\n    .attr('width', backgroundWidth)\n    .attr('height', backgroundHeight)\n    .attr('rx', 5)\n    .attr('ry', 5)\n    .attr('x', 8)\n    .attr('y', 5);\n\n  // get legend\n  legend\n    .attr('x', legendX)\n    .attr('y', legendY);\n}\n"
  },
  {
    "path": "src/utils/colors.js",
    "content": "// TODO: use: https://github.com/mrmrs/colors ?\n// use: https://gui.apex.sh/\nexport default ['#dd4528', '#28a3dd', '#f3db52', '#ed84b5', '#4ab74e', '#9179c0', '#8e6d5a', '#f19839', '#949494'];\n"
  }
]