[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"es2015\", \"stage-0\", \"react\"],\n  \"env\": {\n    \"test\": {\n      \"presets\": [\"es2015\", \"stage-0\", \"react\"]\n    }\n  }\n}"
  },
  {
    "path": ".eslintignore",
    "content": "benchmark\ndist"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"jest\": true,\n    \"es6\": true\n  },\n  \"parser\": \"babel-eslint\",\n  \"parserOptions\": {\n    \"sourceType\": \"module\"\n  },\n  \"extends\": [\n    \"eslint-config-airbnb\"\n  ],\n  \"globals\": {\n  },\n  \"rules\": {\n    \"comma-dangle\": 0,\n    \"consistent-return\": 0,\n    \"func-names\": 0,\n    \"global-require\": 0,\n    \"import/no-extraneous-dependencies\": 0,\n    \"import/no-unresolved\": 0,\n    \"indent\": 0,\n    \"key-spacing\": 0,\n    \"linebreak-style\": 0,\n    \"new-cap\": 0,\n    \"no-cond-assign\": 0,\n    \"no-empty\": 0,\n    \"no-fallthrough\": 0,\n    \"no-loop-func\": 0,\n    \"no-mixed-operators\": 0,\n    \"no-new\": 0,\n    \"no-param-reassign\": 0,\n    \"no-restricted-syntax\": 0,\n    \"no-return-assign\": 0,\n    \"no-underscore-dangle\": 0,\n    \"object-curly-spacing\": 0,\n    \"prefer-rest-params\": 0,\n    \"react/jsx-filename-extension\": 0,\n    \"react/jsx-space-before-closing\": 0,\n    \"strict\": 0,\n    \"max-len\": [\n      2,\n      120,\n      4,\n      {\n        \"ignoreUrls\": true\n      }\n    ],\n    \"id-length\": [\n      2,\n      {\n        \"min\": 1\n      }\n    ],\n    \"class-methods-use-this\": [\n      1,\n      {\n        \"exceptMethods\": [\n          \"CLASSNAME\"\n        ]\n      }\n    ]\n  }\n}"
  },
  {
    "path": ".gitignore",
    "content": ".idea\ncoverage\nnode_modules\n.coveralls.yml\nnpm-debug.*\nl.js\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - '4'\n  - '4'\n  - '5'\n  - '6'\n  - '7'\n  - '8'\nafter_success:\n  - npm run coveralls"
  },
  {
    "path": "README.md",
    "content": "# tcharts.js\n\n> [TCharts.js](http://tcharts.org) is a Lightweight and fast terminal ASCII charts for nodejs and browser.\n\n[![Ver](https://img.shields.io/npm/v/tcharts.js.svg)](https://www.npmjs.com/package/tcharts.js) [![Build Status](https://travis-ci.org/ProtoTeam/tcharts.js.svg?branch=master)](https://travis-ci.org/ProtoTeam/tcharts.js) [![Coverage Status](https://coveralls.io/repos/github/ProtoTeam/tcharts.js/badge.svg?branch=master)](https://coveralls.io/github/ProtoTeam/tcharts.js)\n\n```\n    +--------------+----------------------+---------------------+\n    |              |                      |                     |\n    |              |                      |                     |\n    |              |                      |                     |\n    |              |                      |                     |\n    |              |                      |                     |\n    |              |                      |                     |\n    |              |        C:25%         |      Hello:25%      |\n    |              |                      |                     |\n    |              |                      |                     |\n    |    A:25%     |                      |                     |\n    |              |                      |                     |\n    |              |                      |                     |\n    |              +----------------------+---------------------+\n    |              |                                            |\n    |              |                                            |\n    |              |                                            |\n    |              |                   B:25%                    |\n    |              |                                            |\n    |              |                                            |\n    +--------------+--------------------------------------------+\n\n```\n\n\n## 1. Install & Usage\n\n> npm i -S tcharts.js\n\n\n### Table\n\n```js\nconst TCharts = require('tcharts.js');\nconst { Table } = TCharts;\n\nconst table = new Table(0.2); // set gap rate = 0.2\ntable.setData([\n  ['標識符', '名字', '生日'],\n  ['#1', '圖靈', 24],\n  ['#2', '潘金蓮', false],\n  ['#3', '西門慶', null],\n  ['#4', '明日花绮罗'],\n]);\nconsole.log(table.string());\n```\n\n### Bar\n\n```js\nconst TCharts = require('tcharts.js');\nconst { Bar } = TCharts;\n\nconst bar = new Bar();\nbar.setData([\n  {value:100, name:'A'},\n  {value:45, name:'B'},\n  {value:70, name:'C'},\n  {value:30, name:'D'},\n]);\nconsole.log(bar.string());\n```\n\n### HBar\n\n```js\nconst TCharts = require('tcharts.js');\nconst { HBar } = TCharts;\n\nconst hbar = new HBar();\nhbar.setData([\n  {value: 100, name: 'A'},\n  {value: 45, name: 'B'},\n  {value: 70, name: 'C'},\n  {value: 30, name: 'D'},\n]);\nconsole.log(hbar.string());\n\n```\n\n### Box\n\n```js\nconst TCharts = require('tcharts.js');\nconst { Box } = TCharts;\n\nconst box = new Box(60, 20); // width, height\nbox.setData([\n  {value:100, name:'A'},\n  {value:100, name:'B'},\n  {value:100, name:'C'},\n  {value:100, name:'Hello'},\n]);\nconsole.log(box.string());\n```\n\n\n## 2. Supported charts\n\n - `Bar`: bar chart, with x, y.\n - `HBar`: horizontal bar chart.\n - `Box`: box chart showing with a square.\n - `Table`: data table in terminal.\n\nHow to use them, you can see the testcases in `__tests__` folder.\n\n\n## 3. Build & Test\n\n```\nnpm i\n\nnpm run build\n\nnpm test\n```\n\nThen you can see the result of test cases.\n\n\n## 4. License\n\nISC@[ProtoTeam](https://github.com/ProtoTeam).\n\n\n"
  },
  {
    "path": "__tests__/axis.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (Point, Axis) => {\n  test('1. draw a axis element.', () => {\n    const point0 = new Point(0, 0);\n    const pointX = new Point(20, 0);\n    const pointY = new Point(0, 5);\n    const axis = new Axis(point0, pointX, pointY);\n    console.log(axis.toString());\n    const axisLayer = axis.draw();\n\n    expect(axisLayer.box).toEqual({\n      x1: 0,\n      y1: 0,\n      x2: 20,\n      y2: 5,\n    });\n    expect(axisLayer.array()).toEqual([\n      '^                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '+------------------->'.split(''),\n    ]);\n    expect(axis.clone().draw().array()).toEqual([\n      '^                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '|                    '.split(''),\n      '+------------------->'.split(''),\n    ]);\n    console.log(axisLayer.string());\n    expect(axis.CLASSNAME).toBe('Axis');\n    expect(axisLayer.CLASSNAME).toBe('Layer');\n  });\n};\n"
  },
  {
    "path": "__tests__/bar.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (Bar) => {\n  test('1. draw a bar chart.', () => {\n    let bar = new Bar(20);\n    bar.setData([\n      {value:100, name:'A'},\n      {value:45, name:'B'},\n      {value:70, name:'C'},\n      {value:30, name:'D'},\n    ]);\n    const r = `\n^                           \n|  A:100                    \n|  +--+                     \n|  |  |                     \n|  |  |        C:70         \n|  |  |        +--+         \n|  |  |  B:45  |  |         \n|  |  |  +--+  |  |  D:30   \n|  |  |  |  |  |  |  +--+   \n|  |  |  |  |  |  |  |  |   \n|  |  |  |  |  |  |  |  |   \n+--+--+--+--+--+--+--+--+-->`.trim();\n    expect(bar.string()).toBe(r);\n\n    bar = new Bar(20, 0.1);\n    bar.setData([\n      {value:100, name:'A'},\n      {value:45, name:'B'},\n      {value:70, name:'C'},\n      {value:30, name:'D'},\n    ]);\n    console.log(bar.string());\n\n    bar = new Bar();\n    bar.setData([\n      {value:100, name:'A'},\n      {value:45, name:'B'},\n      {value:70, name:'C'},\n      {value:30, name:'D'},\n    ]);\n    bar.array();\n    console.log(bar.string());\n  });\n};\n"
  },
  {
    "path": "__tests__/box.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (Box) => {\n  test('1. draw a box chart.', () => {\n    let box = new Box(60, 20);\n    box.setData([\n      {value:100, name:'A'},\n      {value:100, name:'B'},\n      {value:100, name:'C'},\n      {value:100, name:'Hello'},\n    ]);\n    const r = `\n+--------------+----------------------+---------------------+\n|              |                      |                     |\n|              |                      |                     |\n|              |                      |                     |\n|              |                      |                     |\n|              |                      |                     |\n|              |                      |                     |\n|              |        C:25%         |      Hello:25%      |\n|              |                      |                     |\n|              |                      |                     |\n|    A:25%     |                      |                     |\n|              |                      |                     |\n|              |                      |                     |\n|              +----------------------+---------------------+\n|              |                                            |\n|              |                                            |\n|              |                                            |\n|              |                   B:25%                    |\n|              |                                            |\n|              |                                            |\n+--------------+--------------------------------------------+`.trim();\n    expect(box.string()).toBe(r);\n\n    box = new Box();\n    box.setData([\n      {value:100, name:'A'},\n      {value:100, name:'B'},\n      {value:100, name:'C'},\n      {value:100, name:'Hello'},\n    ]);\n    console.log(box.string());\n  });\n};\n"
  },
  {
    "path": "__tests__/hbar.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (HBar) => {\n  test('1. draw a hbar chart.', () => {\n    const hbar = new HBar();\n    hbar.setData([\n      {value: 100, name: 'A'},\n      {value: 45, name: 'B'},\n      {value: 70, name: 'C'},\n      {value: 30, name: 'D'},\n    ]);\n    console.log(hbar.string());\n    const r = `\n^                                                      \n|                                                      \n+---------------+                                      \n|           D:30|                                      \n+---------------+                                      \n|                                                      \n+------------------------------------+                 \n|                                C:70|                 \n+------------------------------------+                 \n|                                                      \n+-----------------------+                              \n|                   B:45|                              \n+-----------------------+                              \n|                                                      \n+----------------------------------------------------+ \n|                                               A:100| \n+----------------------------------------------------+ \n|                                                      \n+----------------------------------------------------->\n`.trim();\n    expect(hbar.string()).toBe(r);\n  });\n};\n"
  },
  {
    "path": "__tests__/index.js",
    "content": "/**\n * Created by hustcc on 17/6/21.\n */\n\n// test for library and test\n// eslint-disable-next-line\nconst { Box, Bar, HBar, Table } = require(process.env.NODE_ENV !== 'production' ? '../src/' : '../');\nconst { Axis, Line, Point, Rect, Text, RectText } = require('../src/core/');\nconst StringUtils = require('../src/utils/string');\nconst NumberUtils = require('../src/utils/number');\n\n\ndescribe('Testcases of tcharts.js', () => {\n  describe('1. Point element.', () => {\n    require('./point')(Point);\n  });\n\n  describe('2. Line element.', () => {\n    require('./line')(Point, Line);\n  });\n\n  describe('3. Text element.', () => {\n    require('./text')(Point, Text);\n  });\n\n  describe('4. Rect element.', () => {\n    require('./rect')(Point, Rect);\n  });\n\n  describe('5. RectText element.', () => {\n    require('./recttext')(Point, RectText);\n  });\n\n  describe('6. Axis element.', () => {\n    require('./axis')(Point, Axis);\n  });\n\n  describe('7. Box chart.', () => {\n    require('./box')(Box);\n  });\n\n  describe('8. Bar chart.', () => {\n    require('./bar')(Bar);\n  });\n\n  describe('9. HBar chart.', () => {\n    require('./hbar')(HBar);\n  });\n\n  describe('10. Table chart.', () => {\n    require('./table')(Table);\n  });\n\n  describe('11. utils.', () => {\n    require('./utils')(StringUtils, NumberUtils);\n  });\n});\n"
  },
  {
    "path": "__tests__/line.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\n\nmodule.exports = (Point, Line) => {\n  test('1. draw a line element.', () => {\n    let start = new Point(0, 0);\n    let end = new Point(0, 50);\n    const line = new Line(start, end);\n    let lineLayer = line.draw();\n\n    expect(lineLayer.box).toEqual({\n      x1: 0,\n      y1: 0,\n      x2: 0,\n      y2: 50,\n    });\n    expect(lineLayer.array()).toEqual(new Array(51).fill(new Array(1).fill('|')));\n\n    start = new Point(0, 0);\n    end = new Point(50, 0);\n    lineLayer = new Line(start, end).draw();\n\n    expect(lineLayer.box).toEqual({\n      x1: 0,\n      y1: 0,\n      x2: 50,\n      y2: 0,\n    });\n    expect(lineLayer.array()).toEqual(new Array(1).fill(new Array(51).fill('-')));\n\n    expect(line.clone().CLASSNAME).toBe('Line');\n    expect(line.toString()).toBe('Line(Point(0, 0), Point(0, 50))');\n  });\n};\n"
  },
  {
    "path": "__tests__/point.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\n\nmodule.exports = (Point) => {\n  test('1. draw a point element.', () => {\n    const pointLayer = new Point(50, 50).draw();\n    expect(pointLayer.box).toEqual({\n      x1: 50,\n      y1: 50,\n      x2: 50,\n      y2: 50,\n    });\n    expect(pointLayer.array()).toEqual([['+']]);\n  });\n};\n"
  },
  {
    "path": "__tests__/rect.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\n\nmodule.exports = (Point, Rect) => {\n  test('1. draw a rect element.', () => {\n    const start = new Point(0, 0);\n    const end = new Point(4, 3);\n    const rect = new Rect(start, end);\n    const rectLayer = rect.draw();\n\n    expect(rectLayer.box).toEqual({\n      x1: 0,\n      y1: 0,\n      x2: 4,\n      y2: 3,\n    });\n    expect(rectLayer.array()).toEqual([\n      '+---+'.split(''),\n      '|   |'.split(''),\n      '|   |'.split(''),\n      '+---+'.split(''),\n    ]);\n\n    expect(rect.clone().CLASSNAME).toBe('Rect');\n    rect.toString();\n  });\n};\n"
  },
  {
    "path": "__tests__/recttext.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (Point, RectText) => {\n  test('1. draw a rect-text element.', () => {\n    const start = new Point(0, 0);\n    const end = new Point(10, 5);\n    const reactText = new RectText(start, end, 'TC');\n    const rectTextLayer = reactText.draw();\n\n    expect(rectTextLayer.box).toEqual({\n      x1: 0,\n      y1: 0,\n      x2: 10,\n      y2: 5,\n    });\n    expect(rectTextLayer.array()).toEqual([\n      '+---------+'.split(''),\n      '|         |'.split(''),\n      '|         |'.split(''),\n      ['|', ' ', ' ', ' ', ' ', 'TC', '', ' ', ' ', ' ', '|'],\n      '|         |'.split(''),\n      '+---------+'.split(''),\n    ]);\n\n    expect(reactText.clone().CLASSNAME).toBe('RectText');\n    reactText.toString();\n  });\n};\n"
  },
  {
    "path": "__tests__/table.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\n\nmodule.exports = (Table) => {\n  test('1. draw a table chart.', () => {\n    let table = new Table();\n    table.setData([\n      ['id', 'name', 'birthday'],\n      ['#1', 'xiaowei', '1992-08-01'],\n      ['#2', 'hello', '1992-09-20'],\n      ['#3', 'tcharts', '2017-06-27'],\n      ['#4', 'world'],\n    ]);\n    const r = `\n+--+-------+----------+\n|id|  name | birthday |\n+--+-------+----------+\n|#1|xiaowei|1992-08-01|\n+--+-------+----------+\n|#2| hello |1992-09-20|\n+--+-------+----------+\n|#3|tcharts|2017-06-27|\n+--+-------+----------+\n|#4| world |          |\n+--+-------+----------+`.trim();\n    expect(table.string()).toBe(r);\n\n    table = new Table(0.5); // set gap rate = 0.5\n    table.setData([\n      ['id', 'name', 'birthday'],\n      ['#1', 'xiaowei', '1992-08-01'],\n      ['#2', 'hello', '1992-09-20'],\n      ['#3', 'tcharts', '2017-06-27'],\n      ['#4', 'world'],\n    ]);\n    console.log(table.string());\n  });\n\n    test('2. draw a table chart, contains chinese.', () => {\n        let table = new Table();\n        table.setData([\n            ['標識符', '名字', '生日'],\n            ['#1', '圖靈', '1992-08-01'],\n            ['#2', '潘金蓮', '1992-09-20'],\n            ['#3', '西門慶', '2017-06-27'],\n            ['#4', '明日花绮罗'],\n        ]);\n        const r = `\n+------+----------+----------+\n|標識符|   名字   |   生日   |\n+------+----------+----------+\n|  #1  |   圖靈   |1992-08-01|\n+------+----------+----------+\n|  #2  |  潘金蓮  |1992-09-20|\n+------+----------+----------+\n|  #3  |  西門慶  |2017-06-27|\n+------+----------+----------+\n|  #4  |明日花绮罗|          |\n+------+----------+----------+`.trim();\n        expect(table.string()).toBe(r);\n\n        table = new Table(0.5); // set gap rate = 0.5\n        table.setData([\n            ['標識符', '名字', '生日'],\n            ['#1', '圖靈', '1992-08-01'],\n            ['#2', '潘金蓮', '1992-09-20'],\n            ['#3', '西門慶', '2017-06-27'],\n            ['#4', '明日花绮罗'],\n        ]);\n        console.log(table.string());\n\n      table = new Table(0.5); // set gap rate = 0.5\n      table.setData([\n        ['標識符', '名字', '生日'],\n        ['#1', '圖靈', 24],\n        ['#2', '潘金蓮', false],\n        ['#3', '西門慶', null],\n        ['#4', '明日花绮罗'],\n      ]);\n      console.log(table.string());\n    });\n};\n"
  },
  {
    "path": "__tests__/text.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (Point, Text) => {\n  test('1. draw a text element.', () => {\n    const text = 'Hello world.';\n    const p = new Point(40, 50);\n    const textE = new Text(p, text);\n    const textLayer = textE.draw();\n    expect(textLayer.box).toEqual({\n      x1: 35,\n      y1: 50,\n      x2: 46,\n      y2: 50,\n    });\n    const r = new Array(12).fill('');\n    r[0] = text;\n\n    expect(textLayer.array()).toEqual([\n      r\n    ]);\n\n    expect(textE.clone().CLASSNAME).toBe('Text');\n    textE.toString();\n  });\n};\n"
  },
  {
    "path": "__tests__/utils.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nmodule.exports = (StringUtils, NumberUtils) => {\n  test('1. toString.', () => {\n    expect(StringUtils.toString(null)).toBe('null');\n    expect(StringUtils.toString(undefined)).toBe('undefined');\n    expect(StringUtils.toString(false)).toBe('false');\n    expect(StringUtils.toString('')).toBe('');\n    expect(StringUtils.toString(123)).toBe('123');\n    expect(StringUtils.toString('hustcc')).toBe('hustcc');\n\n    expect(StringUtils.toString([1, '2'])).toBe('[1,\"2\"]');\n    expect(StringUtils.toString({a: 1, b: '2'})).toBe('{\"a\":1,\"b\":\"2\"}');\n    expect(typeof StringUtils.toString(new Date())).toBe('string');\n  });\n\n  test('2. toPercent.', () => {\n    expect(NumberUtils.toPercent(123)).toBe('12300%');\n    expect(NumberUtils.toPercent(0.234, 0)).toBe('23%');\n  });\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"tcharts.js\",\n  \"version\": \"0.0.4\",\n  \"description\": \"Lightweight and fast terminal ASCII charts for nodejs and browser.\",\n  \"main\": \"dist/tcharts.min.js\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"lint\": \"eslint src && eslint __tests__\",\n    \"cover\": \"jest --coverage\",\n    \"test\": \"npm run lint && npm run cover\",\n    \"coveralls\": \"cat ./coverage/lcov.info | coveralls\",\n    \"build\": \"webpack && cross-env NODE_ENV=production jest --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/hustcc/tcharts.js.git\"\n  },\n  \"keywords\": [\n    \"terminal\",\n    \"console\",\n    \"charts\",\n    \"ascii\",\n    \"terminal-charts\",\n    \"tcharts\",\n    \"tcharts.js\"\n  ],\n  \"author\": \"hustcc\",\n  \"license\": \"ISC\",\n  \"bugs\": {\n    \"url\": \"https://github.com/hustcc/tcharts.js/issues\"\n  },\n  \"homepage\": \"https://github.com/hustcc/tcharts.js#readme\",\n  \"devDependencies\": {\n    \"babel-cli\": \"^6.24.1\",\n    \"babel-core\": \"^6.24.1\",\n    \"babel-eslint\": \"^7.2.3\",\n    \"babel-jest\": \"^20.0.3\",\n    \"babel-loader\": \"^7.1.0\",\n    \"babel-preset-env\": \"^1.5.2\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-preset-react\": \"^6.24.1\",\n    \"babel-preset-stage-0\": \"^6.24.1\",\n    \"coveralls\": \"^2.13.1\",\n    \"cross-env\": \"^5.0.5\",\n    \"eslint\": \"^3.19.0\",\n    \"eslint-config-airbnb\": \"^15.0.1\",\n    \"eslint-config-airbnb-base\": \"^11.2.0\",\n    \"eslint-plugin-import\": \"^2.3.0\",\n    \"eslint-plugin-jsx-a11y\": \"^5.0.3\",\n    \"eslint-plugin-react\": \"^7.0.1\",\n    \"jest\": \"^20.0.4\",\n    \"webpack\": \"^3.0.0\"\n  },\n  \"dependencies\": {\n    \"area-divide\": \"^0.0.1\",\n    \"evenly\": \"^1.0.2\",\n    \"fixed-round\": \"^0.0.1\",\n    \"invariant\": \"^2.2.2\",\n    \"variable-type\": \"^0.2.0\",\n    \"what.js\": \"^1.0.1\",\n    \"word-width\": \"^1.0.1\"\n  },\n  \"jest\": {\n    \"testRegex\": \"(/__tests__/index)\\\\.(ts|tsx|js)$\",\n    \"moduleFileExtensions\": [\n      \"ts\",\n      \"tsx\",\n      \"js\",\n      \"json\"\n    ],\n    \"collectCoverage\": true,\n    \"collectCoverageFrom\": [\n      \"src/*.{js,jsx}\",\n      \"src/*/*.{js,jsx}\",\n      \"!**/node_modules/**\",\n      \"!**/vendor/**\"\n    ],\n    \"moduleDirectories\": [\n      \"node_modules\",\n      \"src\"\n    ],\n    \"transform\": {\n      \"^.+\\\\.js?$\": \"babel-jest\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/charts/Bar.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Chart = require('./Chart');\nconst invariant = require('../utils/invariant');\nconst { round } = require('../utils/number');\nconst Axis = require('../core/Axis');\nconst Point = require('../core/Point');\nconst Text = require('../core/Text');\nconst Rect = require('../core/Rect');\nconst { BAR_DATA_TYPE } = require('../const');\n\n/**\n * 柱形图\n *\n * ^\n * |    A:70\n * |   +---+\n * |   |   |\n * |   |   |              C:50\n * |   |   |             +---+\n * |   |   |             |   |\n * |   |   |             |   |\n * |   |   |     B:30    |   |\n * |   |   |    +---+    |   |\n * |   |   |    |   |    |   |\n * |   |   |    |   |    |   |\n * |   |   |    |   |    |   |\n * +---+---+----+---+----+---+----->\n *\n *\n * data 结构：\n [\n   {value:335, name:'A'},\n   {value:310, name:'B'},\n   {value:274, name:'C'},\n   {value:235, name:'D'},\n   {value:400, name:'E'},\n ]\n *\n */\nclass Bar extends Chart {\n  constructor(minWidth = 20, heightRate = 0.4) {\n    super(0, 0);\n    this.minWidth = minWidth;\n    this.heightRate = heightRate; // 高度 / 宽度比例\n    this.barWidth = 2;\n  }\n\n  setData = (data) => {\n    invariant(\n      BAR_DATA_TYPE.check(data),\n      'TCharts: data of `Bar` chart should be type of Array.'\n    );\n    this.data = data;\n    // 计算宽高\n    let width = (this.data.length * 2 + 1) * (this.barWidth + 1);\n    width = Math.max(width, this.minWidth);\n    const height = round(width * this.heightRate);\n    this.resetSize(width, height);\n    this.generateLayer();\n  };\n\n  /**\n   * 具体图表的实现\n   */\n  generateLayer = () => {\n    // 1. 构造 text 键值\n    let maxValue = 0;\n    this.data.forEach((d) => {\n      d.text = `${d.name}:${d.value}`;\n      maxValue = Math.max(maxValue, d.value);\n    });\n\n    // 2. 计算每个数值的柱形图高度d\n    this.data.forEach((d) => {\n      d.height = round((d.value / maxValue) * (this.height - 2)); // -2 是为了显示文本\n    });\n\n    // 3. 绘制坐标轴图层\n    const axisLayer = new Axis(\n      new Point(0, 0),\n      new Point(this.width, 0),\n      new Point(0, this.height)\n    ).draw();\n\n    // 4. 绘制矩形图层\n    const widthStep = round(this.width / (this.data.length * 2 + 1));\n    const rectLayers = this.data.map((d, i) => new Rect(\n      new Point(widthStep * (i * 2 + 1), 0),\n      new Point(widthStep * (i * 2 + 2), d.height)).draw()\n    );\n\n    // 5. 绘制文字图层(局左对齐)\n    const textLayers = this.data.map((d, i) => new Text(\n      new Point(widthStep * (i * 2 + 1), d.height + 1), // 文本高度为 1\n      d.text,\n      'left').draw()\n    );\n\n    // 6. 合并图层\n    let layers = [];\n    layers.push(axisLayer);\n    layers = layers.concat(rectLayers);\n    layers = layers.concat(textLayers);\n\n    this.layer.mergeArray(layers);\n  }\n}\n\nmodule.exports = Bar;\n"
  },
  {
    "path": "src/charts/Box.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst areaDivide = require('area-divide');\nconst Chart = require('./Chart');\nconst { toPercent } = require('../utils/number');\nconst RectText = require('../core/RectText');\nconst Point = require('../core/Point');\nconst invariant = require('../utils/invariant');\nconst { BOX_DATA_TYPE } = require('../const');\n\n/**\n * 面积区域占比图\n *\n *  +-------------------+------------+\n *  |                   |    B:10%   |\n *  |                   |            |\n *  |                   |------------+\n *  |       A:75%       |            |\n *  |                   |    C:20%   |\n *  |                   |            |\n *  +-------------------+------------+\n *\n * data 结构：\n [\n   {value:335, name:'A'},\n   {value:310, name:'B'},\n   {value:274, name:'C'},\n   {value:235, name:'D'},\n   {value:400, name:'E'},\n ]\n *\n */\nclass Box extends Chart {\n  constructor(width = 60, height = 20) {\n    super(width, height);\n  }\n\n  setData = (data) => {\n    invariant(\n      BOX_DATA_TYPE.check(data),\n      'TCharts: data of `Box` chart should be type of Array.'\n    );\n    this.data = data;\n    this.generateLayer();\n  };\n\n  /**\n   * 具体图表的实现\n   */\n  generateLayer = () => {\n    // 1. 计算总数\n    let total = 0;\n    this.data.forEach((d) => {\n      total += d.value;\n    });\n    // 2. 计算占比\n    this.data.forEach((d) => {\n      d.percent = d.value / total;\n      d.text = `${d.name}:${toPercent(d.percent, 0)}`;\n    });\n    // 3. 降序排序\n    this.data.sort((x, y) => y.value - x.value);\n    // 4. 瓜分面积\n    // 获得比率，然后调用方法瓜分算法\n    const percents = this.data.map(e => e.percent);\n    const plan = areaDivide(this.width, this.height, percents);\n\n    const layers = plan.map((p, index) => new RectText(\n      new Point(p.x1, p.y1),\n      new Point(p.x2, p.y2),\n      this.data[index].text).draw()\n    );\n\n    this.layer.mergeArray(layers);\n  };\n}\n\nmodule.exports = Box;\n"
  },
  {
    "path": "src/charts/Chart.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Layer = require('../core/Layer');\n\n/**\n * 图表的基类\n * 1. 拥有画布的宽高属性\n * 2. 可以设置图形的 data 配置\n * 3. 拥有将图层变成字符串的能力 string() / array();\n * 4. 拥有一个图层，这个是最最终图层\n */\nclass Chart {\n  constructor(width, height) {\n    this.resetSize(width, height);\n    this.data = [];\n  }\n\n  resetSize = (width, height) => {\n    this.width = width;\n    this.height = height;\n    // 创建一个空的图层\n    this.layer = Layer.emptyInstance({\n      x1: 0,\n      y1: 0,\n      x2: this.width,\n      y2: this.height,\n    });\n  };\n\n  // 返回图表的文本，可以直接用脑输出\n  string = () => this.layer.string();\n\n  // 返回图表的文本数组，逐行打印就可以显示了\n  array = () => this.layer.array();\n}\n\nmodule.exports = Chart;\n"
  },
  {
    "path": "src/charts/HBar.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Chart = require('./Chart');\nconst invariant = require('../utils/invariant');\nconst { round } = require('../utils/number');\nconst Axis = require('../core/Axis');\nconst Point = require('../core/Point');\nconst Rect = require('../core/Rect');\nconst Text = require('../core/Text');\nconst { HBAR_DATA_TYPE } = require('../const');\n\n/**\n * 横向柱形图\n *\n * ^\n * |\n * +--------------------------+\n * |           A:70           |\n * +--------------------------+\n * |\n * |\n * +-----------------+\n * |      B:30       |\n * +-----------------+\n * |\n * |\n * +---------------------+\n * |         C:50        |\n * +---------------------+\n * |\n * +---+---+----+---+----+---+----->\n *\n */\nclass HBar extends Chart {\n  constructor(minHeight = 8, widthRate = 3) {\n    super(0, 0);\n    this.minHeight = minHeight;\n    this.widthRate = widthRate; // 高度 / 宽度比例\n    this.barHeight = 1;\n  }\n\n  setData = (data) => {\n    invariant(\n      HBAR_DATA_TYPE.check(data),\n      'TCharts: data of `HBar` chart should be type of Array.'\n    );\n    this.data = data;\n    // 计算宽高\n    let height = (this.data.length * 2 + 1) * (this.barHeight + 1);\n    height = Math.max(height, this.minHeight);\n    const width = round(height * this.widthRate);\n    this.resetSize(width, height);\n    this.generateLayer();\n  };\n\n  /**\n   * 具体图表的实现\n   */\n  generateLayer = () => {\n    // 1. 构造 text 键值\n    let maxValue = 0;\n    this.data.forEach((d) => {\n      d.text = `${d.name}:${d.value}`;\n      maxValue = Math.max(maxValue, d.value);\n    });\n\n    // 2. 计算每个数值的柱形图宽度\n    this.data.forEach((d) => {\n      d.width = round((d.value / maxValue) * (this.width - 1)); // -1 图形美观\n    });\n\n    // 3. 绘制坐标轴图层\n    const axisLayer = new Axis(\n      new Point(0, 0),\n      new Point(this.width, 0),\n      new Point(0, this.height)\n    ).draw();\n\n    // 4. 绘制矩形图层\n    const heightStep = round(this.height / (this.data.length * 2 + 1));\n    const rectLayers = this.data.map((d, i) => new Rect(\n      new Point(0, heightStep * (i * 2 + 1)),\n      new Point(d.width, heightStep * (i * 2 + 2))).draw()\n    );\n\n    // 5. 绘制文字图层(局左对齐)\n    const textLayers = this.data.map((d, i) => {\n      if (d.text.length >= d.width) {\n        // 文本长度超过柱子长度，在在柱形右边显示\n        return new Text(\n          new Point(d.width + 1, heightStep * (i * 2 + 1) + 1),\n          d.text).draw();\n      }\n      // 居右显示\n      return new Text(\n        new Point(d.width - 1, heightStep * (i * 2 + 1) + 1),\n        d.text,\n        'right').draw();\n    });\n\n    // 6. 合并图层\n    let layers = [];\n    layers.push(axisLayer);\n    layers = layers.concat(rectLayers);\n    layers = layers.concat(textLayers);\n\n    this.layer.mergeArray(layers);\n  }\n}\n\nmodule.exports = HBar;\n"
  },
  {
    "path": "src/charts/Table.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Chart = require('./Chart');\nconst invariant = require('../utils/invariant');\nconst RectText = require('../core/RectText');\nconst Point = require('../core/Point');\nconst { arrayClone } = require('../utils/array');\nconst { wordWidth } = require('../utils/string');\nconst { round } = require('../utils/number');\nconst { TABLE_DATA_TYPE } = require('../const');\n\n/**\n * 表格\n *\n *\n * +----+----------+----------------+\n * | id |   name   |    birthday    |\n * +----+----------+----------------+\n * | #1 |  xiaowei |   1992-08-01   |\n * +----+----------+----------------+\n * | #2 |  hello   |   1992-09-20   |\n * +----+----------+----------------+\n * | #3 | tcharts  |   2017-06-27   |\n * +----+----------+----------------+\n * | #4 |     d    |                |\n * +----+----------+----------------+\n *\n *\n *\n */\nclass Table extends Chart {\n  constructor(rate = 0) {\n    super(0, 0); // table 的宽高有内容自动伸缩\n    this.rate = rate; // 比例，比如文字宽度为10, rate = 0.1，则表格 cell 宽度为 12\n  }\n\n  // 通过内容计算每一列的宽高\n  _calColSizes = (data, row, col) => {\n    let sizes = new Array(col).fill(0);\n    data.forEach((d) => {\n      sizes = sizes.map((s, i) => Math.max(wordWidth(d[i]), s));\n    });\n    // 乘以 rate\n    sizes = sizes.map(s => s + round(s * this.rate) * 2);\n    return sizes;\n  };\n\n  _getRowAndCol = (data) => {\n    const row = data.length;\n    let col = 0;\n    data.forEach((d) => {\n      col = Math.max(col, d.length);\n    });\n\n    // 数据不能为零长度\n    invariant(\n      row !== 0 && col !== 0,\n      `TCharts: data of \\`Table\\` chart should be type of matrix Array, \n      and can not be zero row or column. Got row: %s, column: %s.`,\n      row,\n      col\n    );\n    return {\n      row,\n      col,\n    };\n  };\n\n  // 填充数据（对于有空缺的数据）\n  _fullFillData = (data, row, col) => {\n    const cloneData = arrayClone(data);\n    // 遍历来填充数据\n    data.forEach((d, index) => {\n      if (col > d.length) {\n        // 补充一些空的文本\n        cloneData[index].splice(cloneData[index].length, 0, ...new Array(col - d.length).fill(''));\n      }\n    });\n    return cloneData;\n  };\n\n  _calTableSizes = (colSizes, row, col) => {\n    // width height 是从 0 开始计数的，所以这里的 width height 比实际的 - 1\n    const height = row * 2;\n    const width = col + colSizes.reduce((r, ele) => r + ele);\n    return {\n      width,\n      height,\n    };\n  };\n\n  setData = (data) => {\n    invariant(\n      TABLE_DATA_TYPE.check(data),\n      'TCharts: data of `Table` chart should be type of matrix Array.'\n    );\n    const { row, col } = this._getRowAndCol(data);\n    this.data = this._fullFillData(data, row, col);\n\n    const colSizes = this._calColSizes(this.data, row, col);\n    const { width, height } = this._calTableSizes(colSizes, row, col);\n\n    this.resetSize(width, height);\n    this.generateLayer(colSizes, row, col);\n  };\n\n  /**\n   * 具体 table 的实现\n   */\n  generateLayer = (colSizes, row, col) => {\n    const rectTexts = []; // 非常多有的 rectText 实例\n    let startX = 0;\n    let startY = 0;\n\n    for (let i = 0; i < row; i += 1) {\n      startX = 0;\n      for (let j = 0; j < col; j += 1) {\n        rectTexts.push(new RectText(\n          new Point(startX, startY),\n          new Point(startX + colSizes[j] + 1, startY + 2),\n          this.data[row - i - 1][j]).draw());\n\n        startX += (colSizes[j] + 1);\n      }\n      startY += 2;\n    }\n    return this.layer.mergeArray(rectTexts);\n  }\n}\n\nmodule.exports = Table;\n"
  },
  {
    "path": "src/const.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nconst VT = require('variable-type');\n\nconst COMMON_TYPE = VT.arrayOf(\n  VT.shape({\n    name: VT.or([\n      VT.number,\n      VT.string,\n    ]),\n    value: VT.number,\n  })\n);\n\nconst BAR_DATA_TYPE = COMMON_TYPE;\n\nconst BOX_DATA_TYPE = COMMON_TYPE;\n\nconst HBAR_DATA_TYPE = COMMON_TYPE;\n\nconst TABLE_DATA_TYPE = VT.arrayOf(\n  VT.arrayOf(\n    VT.any,\n  ),\n);\n\n// const TREE_DATA_TYPE = VT.shape({\n//   name: VT.or([\n//     VT.number,\n//     VT.string,\n//   ]),\n//   // TODO children 一个递归结构的数组\n//   children: VT.arrayOf(\n//     VT.recursive\n//   ),\n// });\n\nmodule.exports = {\n  BAR_DATA_TYPE,\n  BOX_DATA_TYPE,\n  HBAR_DATA_TYPE,\n  TABLE_DATA_TYPE,\n  // TREE_DATA_TYPE,\n};\n"
  },
  {
    "path": "src/core/Axis.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst Element = require('./Element');\nconst Line = require('./Line');\n\n/**\n * 一个坐标轴系统，不带 x，y 文字\n *\n * ^\n * |\n * |\n * |\n * |\n * |\n * |\n * |\n * |\n * |\n * +------------------------------>\n *\n */\nclass Axis extends Element {\n  /**\n   * 构造方法\n   * @param point0 零点\n   * @param pointX 横向轴\n   * @param pointY 纵向轴\n   */\n  constructor(point0, pointX, pointY) {\n    super();\n    invariant(\n      types.isPoint(point0) && types.isPoint(pointX) && types.isPoint(pointY),\n      'TCharts: constructor props of Axis should be (Point, Point, Point), got (%s, %s, %s).',\n      types.typeOf(point0),\n      types.typeOf(pointX),\n      types.typeOf(pointY));\n\n    invariant(\n      point0.y === pointX.y,\n      'TCharts: constructor props `pointX` of Axis should be an Horizontal line with `point0`.');\n\n    invariant(\n      point0.x === pointY.x,\n      'TCharts: constructor props `pointY` of Axis should be an Horizontal line with `point0`.');\n\n    this.point0 = point0;\n    this.pointX = pointX;\n    this.pointY = pointY;\n    this.box = {\n      x1: this.point0.x,\n      y1: this.point0.y,\n      x2: this.pointX.x,\n      y2: this.pointY.y,\n    };\n\n    this.initLayer();\n  }\n\n  clone = () => new Axis(this.point0, this.pointX, this.pointY);\n\n  toString = () => `Axis(${this.point0}, ${this.pointX}, ${this.pointY})`;\n\n  draw = () => {\n    // X 轴图层\n    const lineXLayer = new Line(this.point0, this.pointX).draw();\n    // Y 轴图层\n    const lineYLayer = new Line(this.point0, this.pointY).draw();\n\n    // 后合并点，可以提高性能，同时不会导致层覆盖问题\n    return this.layer.merge(\n      lineXLayer,                      // x 轴\n      lineYLayer,                      // y 轴\n      this.point0.draw({ fill: '+' }), // 左边圆点\n      this.pointX.draw({ fill: '>' }), // x 轴箭头\n      this.pointY.draw({ fill: '^' })  // y 轴箭头\n    );\n  };\n\n  get CLASSNAME() {\n    return 'Axis';\n  }\n}\n\nmodule.exports = Axis;\n"
  },
  {
    "path": "src/core/Element.js",
    "content": "/**\n * Created by hustcc.\n */\nconst { floorCenter } = require('../utils/number');\nconst Layer = require('./Layer');\n/**\n * 元素基类，像积木一样一层一层的搭建组件元素\n * 每隔元素都可以通过 draw 方法获得一个图层\n * 上层的元素是利用下层元素组合出来的，然后形成新的图层\n * 一层一层，直到形成最终的图表 charts\n *\n * 元素都有一个 box 结构（盒模型？）限定了元素的起始位置\n * 另外具有一个 z-index 属性，可以设置元素显示的层级\n *\n * 元素的 clone 可以直接获得一个相同的元素，引用不同\n */\nclass Element {\n  constructor(zIndex = 0) {\n    this.zIndex = zIndex; // TODO 用于控制渲染层级，后期可以用于重构渲染性能\n    // box 限制了元素的起始结束点坐标，以\n    this.box = { x1: 0, y1: 0, x2: 0, y2: 0 };\n  }\n\n  /**\n   * 初始化空的 layer\n   */\n  initLayer = () => {\n    this.layer = Layer.emptyInstance(this.box, this.zIndex);\n  };\n\n  // setZIndex = (zIndex = 0) => {\n  //   this.zIndex = zIndex;\n  // };\n\n  /**\n   * 获得中心点的坐标\n   * @returns {{x: number, y: number}}\n   */\n  center = () => ({\n    x: floorCenter(this.box.x1, this.box.x2),\n    y: floorCenter(this.box.y1, this.box.y2),\n  });\n\n  /**\n   * 获得元素的大小\n   * @returns {{width: number, height: number}}\n   */\n  size = () => {\n    const width = this.box.x2 - this.box.x1 + 1;\n    const height = this.box.y2 - this.box.y1 + 1;\n    return {\n      width,\n      height,\n    };\n  };\n\n  // clone = () => new Element();\n  //\n  // toString = () => {\n  //   invariant(false, 'TCharts: Element\\'s method `toString` should be implemented by children Class.');\n  // };\n  //\n  //\n  // /**\n  //  * 绘制图形，产生图层，图层将用于最终的渲染\n  //  * @param options { fill: '*', line: '-' }\n  //  */\n  // draw = () => {\n  //   invariant(false, 'TCharts: Element\\'s method `draw` should be implemented by children Class.');\n  // };\n  //\n  // get CLASSNAME() {\n  //   invariant(false, 'TCharts: Element\\'s method `CLASSNAME` should be implemented by children Class.');\n  // }\n}\n\nmodule.exports = Element;\n"
  },
  {
    "path": "src/core/Layer.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst { fillMatrix } = require('../utils/array');\n\n/**\n * 定义一个图层，图层包括一个范围和填充的内容\n * 图层是最终将用于显示的部分，图层可以通过 merge 合并\n * 最终显示在控制台的仅仅只有一个图层\n * 这个图层是有很多的小元素图层合并而来\n *\n * 如何设计图层，更好划分图层，将提高 merge 性能\n *\n * 图层也就是 Element 元素 draw 方法的返回值\n */\nclass Layer {\n  constructor(box = { x1: 0, y1: 0, x2: 0, y2: 0 }, ascii = [], zIndex = 0) {\n    invariant(\n      types.isObject(box) && types.isArray(ascii) && types.isNumber(zIndex),\n      'TCharts: constructor props of Layer should be (object, array, number), got (%s, %s, %s).',\n      types.typeOf(box),\n      types.typeOf(ascii),\n      types.typeOf(zIndex));\n\n    this.box = box;\n    this.ascii = ascii;\n    this.zIndex = zIndex;\n  }\n\n  static emptyInstance(box, zIndex = 0) {\n    const width = box.x2 - box.x1 + 1;\n    const height = box.y2 - box.y1 + 1;\n\n    const ascii = fillMatrix(height, width, ' ');\n    return new Layer(box, ascii, zIndex);\n  }\n\n  // box 盒模型是不是大于\n  // gt = (layer, includeEqual = true) => {\n  //    if (includeEqual) {\n  //      if (\n  //        this.box.x1 <= layer.box.x1 &&\n  //        this.box.y1 <= layer.box.y1 &&\n  //        this.box.x2 >= layer.box.x2 &&\n  //        this.box.y2 >= layer.box.y2) {\n  //        return true;\n  //      }\n  //      return false;\n  //    }\n  //   if (\n  //     this.box.x1 < layer.box.x1 &&\n  //     this.box.y1 < layer.box.y1 &&\n  //     this.box.x2 > layer.box.x2 &&\n  //     this.box.y2 > layer.box.y2) {\n  //     return true;\n  //   }\n  //    return false;\n  // };\n\n  /**\n   * 按顺序合并另外的 layers\n   * @param layer\n   */\n  merge = (...layers) => this.mergeArray(layers);\n\n  /**\n   * 合并一个 layer\n   * @param layer\n   */\n  mergeOne = (layer) => {\n    // 校验：前提条件是，this 的范围肯定大于 layer\n    // invariant(\n    //   this.gt(layer),\n    //   'TCharts: layer\\'box should be greater then layer which will be merged.');\n\n    // 算法\n    const { x1, y1, x2, y2 } = layer.box;\n    const { x1: thisX1, y1: thisY1, x2: thisX2, y2: thisY2 } = this.box;\n    const rangeX1 = Math.max(x1, thisX1);\n    const rangeY1 = Math.max(y1, thisY1);\n    const rangeX2 = Math.min(x2, thisX2);\n    const rangeY2 = Math.min(y2, thisY2);\n    // box 的偏移量\n    let i1;\n    let i2;\n    for (let i = rangeX1; i <= rangeX2; i += 1) {\n      // 减少计算量\n      i1 = i - thisX1;\n      i2 = i - x1;\n      for (let j = rangeY1; j <= rangeY2; j += 1) {\n        this.ascii[j - thisY1][i1] = layer.ascii[j - y1][i2];\n      }\n    }\n    return this;\n  };\n\n  /**\n   * 合并一个 layer\n   * @param layer\n   */\n  mergeArray = (layers) => {\n    // 首先先按照 zIndex 升序排列，越大越在上层\n    // chrome 下 sort 方法可能为不稳定，这点需要注意。\n    // layers.sort((x, y) => x - y); // TODO :暂时不要 zIndex 排序特性\n    // 排序之后遍历，先绘制底层的，后使用上层覆盖\n    layers.forEach((layer) => {\n      this.mergeOne(layer);\n    });\n    return this;\n  };\n\n  /**\n   * 返回图表的文本，可以直接用脑输出\n   * @returns {string}\n   */\n  string = () => {\n    const asciiArray = this.ascii;\n    // 逆向遍历\n    const rst = [];\n    for (let i = asciiArray.length - 1; i >= 0; i -= 1) {\n      rst.push(`${asciiArray[i].join('')}`);\n    }\n    return rst.join('\\n');\n  };\n\n  /**\n   * 返回图表的文本数组，逐行打印就可以显示了\n   */\n  array = () => this.ascii.slice().reverse();\n\n  get CLASSNAME() {\n    return 'Layer';\n  }\n}\n\nmodule.exports = Layer;\n"
  },
  {
    "path": "src/core/Line.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst Element = require('./Element');\nconst { fillMatrix } = require('../utils/array');\n// const Layer = require('./Layer');\n\n/**\n * 一个线段，包括横线和竖线\n *\n * 横线\n * -------------------\n *\n * 竖线\n * |\n * |\n * |\n * |\n * |\n * |\n *\n */\nclass Line extends Element {\n  constructor(start, end) {\n    super();\n    // 参数必须是 point 类型的\n    invariant(\n      types.isPoint(start) && types.isPoint(end),\n      'TCharts: constructor props of Line should be (Point, Point), got (%s, %s).',\n      types.typeOf(start),\n      types.typeOf(end));\n    // 控制台模式下，仅仅只能输入横线或者竖线\n    invariant(\n      start.x === end.x || start.y === end.y,\n      'TCharts: we can only draw Horizontal / Vertical line in terminal. got(%s, %s).',\n      start,\n      end);\n    // 校验通过，赋值属性\n    this.start = start;\n    this.end = end;\n    this.box = {\n      x1: Math.min(this.start.x, this.end.x),\n      y1: Math.min(this.start.y, this.end.y),\n      x2: Math.max(this.start.x, this.end.x),\n      y2: Math.max(this.start.y, this.end.y),\n    };\n\n    this.initLayer();\n  }\n\n  clone = () => new Line(this.start.clone(), this.end.clone());\n\n  toString = () => `Line(${this.start}, ${this.end})`;\n\n  draw = () => {\n    const { width, height } = this.size();\n    const isHorizontal = this.box.y1 === this.box.y2;\n\n    let ascii = null;\n    if (isHorizontal) {\n      // 横向线\n      ascii = fillMatrix(1, width, '-');\n    } else {\n      // 纵向线\n      ascii = fillMatrix(height, 1, '|');\n    }\n    this.layer.ascii = ascii;\n    return this.layer;\n  };\n\n  get CLASSNAME() {\n    return 'Line';\n  }\n}\n\nmodule.exports = Line;\n"
  },
  {
    "path": "src/core/Point.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst Element = require('./Element');\n\n/**\n * 一个点\n *\n * +\n *\n */\nclass Point extends Element {\n  constructor(x, y) {\n    super();\n    invariant(\n      types.isNumber(x) && types.isNumber(y),\n      'TCharts: constructor props of Point should be (number, number), got (%s, %s).',\n      types.typeOf(x),\n      types.typeOf(y));\n\n    this.x = x;\n    this.y = y;\n    this.box = {\n      x1: this.x,\n      y1: this.y,\n      x2: this.x,\n      y2: this.y,\n    };\n\n    this.initLayer();\n  }\n\n  clone = () => new Point(this.x, this.y);\n\n  toString = () => `Point(${this.x}, ${this.y})`;\n\n  draw = (options = { fill: '+' }) => {\n    this.layer.ascii = [[options.fill]];\n    return this.layer;\n  };\n\n  get CLASSNAME() {\n    return 'Point';\n  }\n}\n\nmodule.exports = Point;\n"
  },
  {
    "path": "src/core/Rect.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst Element = require('./Element');\nconst Point = require('./Point');\nconst Line = require('./Line');\n// const Layer = require('./Layer');\n\n/**\n *  带边框的填充矩形，在控制台下面，仅仅只能绘制四边形\n *\n *  +---------------------------+\n *  |                           |\n *  |                           |\n *  |                           |\n *  |                           |\n *  +---------------------------+\n *\n */\nclass Rect extends Element {\n  constructor(start, end) {\n    super();\n    // 参数必须是 point 类型的\n    invariant(\n      types.isPoint(start) && types.isPoint(end),\n      'TCharts: constructor props of Rect should be (Point, Point), got (%s, %s).',\n      types.typeOf(start),\n      types.typeOf(end));\n    // 校验通过，赋值属性\n    this.start = start;\n    this.end = end;\n    this.box = {\n      x1: Math.min(this.start.x, this.end.x),\n      y1: Math.min(this.start.y, this.end.y),\n      x2: Math.max(this.start.x, this.end.x),\n      y2: Math.max(this.start.y, this.end.y),\n    };\n\n    this.initLayer();\n  }\n\n  clone = () => new Rect(this.start.clone(), this.end.clone());\n\n  toString = () => `Rect(${this.start}, ${this.end})`;\n\n  draw = () => {\n    // 四个顶点\n    const points = [\n      new Point(this.box.x1, this.box.y1),\n      new Point(this.box.x2, this.box.y1),\n      new Point(this.box.x2, this.box.y2),\n      new Point(this.box.x1, this.box.y2),\n    ];\n    const corners = points.map(p => p.draw());\n\n    // 四条边\n    const lines = [\n      new Line(points[0], points[1]).draw(),\n      new Line(points[1], points[2]).draw(),\n      new Line(points[2], points[3]).draw(),\n      new Line(points[3], points[0]).draw(),\n    ];\n\n    // 合并图层部分\n    return this.layer.mergeArray(lines.concat(corners));\n  };\n  get CLASSNAME() {\n    return 'Rect';\n  }\n}\n\nmodule.exports = Rect;\n"
  },
  {
    "path": "src/core/RectText.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst Element = require('./Element');\nconst Point = require('./Point');\nconst Rect = require('./Rect');\nconst Text = require('./Text');\n\n/**\n *  带边框的填充矩形，并且显示说明文本，在控制台下面，仅仅只能绘制四边形\n *\n *  +---------------------------+\n *  |                           |\n *  |            ABC            |\n *  |                           |\n *  |                           |\n *  +---------------------------+\n *\n */\nclass RectText extends Element {\n  constructor(start, end, text) {\n    super();\n    // 参数必须是 point 类型的\n    invariant(\n      types.isPoint(start) && types.isPoint(end),\n      'TCharts: constructor props of RectText should be (Point, Point, any), got (%s, %s, %s).',\n      types.typeOf(start),\n      types.typeOf(end),\n      types.typeOf(text));\n    // 校验通过，赋值属性\n    this.start = start;\n    this.end = end;\n    this.text = text;\n    this.box = {\n      x1: Math.min(this.start.x, this.end.x),\n      y1: Math.min(this.start.y, this.end.y),\n      x2: Math.max(this.start.x, this.end.x),\n      y2: Math.max(this.start.y, this.end.y),\n    };\n\n    this.initLayer();\n  }\n\n  clone = () => new RectText(this.start.clone(), this.end.clone(), this.text);\n\n  toString = () => `RectText(${this.start}, ${this.end}, ${this.text})`;\n\n  draw = () => {\n    // 四个顶点\n    const rect = new Rect(this.start, this.end);\n    const center = this.center(); // 居中位置\n    const text = new Text(new Point(center.x, center.y), this.text);\n\n    // 合并图层\n    return this.layer.merge(rect.draw(), text.draw());\n  };\n\n  get CLASSNAME() {\n    return 'RectText';\n  }\n}\n\nmodule.exports = RectText;\n"
  },
  {
    "path": "src/core/Text.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst evenly = require('evenly');\nconst { wordWidth, toString } = require('../utils/string');\nconst invariant = require('../utils/invariant');\nconst types = require('../utils/types');\nconst { fillMatrix } = require('../utils/array');\nconst Element = require('./Element');\n\n/**\n * 一段文本（目前仅支持横向）\n *\n * hello world，这个是一个控制台图标库\n */\nclass Text extends Element {\n  constructor(p, text, align = 'center') {\n    super();\n    invariant(\n      types.isPoint(p),\n      'TCharts: constructor props of Text should be (Point, any), got (%s, %s).',\n      types.typeOf(p),\n      types.typeOf(text));\n\n    invariant(\n      ['center', 'left', 'right'].indexOf(align) >= 0,\n      'TCharts: constructor props `align` of Text should be one of [\\'center\\', \\'left\\', \\'right\\'], got %s.',\n      align);\n    this.p = p;\n    this.text = toString(text);\n    this.align = align;\n\n\n    const textWidth = wordWidth(this.text);\n\n    if (this.align === 'center') {\n      // 居中显示\n      const _width = evenly(textWidth, 2, 0);\n      this.box = {\n        x1: p.x - _width[0] + 1, // 因为当前 p 位置还可以存一个字符串\n        y1: p.y,\n        x2: p.x + _width[1],\n        y2: p.y,\n      };\n    } else if (this.align === 'left') {\n      // 局左显示\n      this.box = {\n        x1: p.x,\n        y1: p.y,\n        x2: p.x + textWidth - 1,\n        y2: p.y,\n      };\n    } else {\n      // 居右显示\n      this.box = {\n        x1: p.x - textWidth + 1,\n        y1: p.y,\n        x2: p.x,\n        y2: p.y,\n      };\n    }\n\n    this.initLayer();\n  }\n\n  clone = () => new Text(this.p, this.text);\n\n  toString = () => `Text(${this.p}, ${this.text})`;\n\n  draw = () => {\n    const { width } = this.size();\n\n    this.layer.ascii = fillMatrix(1, width, '');\n    this.layer.ascii[0][0] = this.text;\n    return this.layer;\n  };\n\n  get CLASSNAME() {\n    return 'Text';\n  }\n}\n\nmodule.exports = Text;\n"
  },
  {
    "path": "src/core/index.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Axis = require('./Axis');\nconst Line = require('./Line');\nconst Point = require('./Point');\nconst Rect = require('./Rect');\nconst Text = require('./Text');\nconst RectText = require('./RectText');\n\nmodule.exports = {\n  Axis,\n  Line,\n  Point,\n  Rect,\n  Text,\n  RectText,\n};\n"
  },
  {
    "path": "src/index.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst Bar = require('./charts/Bar');\nconst Box = require('./charts/Box');\nconst HBar = require('./charts/HBar');\nconst Table = require('./charts/Table');\n\nmodule.exports = {\n  Box,\n  Bar,\n  HBar,\n  Table,\n};\n"
  },
  {
    "path": "src/utils/array.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\n'use strict';\n\n\n/**\n * fastest way to fill a array\n * here: https://jsperf.com/zeroarrayjs/10\n * @param len\n * @param val\n * @returns {Array}\n */\nconst fillArray = (len, val) => {\n  const res = new Array(len);\n  for (let i = 0; i < len; i += 1) {\n    res[i] = val;\n  }\n  return res;\n};\n\n/**\n * Return a of val\n *\n * @param  {Number} `row` number of rows\n * @param  {Number} `col` number of columns\n * @param  {*} `val`\n * @return {*[][]} `matrix` of val\n */\nconst fillMatrix = (row, col, val) => {\n  const res = new Array(row);\n  for (let i = 0; i < row; i += 1) {\n    res[i] = fillArray(col, val);\n  }\n  return res;\n};\n\n/**\n * deep clone array\n * @param arr\n * @returns {*}\n */\nconst arrayClone = (arr) => {\n  let i;\n  let copy;\n  if (Array.isArray(arr)) {\n    copy = arr.slice(0);\n    for (i = 0; i < copy.length; i += 1) {\n      copy[i] = arrayClone(copy[i]);\n    }\n    return copy;\n  }\n  return arr;\n};\n\nmodule.exports = {\n  fillArray,\n  fillMatrix,\n  arrayClone,\n};\n"
  },
  {
    "path": "src/utils/invariant.js",
    "content": "module.exports = require('invariant');\n"
  },
  {
    "path": "src/utils/number.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nconst round = require('fixed-round');\n\nconst center = (x1, x2) => round((x1 + x2) / 2);\n\nconst floorCenter = (x1, x2) => Math.floor((x1 + x2) / 2);\n\nconst toPercent = (number, fixed = 2) => `${round(number * 100, fixed)}%`;\n\n\nmodule.exports = {\n  round,\n  center,\n  floorCenter,\n  toPercent,\n};\n"
  },
  {
    "path": "src/utils/string.js",
    "content": "/**\n * Created by hustcc.\n * Contract: i@hust.cc\n */\n\nconst WordWidth = require('word-width');\nconst types = require('./types');\n\nconst toString = (v) => {\n  if (v === null) return 'null';\n  if (v === undefined) return 'undefined';\n  if (types.isNumber(v) || types.isString(v) || types.isBool(v)) return `${v}`;\n  if (types.isArray(v) || types.isObject(v)) return JSON.stringify(v);\n  return Object({}).toString.call(v);\n};\n\nconst wordWidth = s => WordWidth(toString(s));\n\nmodule.exports = {\n  wordWidth,\n  toString,\n};\n"
  },
  {
    "path": "src/utils/types.js",
    "content": "/**\n * Created by hustcc.\n */\n\nconst VT = require('variable-type');\nconst what = require('what.js');\n\n\nconst isNumber = v => VT.number.check(v);\n\nconst isString = v => VT.string.check(v);\n\nconst isArray = v => VT.array.check(v);\n\nconst isObject = v => VT.object.check(v);\n\nconst isBool = v => VT.bool.check(v);\n\nconst isEmpty = v => VT.or([\n  VT.null,\n  VT.undefined\n]).check(v);\n\nconst isPoint = v => v.CLASSNAME === 'Point';\n\nconst typeOf = (v) => {\n  if (v && v.CLASSNAME) return v.CLASSNAME;\n  return what(v);\n};\n\nmodule.exports = {\n  isNumber,\n  isString,\n  isArray,\n  isObject,\n  isBool,\n  isEmpty,\n  isPoint,\n  typeOf,\n};\n"
  },
  {
    "path": "webpack.config.js",
    "content": "/**\n * Copyright (c) 2017 hustcc\n * License: ISC\n * GitHub: https://github.com/hustcc/tcharts.js\n **/\n\nvar path = require('path');\nvar webpack = require('webpack');\n\nmodule.exports = {\n  entry: './src/index.js',\n  output: {\n    filename: 'tcharts.min.js',\n    path: path.resolve(__dirname, 'dist'),\n    library: 'TCharts',\n    libraryTarget: 'umd',\n    umdNamedDefine: true\n  },\n  module: {\n    loaders: [{\n      test: /.js$/,\n      loader: 'babel-loader'\n    }]\n  },\n  devtool: 'source-map',\n  plugins: [\n    new webpack.optimize.UglifyJsPlugin({\n      output: { comments: false },\n      compress: { warnings: false }\n    })\n  ]\n};"
  }
]