├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .prettierrc.js
├── .travis.yml
├── README.md
├── app.ts
├── app
├── controller
│ ├── home.ts
│ └── repo.ts
├── entity
│ └── ChartsOptions.ts
├── extend
│ ├── context.ts
│ └── helper.ts
├── router.ts
├── service
│ ├── fork.ts
│ ├── home.ts
│ ├── language.ts
│ └── star.ts
├── utils
│ ├── charts-render.ts
│ └── index.ts
└── validator
│ ├── home.ts
│ └── repo.ts
├── appveyor.yml
├── charts-theme
├── language
│ └── default.js
└── star
│ └── default.js
├── config
├── config.default.ts
├── config.prod.ts
└── plugin.ts
├── examples
└── test.svg
├── html
├── .browserslistrc
├── .eslintrc.js
├── .postcssrc.js
├── .prettierrc.js
├── babel.config.js
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.vue
│ ├── assets
│ └── logo.png
│ ├── components
│ └── HelloWorld.vue
│ ├── main.js
│ ├── router.js
│ ├── store.js
│ └── views
│ ├── About.vue
│ └── Home.vue
├── laboratory
├── echartsOptions.js
├── puppeteerTest.js
├── testChartist.js
├── testEchartSVG.js
├── testLanguageData.js
└── testStarData.js
├── package-lock.json
├── package.json
├── tsconfig.json
├── typings
├── app
│ ├── controller
│ │ └── index.d.ts
│ ├── extend
│ │ ├── context.d.ts
│ │ └── helper.d.ts
│ ├── index.d.ts
│ └── service
│ │ └── index.d.ts
├── config
│ ├── index.d.ts
│ └── plugin.d.ts
└── index.d.ts
└── vue.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | insert_final_newline = false
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*.d.ts
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "extends": [
4 | "plugin:@typescript-eslint/recommended",
5 | "prettier/@typescript-eslint",
6 | "plugin:prettier/recommended"
7 | ],
8 | "plugins": [
9 | "@typescript-eslint",
10 | "prettier"
11 | ],
12 | "parserOptions": {
13 | "project": "./tsconfig.json"
14 | },
15 | "env": {
16 | "node": true,
17 | "es6": true
18 | },
19 | "rules": {
20 | "prettier/prettier": 1,
21 | "no-console": ["off", { "allow": ["warn", "error"] }],
22 | "eqeqeq": ["warn", "always"],
23 | "quotes": ["error", "single"],
24 | "semi": ["error", "never"],
25 | "prefer-const": ["error", {"destructuring": "all", "ignoreReadBeforeAssign": true}],
26 | "@typescript-eslint/indent": ["off", 2, { "VariableDeclarator": 4, "SwitchCase": 1 }],
27 | "@typescript-eslint/no-explicit-any": 0,
28 | "@typescript-eslint/no-unused-vars": 0,
29 | "@typescript-eslint/interface-name-prefix": 0,
30 | "@typescript-eslint/explicit-member-accessibility": 0,
31 | "@typescript-eslint/no-triple-slash-reference": 0,
32 | "@typescript-eslint/ban-ts-ignore": 0,
33 | "@typescript-eslint/no-this-alias": 0,
34 | "@typescript-eslint/triple-slash-reference": ["error", { "path": "always", "types": "never", "lib": "never" }],
35 | "@typescript-eslint/no-array-constructor": 0,
36 | "@typescript-eslint/explicit-function-return-type": 0
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | logs/
3 | npm-debug.log
4 | node_modules/
5 | coverage/
6 | .idea/
7 | run/
8 | logs/
9 | .DS_Store
10 | .vscode
11 | *.swp
12 | *.lock
13 | !.autod.conf.js
14 |
15 | app.js
16 | app/**/*.js
17 | test/**/*.js
18 | config/**/*.js
19 | app/**/*.map
20 | test/**/*.map
21 | config/**/*.map
22 |
23 | report*
24 |
25 | ## Vue.js
26 | .DS_Store
27 | node_modules
28 | /dist
29 |
30 | # local env files
31 | .env.local
32 | .env.*.local
33 |
34 | # Log files
35 | npm-debug.log*
36 | yarn-debug.log*
37 | yarn-error.log*
38 |
39 | # Editor directories and files
40 | .idea
41 | .vscode
42 | *.suo
43 | *.ntvs*
44 | *.njsproj
45 | *.sln
46 | *.sw?
47 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 2,
3 | singleQuote: true,
4 | semi: false,
5 | trailingComma: 'es5',
6 | bracketSpacing: true,
7 | jsxBracketSameLine: true,
8 | arrowParens: 'always',
9 | parser: 'typescript',
10 | };
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '8'
5 | - '10'
6 | - '12'
7 | before_install:
8 | - npm i npminstall -g
9 | install:
10 | - npminstall
11 | script:
12 | - npm run ci
13 | after_script:
14 | - npminstall codecov && codecov
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Github Repo Charts
4 | 为你的 README 生成 GitHub 仓库成长图,个人数据报表
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 | ## 特性
35 | * [生成仓库成长图表](#生成仓库成长图表)
36 | * [生成仓库语言图](#生成仓库语言图)
37 | * [全部 Demo](#全部-Demo)
38 | * [开发](#开发)
39 | * [TODO](#TODO)
40 |
41 | ## 生成仓库成长图表
42 |
43 | > Github Star 成长图例是循环访问了 Github API 并获取到仓库的 Star 列表,由于 API 的限制,我们不能完美的获取到所有 Star 和其对应的时间节点,所以只提供了少于 500Star 项目的图例,如果你的项目 Star 数超过500,那么图例也仅仅会渲染前500条,姑且认为超过500条的项目已经是稍微成熟点的项目了,哈哈
44 |
45 | #### 生成 Stars 图表
46 |
47 | 将以下代码复制到你的 markdown 文件中,即可欣赏你的仓库成长图了
48 | 需要更新 `repo=` 为你的仓库名称,`owner=` 为你的用户名称
49 |
50 | ```md
51 | 
52 | ```
53 |
54 | #### 设置标题与副标题
55 |
56 | 在图例中,我们默认使用 `${owner}/${repo}` 的形式作为主标题,`Star 成长曲线` 作为副标题,你也可以通过传参来修改他们
57 | 修改 `title=` 为你的主标题,`subtitle=` 为你的副标题
58 | 你也可以使用 `showTitle=true` 或者 `showSubtitle=false` 来控制主标题与副标题的隐藏
59 | ```md
60 | 
61 | ```
62 |
63 | #### 生成 Forks 图表
64 |
65 | > Forks 与 Stars 的原因一样,出于 Github API 的限制,我们只能获取到500条数据
66 |
67 |
68 | 以下代码即可生成Forks成长图例,或许你已经注意到,我们只是加了一个特殊的参数 `from=fork`,`from`参数用于区分数据来源于`star`还是`fork`,如果你不传递该参数,则默认使用`star`,其他参数与获取 Star 图例的接口一致
69 |
70 | ```md
71 | 
72 | ```
73 |
74 | ## 生成仓库语言图
75 |
76 | 该图例支持两种生成方式,当 `owner=` 不为空时,会获得该用户名下所有仓库的语言图,如果 `owner=` 和 `repo=` 皆不为空的时候,会生成该仓库的语言图
77 | > 图例的颜色选项来自 GitHub, GitHub 对每一种语言都有唯一的颜色定义
78 |
79 | #### 获取用户所有语言
80 | ```md
81 | 
82 | ```
83 |
84 |
85 |
86 |
87 |
88 |
89 | #### 获取单个仓库语言
90 |
91 | ```md
92 | 
93 | ```
94 |
95 |
96 |
97 |
98 |
99 | ## 全部 Demo
100 | 
101 | 
102 | 
103 |
104 | ## 开发
105 |
106 | 如果你有意参与此项目,或者你仅仅只是想本地运行,那么你只需要以下步骤即可正常运行
107 |
108 | #### 步骤一
109 | 我们需要你把项目正确的clone下来,并安装相关依赖,需要注意的是,项目中含有 [puppeteer](https://github.com/puppeteer/puppeteer) 相关依赖,如果存在下载不成功的情况,请参阅其他文档
110 |
111 | ```bash
112 | git clone https://github.com/TaroXin/github-repo-charts.git
113 | cd github-repo-charts && npm i
114 | ```
115 |
116 | #### 步骤二
117 | 新建 `.env` 文件,这是我们的私有变量文件,存储个人的`Github Access Token`以及我们需要用作数据缓存的`Redis`相关配置,以下配置不可用,需要你配置好自己的数据
118 | ```bash
119 | GITHUB_ACCESS_TOKEN=
120 |
121 | REDIS_IP=
122 | REDIS_PORT=
123 | REDIS_PASSWORD=
124 |
125 | ```
126 |
127 | #### 步骤三
128 | 运行项目,并访问
129 | ```bash
130 | npm run dev
131 | open http://localhost:7001/api/repo/starChart
132 | ```
133 | 你会得到一个`422`错误,来提醒你缺少相应的参数配置
134 |
135 | ## TODO
136 | * 生成原创项目 Star 与 Fork 对比柱状图
137 | * 生成 Github 数据主页
138 | * Docker 私有化部署
--------------------------------------------------------------------------------
/app.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg'
2 | import 'reflect-metadata'
3 | import { createApolloFetch } from 'apollo-fetch'
4 | require('dotenv').config({ path: '.env' })
5 |
6 | export default (app: Application) => {
7 | app.ready(async () => {
8 | console.log('====== application ready =======')
9 |
10 | const apolloFetch = createApolloFetch({
11 | uri: 'https://api.github.com/graphql',
12 | })
13 |
14 | apolloFetch.use(({ options }, next) => {
15 | if (!options.headers) {
16 | options.headers = {}
17 | }
18 | options.headers[
19 | 'authorization'
20 | ] = `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`
21 | options.headers['Accept'] = 'application/vnd.github.cloak-preview'
22 | options.headers['Content-Type'] = 'application/json'
23 | next()
24 | })
25 | app.apolloFetch = apolloFetch
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/app/controller/home.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from 'egg'
2 |
3 | export default class HomeController extends Controller {
4 | public async test() {
5 | const { ctx } = this
6 |
7 | ctx.resSucc({
8 | result: 'Get it',
9 | })
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/controller/repo.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from 'egg'
2 | import { formatLanguageList } from '../utils'
3 |
4 | export default class RepoController extends Controller {
5 | /**
6 | * @name 获取仓库的Star成长图表
7 | * @router get /api/repo/starChart
8 | */
9 | public async starChart() {
10 | const { ctx, app } = this
11 | const params = ctx.validate(app.validator.repo.starChart, ctx.query, {
12 | allowUnknown: true,
13 | })
14 |
15 | const {
16 | repo,
17 | owner,
18 | title,
19 | subtitle,
20 | showTitle,
21 | showSubtitle,
22 | from,
23 | } = params.value
24 |
25 | const repoFullname = `${owner}/${repo}`
26 | const cacheKey = `${repoFullname}/${from}`
27 | const cacheData = await app.redis.get(cacheKey)
28 | let dataList: any[] = []
29 | if (cacheData) {
30 | dataList = JSON.parse(cacheData)
31 | } else {
32 | if (from === 'star') {
33 | const [
34 | totalCount,
35 | createdAt,
36 | ] = await ctx.service.star.getStarTotalCount(repo, owner)
37 | dataList = await ctx.service.star.getStarListWithREST(
38 | repo,
39 | owner,
40 | totalCount,
41 | createdAt
42 | )
43 | await app.redis.set(
44 | cacheKey,
45 | JSON.stringify(dataList),
46 | 'EX',
47 | 3600 * 2 // redis 缓存请求结果 2小时
48 | )
49 | } else {
50 | const [
51 | totalCount,
52 | createdAt,
53 | ] = await ctx.service.fork.getStarTotalCount(repo, owner)
54 | dataList = await ctx.service.fork.getForkListWithREST(
55 | repo,
56 | owner,
57 | totalCount,
58 | createdAt
59 | )
60 | await app.redis.set(
61 | cacheKey,
62 | JSON.stringify(dataList),
63 | 'EX',
64 | 3600 * 2 // redis 缓存请求结果 2小时
65 | )
66 | }
67 | }
68 |
69 | const defaultSubtitle =
70 | from === 'star' ? 'Star成长曲线图' : 'Fork成长曲线图'
71 | await ctx.resCharts(dataList, {
72 | title: title || repoFullname,
73 | subtitle: subtitle || defaultSubtitle,
74 | theme: 'default',
75 | showTitle,
76 | showSubtitle,
77 | })
78 | }
79 |
80 | /**
81 | * @name 获取语言玫瑰图
82 | * @router get /api/repo/languageChart
83 | */
84 | public async languageChart() {
85 | const { ctx, app } = this
86 | const params = ctx.validate(app.validator.repo.languageChart, ctx.query, {
87 | allowUnknown: true,
88 | })
89 |
90 | const { owner, repo } = params.value
91 |
92 | const cacheKey = repo ? `language/${owner}/${repo}` : `language/${owner}`
93 | const cacheData = await app.redis.get(cacheKey)
94 | let dataList: any[] = []
95 | let colors: string[] = []
96 | let legendItems: string[] = []
97 | if (cacheData) {
98 | const [nodes, colorNodes, items] = formatLanguageList(
99 | JSON.parse(cacheData),
100 | !!repo
101 | )
102 | dataList = nodes
103 | colors = colorNodes
104 | legendItems = items
105 | } else {
106 | const loadedData = await ctx.service.language.getLanguageList(owner, repo)
107 | await app.redis.set(
108 | cacheKey,
109 | JSON.stringify(loadedData),
110 | 'EX',
111 | 3600 * 2 // redis 缓存请求结果 2小时
112 | )
113 | const [nodes, colorNodes, items] = formatLanguageList(loadedData, !!repo)
114 | dataList = nodes
115 | colors = colorNodes
116 | legendItems = items
117 | }
118 |
119 | await ctx.resCharts(
120 | dataList,
121 | {
122 | title: `${owner}'s Language`,
123 | subtitle: '',
124 | showTitle: true,
125 | showSubtitle: true,
126 | theme: 'default',
127 | colors,
128 | legendItems,
129 | },
130 | 'language'
131 | )
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/app/entity/ChartsOptions.ts:
--------------------------------------------------------------------------------
1 | export default class ChartsOptions {
2 | title: string
3 | subtitle: string
4 | theme?: 'default' = 'default'
5 | showTitle? = true
6 | showSubtitle? = true
7 | colors?: string[] = []
8 | legendItems?: string[] = []
9 | }
10 |
--------------------------------------------------------------------------------
/app/extend/context.ts:
--------------------------------------------------------------------------------
1 | // app/extend/context.ts
2 | import { Context } from 'egg'
3 | import { starChartsRender, languageChartsRender } from '../utils/charts-render'
4 | import ChartsOptions from '../entity/ChartsOptions'
5 |
6 | export default {
7 | resSucc(this: Context, data: Record = {}) {
8 | this.body = {
9 | code: 0,
10 | data,
11 | }
12 | },
13 |
14 | resFail(this: Context, message: string) {
15 | this.body = {
16 | code: 30001,
17 | message,
18 | }
19 | },
20 |
21 | resParamError(this: Context, message = '请求参数不符合接口规则') {
22 | this.body = {
23 | code: 30002,
24 | message,
25 | }
26 | },
27 |
28 | resDataError(this: Context, message = '请求参数错误', code = 30003) {
29 | this.body = {
30 | code,
31 | message,
32 | }
33 | },
34 |
35 | async resCharts(
36 | this: Context,
37 | data: any[],
38 | options: ChartsOptions,
39 | type: 'star' | 'language' = 'star'
40 | ) {
41 | let svg = ''
42 | switch (type) {
43 | case 'star':
44 | svg = await starChartsRender(data, options)
45 | break
46 | case 'language':
47 | svg = await languageChartsRender(data, options)
48 | break
49 | }
50 | this.set('content-type', 'image/svg+xml;charset=utf-8')
51 | this.set('cache-control', 'public, max-age=86400')
52 | this.set('date', new Date().toDateString())
53 | this.set('expires', new Date(Date.now() + 3600 * 2 * 1000).toDateString())
54 | this.body = svg
55 | },
56 | }
57 |
--------------------------------------------------------------------------------
/app/extend/helper.ts:
--------------------------------------------------------------------------------
1 | // import { IHelper } from 'egg'
2 |
3 | export default {
4 | // async requestGithubGraphQL(this: IHelper, query: string) {
5 | // //
6 | // },
7 | }
8 |
--------------------------------------------------------------------------------
/app/router.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg'
2 |
3 | export default (app: Application) => {
4 | // const { controller, router, jwt } = app
5 | const { controller, router } = app
6 |
7 | router.get('/', controller.home.test)
8 |
9 | // 仓库相关
10 | const repoRouteBase = '/api/repo'
11 | router.get(`${repoRouteBase}/starChart`, app.controller.repo.starChart)
12 | router.get(
13 | `${repoRouteBase}/languageChart`,
14 | app.controller.repo.languageChart
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/app/service/fork.ts:
--------------------------------------------------------------------------------
1 | import { Service } from 'egg'
2 | import { RequestOptions2 as RequestOptions } from 'urllib'
3 |
4 | export default class FormService extends Service {
5 | // 获得Fork总数目 [totalCount, createdAt]
6 | async getStarTotalCount(
7 | repo: string,
8 | owner: string
9 | ): Promise<[number, string]> {
10 | const { ctx, app } = this
11 | const query = `
12 | query($repo: String!, $owner: String!) {
13 | repository(name: $repo, owner: $owner) {
14 | createdAt
15 | forks {
16 | totalCount
17 | }
18 | }
19 | }
20 | `
21 |
22 | const { errors, data } = await app.apolloFetch({
23 | query,
24 | variables: {
25 | repo,
26 | owner,
27 | },
28 | })
29 |
30 | if (errors) {
31 | const message = errors.length ? errors[0].message : errors
32 | ctx.resDataError(message)
33 | throw new Error(message)
34 | }
35 |
36 | return [data.repository.forks.totalCount, data.repository.createdAt]
37 | }
38 |
39 | // 获取 Fork 列表
40 | async getForkListWithREST(
41 | repo: string,
42 | owner: string,
43 | totalCount: number,
44 | createdAt: string
45 | ): Promise {
46 | console.log('获取仓库Fork列表', `${owner}/${repo}`)
47 |
48 | const { ctx } = this
49 | const options: RequestOptions = {
50 | headers: {
51 | Accept: 'application/vnd.github.v3.star+json',
52 | Authorization: 'bearer ' + process.env.GITHUB_ACCESS_TOKEN,
53 | },
54 | contentType: 'json',
55 | timeout: 1000 * 60,
56 | retry: 7,
57 | }
58 |
59 | const url = `https://api.github.com/repos/${owner}/${repo}/forks`
60 | let promises: Promise[] = []
61 | if (totalCount <= 500) {
62 | promises = new Array(Math.ceil(totalCount / 100)).fill(null)
63 | promises = promises.map((_, index) => {
64 | return new Promise(async (resolve) => {
65 | const res = await ctx.curl(
66 | `${url}?page=${index + 1}&per_page=100&sort=oldest`,
67 | options
68 | )
69 | resolve(JSON.parse(res.data.toString()))
70 | })
71 | })
72 | } else {
73 | // Forks 也500个
74 | promises = new Array(5).fill(null)
75 | promises = promises.map((_, index) => {
76 | return new Promise(async (resolve) => {
77 | const res = await ctx.curl(
78 | `${url}?page=${index + 1}&per_page=100&sort=oldest`,
79 | options
80 | )
81 | resolve(JSON.parse(res.data.toString()))
82 | })
83 | })
84 | }
85 |
86 | const data: any[] = []
87 | if (promises.length) {
88 | const list = await Promise.all(promises)
89 | list.forEach((item) => data.push(...item))
90 | }
91 |
92 | // 第一个 Fork 为 0 的时候应该是项目创建的时候
93 | // eslint-disable-next-line @typescript-eslint/camelcase
94 | data.unshift({ created_at: createdAt })
95 | return data.map((item, index) => ({
96 | name: item.created_at,
97 | value: [item.created_at, index],
98 | }))
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/service/home.ts:
--------------------------------------------------------------------------------
1 | import { Service } from 'egg'
2 |
3 | export default class HomeService extends Service {
4 | //
5 | }
6 |
--------------------------------------------------------------------------------
/app/service/language.ts:
--------------------------------------------------------------------------------
1 | import { Service } from 'egg'
2 |
3 | export default class LanguageService extends Service {
4 | // 获得仓库语言占比列表
5 | async getLanguageList(owner: string, repo?: string): Promise {
6 | const { ctx, app } = this
7 | const query = `
8 | query($owner: String!) {
9 | user(login: $owner) {
10 | repositories(first: 100) {
11 | nodes {
12 | isFork
13 | languages(first: 10) {
14 | edges {
15 | size
16 | node {
17 | color
18 | name
19 | id
20 | }
21 | }
22 | totalSize
23 | }
24 | }
25 | }
26 | }
27 | }
28 | `
29 |
30 | const repoQuery = `
31 | query($owner: String!, $repo: String!) {
32 | user(login: $owner) {
33 | repository(name: $repo) {
34 | isFork
35 | languages(first: 10) {
36 | edges {
37 | size
38 | node {
39 | color
40 | name
41 | id
42 | }
43 | }
44 | totalSize
45 | }
46 | }
47 | }
48 | }
49 | `
50 |
51 | const { errors, data } = await app.apolloFetch({
52 | query: repo ? repoQuery : query,
53 | variables: repo
54 | ? {
55 | owner,
56 | repo,
57 | }
58 | : {
59 | owner,
60 | },
61 | })
62 |
63 | if (errors) {
64 | const message = errors.length ? errors[0].message : errors
65 | ctx.resDataError(message)
66 | throw new Error(message)
67 | }
68 |
69 | return data
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/service/star.ts:
--------------------------------------------------------------------------------
1 | import { Service } from 'egg'
2 | import { RequestOptions2 as RequestOptions } from 'urllib'
3 |
4 | export default class StarService extends Service {
5 | // 获得Star总数目 [totalCount, createdAt]
6 | async getStarTotalCount(
7 | repo: string,
8 | owner: string
9 | ): Promise<[number, string]> {
10 | const { ctx, app } = this
11 | const query = `
12 | query($repo: String!, $owner: String!) {
13 | repository(name: $repo, owner: $owner) {
14 | createdAt
15 | stargazers {
16 | totalCount
17 | }
18 | }
19 | }
20 | `
21 |
22 | const { errors, data } = await app.apolloFetch({
23 | query,
24 | variables: {
25 | repo,
26 | owner,
27 | },
28 | })
29 |
30 | if (errors) {
31 | const message = errors.length ? errors[0].message : errors
32 | ctx.resDataError(message)
33 | throw new Error(message)
34 | }
35 |
36 | return [data.repository.stargazers.totalCount, data.repository.createdAt]
37 | }
38 |
39 | // 获取 Star 列表
40 | async getStarListWithREST(
41 | repo: string,
42 | owner: string,
43 | totalCount: number,
44 | createdAt: string
45 | ): Promise {
46 | console.log('获取仓库Star列表', `${owner}/${repo}`)
47 |
48 | const { ctx } = this
49 | const options: RequestOptions = {
50 | headers: {
51 | Accept: 'application/vnd.github.v3.star+json',
52 | Authorization: 'bearer ' + process.env.GITHUB_ACCESS_TOKEN,
53 | },
54 | contentType: 'json',
55 | timeout: 1000 * 60,
56 | retry: 7,
57 | }
58 |
59 | const url = `https://api.github.com/repos/${owner}/${repo}/stargazers`
60 | let promises: Promise[] = []
61 | if (totalCount <= 500) {
62 | promises = new Array(Math.ceil(totalCount / 100)).fill(null)
63 | promises = promises.map((_, index) => {
64 | return new Promise(async (resolve) => {
65 | const res = await ctx.curl(
66 | `${url}?page=${index + 1}&per_page=100`,
67 | options
68 | )
69 | resolve(JSON.parse(res.data.toString()))
70 | })
71 | })
72 | } else {
73 | // 对大于1000star的项目采用抽样形式,无法做到较为精确
74 | // 抽样有限制,Github API限制页数过多的请求,不知道怎么解决
75 | // 1000 个也搞不了,哎,五百个吧😌
76 | promises = new Array(5).fill(null)
77 | promises = promises.map((_, index) => {
78 | return new Promise(async (resolve) => {
79 | const res = await ctx.curl(
80 | `${url}?page=${index + 1}&per_page=100`,
81 | options
82 | )
83 | resolve(JSON.parse(res.data.toString()))
84 | })
85 | })
86 | }
87 |
88 | const data: any[] = []
89 | if (promises.length) {
90 | const list = await Promise.all(promises)
91 | list.forEach((item) => data.push(...item))
92 | }
93 |
94 | // 第一个Star为0的时候应该是项目创建的时候
95 | // eslint-disable-next-line @typescript-eslint/camelcase
96 | data.unshift({ starred_at: createdAt })
97 | return data.map((item, index) => ({
98 | name: item.starred_at,
99 | value: [item.starred_at, index],
100 | }))
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/utils/charts-render.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 | import puppeteer = require('puppeteer')
3 | import ChartsOptions from '../entity/ChartsOptions'
4 |
5 | const render = async (options): Promise => {
6 | const browser = await puppeteer.launch({
7 | args: ['--no-sandbox'],
8 | })
9 |
10 | const page = await browser.newPage()
11 | await page.setContent(`
12 |
13 | `)
14 |
15 | await page.evaluate((options) => {
16 | // @ts-ignore
17 | window.chart = {
18 | options,
19 | }
20 | }, options)
21 |
22 | await page.addScriptTag({
23 | url: 'https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js',
24 | })
25 |
26 | //echarts 初始化脚本注入页面
27 | await page.addScriptTag({
28 | content: `
29 | (function (window) {
30 | let option = window.chart.options;
31 | var myChart = window.echarts.init(document.getElementById('container'), null, {
32 | renderer: 'svg'
33 | });
34 | myChart.setOption(option);
35 | })(this);
36 | `,
37 | })
38 |
39 | const eles = await page.$eval('#container svg', (el) => el.outerHTML)
40 | await page.close()
41 | await browser.close()
42 | return eles
43 | }
44 |
45 | export async function starChartsRender(
46 | data: any[],
47 | options: ChartsOptions
48 | ): Promise {
49 | const optionData = require(`../../charts-theme/star/${options.theme}.js`)(
50 | data,
51 | options
52 | )
53 | return await render(optionData)
54 | }
55 |
56 | export async function languageChartsRender(
57 | data: any[],
58 | options: ChartsOptions
59 | ): Promise {
60 | const optionData = require(`../../charts-theme/language/${options.theme}.js`)(
61 | data,
62 | options
63 | )
64 | return await render(optionData)
65 | }
66 |
--------------------------------------------------------------------------------
/app/utils/index.ts:
--------------------------------------------------------------------------------
1 | // 格式化语言数组
2 | export function formatLanguageList(
3 | data: any,
4 | hasRepo: boolean
5 | ): [any[], string[], string[]] {
6 | const nodes: any = []
7 | if (hasRepo) {
8 | data.user.repository.languages.edges.forEach((item) => {
9 | const exists = nodes.find((el) => el.id === item.node.id)
10 | if (exists) {
11 | exists.value += item.size
12 | } else {
13 | nodes.push({
14 | ...item.node,
15 | value: item.size,
16 | })
17 | }
18 | })
19 | } else {
20 | data.user.repositories.nodes.forEach((l) => {
21 | if (l.languages.edges && !l.isFork) {
22 | l.languages.edges.forEach((item) => {
23 | const exists = nodes.find((el) => el.id === item.node.id)
24 | if (exists) {
25 | exists.value += item.size
26 | } else {
27 | nodes.push({
28 | ...item.node,
29 | value: item.size,
30 | })
31 | }
32 | })
33 | }
34 | })
35 | }
36 |
37 | nodes.sort((a, b) => b.value - a.value)
38 | const colors = nodes.map((item) => item.color)
39 | const items = nodes.map((item) => item.name)
40 | return [nodes, colors, items]
41 | }
42 |
--------------------------------------------------------------------------------
/app/validator/home.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg'
2 |
3 | export default (app: Application) => {
4 | const { Joi } = app
5 |
6 | return {
7 | // Joi常用的验证类型
8 | index: Joi.object()
9 | .keys({
10 | // 3 - 30 个 数字、字符
11 | username: Joi.string().alphanum().min(3).max(30).required(),
12 | // 3 - 30 位 字母数字组合密码
13 | password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
14 | // string || number 都可以通过
15 | accessToken: [Joi.string(), Joi.number()],
16 | // 生日限制
17 | birthyear: Joi.number().integer().min(1900).max(2018),
18 | // email 限制
19 | email: Joi.string().email(),
20 | // URI限制
21 | website: Joi.string().uri({
22 | scheme: ['git', /git\+https?/],
23 | }),
24 | // ==== 允许为空/ 否认不允许为空 ====
25 | search: Joi.string().allow(''),
26 | // 验证枚举值,如果不传,默认为all
27 | type: Joi.string().valid('disabled', 'normal', 'all').default('all'),
28 | // 开始时间 会自动格式化
29 | startTime: Joi.date().min('1-1-1974').max('now'),
30 | // 结束时间 必须大于开始时间,小于2100
31 | endTime: Joi.when(Joi.ref('startTime'), {
32 | is: Joi.date().required(),
33 | then: Joi.date().max('1-1-2100'),
34 | }),
35 | // 页码 限制最小值
36 | page: Joi.number().integer().min(1).default(1),
37 | pageSize: Joi.number().integer().default(8),
38 | //
39 | deleteWhenLtTen: Joi.number().integer().max(10).strip(),
40 | // 数组中包含某个字段 && 数字
41 | arrayString: Joi.array().items(
42 | // 数组中必须包含 name1
43 | Joi.string().label('name1').required(),
44 | // 数组中必须包含 数字
45 | Joi.number().required(),
46 | // 数组中可以包含其他类型,如bool, 但是最终结果会==除掉【以上类型的以外字段】
47 | Joi.any().strip()
48 | ),
49 | // 数组对象, 如需其参考以上字段
50 | arrayObject: Joi.array().items(
51 | Joi.object().keys({
52 | age: Joi.number().integer().max(200),
53 | sex: Joi.boolean(),
54 | })
55 | ),
56 | })
57 | // with 中必须同时存在某些字段,故不可以填写一个参数
58 | .with('username', 'password')
59 | // .without() 同理,不可以一个字段,不能同时存在
60 | .without('a', 'b'),
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/validator/repo.ts:
--------------------------------------------------------------------------------
1 | import { Application } from 'egg'
2 |
3 | export default (app: Application) => {
4 | const { Joi } = app
5 |
6 | return {
7 | // Joi常用的验证类型
8 | starChart: Joi.object().keys({
9 | repo: Joi.string().required(),
10 | owner: Joi.string().required(),
11 | title: Joi.string(),
12 | subtitle: Joi.string(),
13 | showTitle: Joi.boolean().default(true),
14 | showSubtitle: Joi.boolean().default(true),
15 | from: Joi.string().valid('star', 'fork').default('star'),
16 | }),
17 |
18 | languageChart: Joi.object().keys({
19 | owner: Joi.string().required(),
20 | repo: Joi.string(),
21 | }),
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 | - nodejs_version: '10'
5 | - nodejs_version: '12'
6 |
7 | install:
8 | - ps: Install-Product node $env:nodejs_version
9 | - npm i npminstall && node_modules\.bin\npminstall
10 |
11 | test_script:
12 | - node --version
13 | - npm --version
14 | - npm run test
15 |
16 | build: off
17 |
--------------------------------------------------------------------------------
/charts-theme/language/default.js:
--------------------------------------------------------------------------------
1 | module.exports = (data, options) => {
2 | const defaultColors = [
3 | '#c23531',
4 | '#2f4554',
5 | '#61a0a8',
6 | '#d48265',
7 | '#91c7ae',
8 | '#749f83',
9 | '#ca8622',
10 | '#bda29a',
11 | '#6e7074',
12 | '#546570',
13 | '#c4ccd3',
14 | ]
15 |
16 | let legend = {
17 | left: 'center',
18 | top: 'bottom',
19 | data: options.legendItems,
20 | }
21 |
22 | if (options.legendItems.length > 5) {
23 | const tempArray = new Array(Math.ceil(options.legendItems.length / 5)).fill(
24 | null
25 | )
26 | const bottom = (tempArray.length - 1) * 25
27 | legend = tempArray.map((_, index) => ({
28 | left: 'center',
29 | bottom: bottom - index * 25,
30 | data: options.legendItems.slice(index * 5, index * 5 + 5),
31 | }))
32 | }
33 |
34 | return {
35 | animation: false,
36 | color: options.colors.length ? options.colors : defaultColors,
37 | title: {
38 | show: options.showTitle || options.showSubtitle,
39 | text: options.showTitle ? options.title : '',
40 | textStyle: {
41 | color: '#2468cf',
42 | fontSize: 18,
43 | fontWeight: 'bold',
44 | },
45 | subtext: options.showSubtitle ? 'Powered by github-repo-charts' : '',
46 | subtextStyle: {
47 | color: '#7e848a',
48 | fontSize: 12,
49 | },
50 | left: 'center',
51 | },
52 | legend,
53 | series: [
54 | {
55 | type: 'pie',
56 | radius: [20, 120],
57 | roseType: 'area',
58 | data,
59 | minShowLabelAngle: 5,
60 | label: {
61 | formatter: '{b}: {d}%',
62 | },
63 | },
64 | ],
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/charts-theme/star/default.js:
--------------------------------------------------------------------------------
1 | module.exports = (data, options) => {
2 | const grid = {
3 | left: '3%',
4 | right: '1%',
5 | bottom: '0',
6 | containLabel: true,
7 | }
8 |
9 | if (!options.showTitle && !options.showSubtitle) {
10 | grid.top = '2%'
11 | } else if (!options.showTitle || !options.showSubtitle) {
12 | grid.top = '40px'
13 | }
14 |
15 | return {
16 | animation: false,
17 | title: {
18 | show: options.showTitle || options.showSubtitle,
19 | text: options.showTitle ? options.title : '',
20 | textStyle: {
21 | color: '#2468cf',
22 | fontSize: 18,
23 | fontWeight: 'bold',
24 | },
25 | subtext: options.showSubtitle
26 | ? options.subtitle + '. Powered by github-repo-charts'
27 | : '',
28 | subtextStyle: {
29 | color: '#7e848a',
30 | fontSize: 12,
31 | },
32 | },
33 | grid,
34 | xAxis: [
35 | {
36 | type: 'time',
37 | boundaryGap: false,
38 | nameLocation: 'center',
39 | axisLine: {
40 | show: false,
41 | },
42 | axisTick: {
43 | show: false,
44 | },
45 | },
46 | ],
47 | yAxis: {
48 | position: 'right',
49 | axisLine: {
50 | show: false,
51 | },
52 | axisTick: {
53 | show: false,
54 | },
55 | },
56 | series: [
57 | {
58 | type: 'line',
59 | data,
60 | smooth: true,
61 | smoothMonotone: 'x',
62 | symbol: 'none',
63 | lineStyle: {
64 | color: '#2468cf',
65 | },
66 | areaStyle: {
67 | color: '#2468cf',
68 | },
69 | },
70 | ],
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/config/config.default.ts:
--------------------------------------------------------------------------------
1 | import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'
2 | require('dotenv').config({ path: '.env' })
3 |
4 | export default (appInfo: EggAppInfo) => {
5 | const config = {} as PowerPartial
6 |
7 | config.keys = appInfo.name + '_1585035503822_2810'
8 |
9 | config.middleware = []
10 |
11 | config.security = {
12 | csrf: {
13 | enable: false,
14 | ignoreJSON: true,
15 | },
16 | domainWhiteList: ['*'],
17 | }
18 |
19 | config.cors = {
20 | origin: '*',
21 | credentials: true,
22 | allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
23 | }
24 |
25 | config.joi = {
26 | options: {},
27 | locale: {
28 | 'zh-cn': {},
29 | },
30 | throw: true,
31 | }
32 |
33 | config.redis = {
34 | client: {
35 | port: Number(process.env.REDIS_PORT),
36 | host: process.env.REDIS_IP,
37 | password: process.env.REDIS_PASSWORD,
38 | db: 0,
39 | },
40 | }
41 |
42 | return {
43 | ...config,
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/config/config.prod.ts:
--------------------------------------------------------------------------------
1 | import { EggAppConfig, PowerPartial } from 'egg'
2 |
3 | export default () => {
4 | const config: PowerPartial = {}
5 |
6 | return config
7 | }
8 |
--------------------------------------------------------------------------------
/config/plugin.ts:
--------------------------------------------------------------------------------
1 | import { EggPlugin } from 'egg'
2 |
3 | const plugin: EggPlugin = {
4 | cors: {
5 | enable: true,
6 | package: 'egg-cors',
7 | },
8 |
9 | joi: {
10 | enable: true,
11 | package: 'egg-joi',
12 | },
13 |
14 | redis: {
15 | enable: true,
16 | package: 'egg-redis',
17 | },
18 | }
19 |
20 | export default plugin
21 |
--------------------------------------------------------------------------------
/examples/test.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/html/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/html/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: ['plugin:vue/essential', '@vue/prettier'],
7 | rules: {
8 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
9 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
10 | },
11 | parserOptions: {
12 | parser: 'babel-eslint',
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/html/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | }
6 |
--------------------------------------------------------------------------------
/html/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 2,
3 | singleQuote: true,
4 | semi: false,
5 | trailingComma: 'all',
6 | bracketSpacing: true,
7 | jsxBracketSameLine: false,
8 | arrowParens: 'always',
9 | };
10 |
--------------------------------------------------------------------------------
/html/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@vue/app'],
3 | }
4 |
--------------------------------------------------------------------------------
/html/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaroXin/github-repo-charts/f560458437be50b2188034eb024f86bcedfcbd4b/html/public/favicon.ico
--------------------------------------------------------------------------------
/html/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | html
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/html/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Home |
5 | About
6 |
7 |
8 |
9 |
10 |
11 |
32 |
--------------------------------------------------------------------------------
/html/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaroXin/github-repo-charts/f560458437be50b2188034eb024f86bcedfcbd4b/html/src/assets/logo.png
--------------------------------------------------------------------------------
/html/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
10 |
11 |
Installed CLI Plugins
12 |
30 |
Essential Links
31 |
54 |
Ecosystem
55 |
86 |
87 |
88 |
89 |
97 |
98 |
99 |
115 |
--------------------------------------------------------------------------------
/html/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 |
6 | Vue.config.productionTip = false
7 |
8 | new Vue({
9 | router,
10 | store,
11 | render: (h) => h(App),
12 | }).$mount('#app')
13 |
--------------------------------------------------------------------------------
/html/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from './views/Home.vue'
4 |
5 | Vue.use(Router)
6 |
7 | export default new Router({
8 | mode: 'history',
9 | base: process.env.BASE_URL,
10 | routes: [
11 | {
12 | path: '/',
13 | name: 'home',
14 | component: Home,
15 | },
16 | {
17 | path: '/about',
18 | name: 'about',
19 | // route level code-splitting
20 | // this generates a separate chunk (about.[hash].js) for this route
21 | // which is lazy-loaded when the route is visited.
22 | component: () =>
23 | import(/* webpackChunkName: "about" */ './views/About.vue'),
24 | },
25 | ],
26 | })
27 |
--------------------------------------------------------------------------------
/html/src/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {},
8 | mutations: {},
9 | actions: {},
10 | })
11 |
--------------------------------------------------------------------------------
/html/src/views/About.vue:
--------------------------------------------------------------------------------
1 | ;
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/html/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/laboratory/echartsOptions.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | legend: {
3 | width: 600,
4 | height: 400,
5 | },
6 | animation: false,
7 | title: {
8 | text: 'juejin-im/open-source',
9 | subtext: 'Star growth curve',
10 | },
11 | grid: {
12 | left: '3%',
13 | right: '1%',
14 | bottom: '0',
15 | containLabel: true,
16 | },
17 | xAxis: [
18 | {
19 | type: 'time',
20 | boundaryGap: false,
21 | },
22 | ],
23 | yAxis: {
24 | position: 'right',
25 | },
26 | series: [
27 | {
28 | type: 'line',
29 | areaStyle: {},
30 | data: [
31 | { name: '2020-08-13T13:11:02Z', value: ['2020-08-13T13:11:02Z', 1] },
32 | { name: '2020-08-13T14:00:52Z', value: ['2020-08-13T14:00:52Z', 2] },
33 | { name: '2020-08-13T15:22:27Z', value: ['2020-08-13T15:22:27Z', 3] },
34 | { name: '2020-08-13T16:39:23Z', value: ['2020-08-13T16:39:23Z', 4] },
35 | { name: '2020-08-13T17:16:46Z', value: ['2020-08-13T17:16:46Z', 5] },
36 | { name: '2020-08-14T08:48:45Z', value: ['2020-08-14T08:48:45Z', 6] },
37 | { name: '2020-08-14T13:30:51Z', value: ['2020-08-14T13:30:51Z', 7] },
38 | { name: '2020-08-15T01:01:56Z', value: ['2020-08-15T01:01:56Z', 8] },
39 | { name: '2020-08-15T03:21:12Z', value: ['2020-08-15T03:21:12Z', 9] },
40 | { name: '2020-08-15T03:29:45Z', value: ['2020-08-15T03:29:45Z', 10] },
41 | { name: '2020-08-15T03:30:28Z', value: ['2020-08-15T03:30:28Z', 11] },
42 | { name: '2020-08-15T03:46:53Z', value: ['2020-08-15T03:46:53Z', 12] },
43 | { name: '2020-08-15T04:16:02Z', value: ['2020-08-15T04:16:02Z', 13] },
44 | { name: '2020-08-15T05:03:41Z', value: ['2020-08-15T05:03:41Z', 14] },
45 | { name: '2020-08-15T05:21:43Z', value: ['2020-08-15T05:21:43Z', 15] },
46 | { name: '2020-08-15T05:26:24Z', value: ['2020-08-15T05:26:24Z', 16] },
47 | { name: '2020-08-15T06:08:24Z', value: ['2020-08-15T06:08:24Z', 17] },
48 | { name: '2020-08-15T06:47:33Z', value: ['2020-08-15T06:47:33Z', 18] },
49 | { name: '2020-08-15T07:13:24Z', value: ['2020-08-15T07:13:24Z', 19] },
50 | { name: '2020-08-15T07:23:55Z', value: ['2020-08-15T07:23:55Z', 20] },
51 | { name: '2020-08-15T08:51:39Z', value: ['2020-08-15T08:51:39Z', 21] },
52 | { name: '2020-08-15T09:58:48Z', value: ['2020-08-15T09:58:48Z', 22] },
53 | { name: '2020-08-15T11:09:59Z', value: ['2020-08-15T11:09:59Z', 23] },
54 | { name: '2020-08-15T12:35:57Z', value: ['2020-08-15T12:35:57Z', 24] },
55 | { name: '2020-08-15T13:24:11Z', value: ['2020-08-15T13:24:11Z', 25] },
56 | { name: '2020-08-15T15:46:52Z', value: ['2020-08-15T15:46:52Z', 26] },
57 | { name: '2020-08-15T17:36:52Z', value: ['2020-08-15T17:36:52Z', 27] },
58 | { name: '2020-08-15T19:27:32Z', value: ['2020-08-15T19:27:32Z', 28] },
59 | { name: '2020-08-16T00:21:20Z', value: ['2020-08-16T00:21:20Z', 29] },
60 | { name: '2020-08-16T05:06:10Z', value: ['2020-08-16T05:06:10Z', 30] },
61 | { name: '2020-08-16T08:10:18Z', value: ['2020-08-16T08:10:18Z', 31] },
62 | { name: '2020-08-16T09:21:42Z', value: ['2020-08-16T09:21:42Z', 32] },
63 | { name: '2020-08-16T10:08:52Z', value: ['2020-08-16T10:08:52Z', 33] },
64 | { name: '2020-08-16T12:00:35Z', value: ['2020-08-16T12:00:35Z', 34] },
65 | { name: '2020-08-16T13:36:17Z', value: ['2020-08-16T13:36:17Z', 35] },
66 | { name: '2020-08-16T13:45:30Z', value: ['2020-08-16T13:45:30Z', 36] },
67 | { name: '2020-08-16T14:45:24Z', value: ['2020-08-16T14:45:24Z', 37] },
68 | { name: '2020-08-16T15:12:47Z', value: ['2020-08-16T15:12:47Z', 38] },
69 | { name: '2020-08-16T15:17:17Z', value: ['2020-08-16T15:17:17Z', 39] },
70 | { name: '2020-08-16T15:31:55Z', value: ['2020-08-16T15:31:55Z', 40] },
71 | { name: '2020-08-16T15:42:20Z', value: ['2020-08-16T15:42:20Z', 41] },
72 | { name: '2020-08-16T22:18:22Z', value: ['2020-08-16T22:18:22Z', 42] },
73 | { name: '2020-08-17T00:11:23Z', value: ['2020-08-17T00:11:23Z', 43] },
74 | { name: '2020-08-17T00:22:43Z', value: ['2020-08-17T00:22:43Z', 44] },
75 | { name: '2020-08-17T00:51:43Z', value: ['2020-08-17T00:51:43Z', 45] },
76 | { name: '2020-08-17T01:01:55Z', value: ['2020-08-17T01:01:55Z', 46] },
77 | { name: '2020-08-17T01:04:00Z', value: ['2020-08-17T01:04:00Z', 47] },
78 | { name: '2020-08-17T01:13:34Z', value: ['2020-08-17T01:13:34Z', 48] },
79 | { name: '2020-08-17T01:15:48Z', value: ['2020-08-17T01:15:48Z', 49] },
80 | { name: '2020-08-17T01:22:22Z', value: ['2020-08-17T01:22:22Z', 50] },
81 | { name: '2020-08-17T01:32:01Z', value: ['2020-08-17T01:32:01Z', 51] },
82 | { name: '2020-08-17T01:37:57Z', value: ['2020-08-17T01:37:57Z', 52] },
83 | { name: '2020-08-17T01:44:58Z', value: ['2020-08-17T01:44:58Z', 53] },
84 | { name: '2020-08-17T01:48:42Z', value: ['2020-08-17T01:48:42Z', 54] },
85 | { name: '2020-08-17T02:00:41Z', value: ['2020-08-17T02:00:41Z', 55] },
86 | { name: '2020-08-17T02:12:08Z', value: ['2020-08-17T02:12:08Z', 56] },
87 | { name: '2020-08-17T02:13:52Z', value: ['2020-08-17T02:13:52Z', 57] },
88 | { name: '2020-08-17T02:28:00Z', value: ['2020-08-17T02:28:00Z', 58] },
89 | { name: '2020-08-17T03:10:22Z', value: ['2020-08-17T03:10:22Z', 59] },
90 | { name: '2020-08-17T03:51:42Z', value: ['2020-08-17T03:51:42Z', 60] },
91 | { name: '2020-08-17T04:12:35Z', value: ['2020-08-17T04:12:35Z', 61] },
92 | { name: '2020-08-17T04:34:10Z', value: ['2020-08-17T04:34:10Z', 62] },
93 | { name: '2020-08-17T04:42:39Z', value: ['2020-08-17T04:42:39Z', 63] },
94 | { name: '2020-08-17T05:03:16Z', value: ['2020-08-17T05:03:16Z', 64] },
95 | { name: '2020-08-17T05:17:31Z', value: ['2020-08-17T05:17:31Z', 65] },
96 | { name: '2020-08-17T05:19:49Z', value: ['2020-08-17T05:19:49Z', 66] },
97 | { name: '2020-08-17T05:24:58Z', value: ['2020-08-17T05:24:58Z', 67] },
98 | { name: '2020-08-17T05:37:01Z', value: ['2020-08-17T05:37:01Z', 68] },
99 | { name: '2020-08-17T05:42:54Z', value: ['2020-08-17T05:42:54Z', 69] },
100 | { name: '2020-08-17T06:10:34Z', value: ['2020-08-17T06:10:34Z', 70] },
101 | { name: '2020-08-17T07:27:43Z', value: ['2020-08-17T07:27:43Z', 71] },
102 | { name: '2020-08-17T07:34:02Z', value: ['2020-08-17T07:34:02Z', 72] },
103 | { name: '2020-08-17T07:35:14Z', value: ['2020-08-17T07:35:14Z', 73] },
104 | { name: '2020-08-17T07:55:52Z', value: ['2020-08-17T07:55:52Z', 74] },
105 | { name: '2020-08-17T08:02:56Z', value: ['2020-08-17T08:02:56Z', 75] },
106 | { name: '2020-08-17T08:13:53Z', value: ['2020-08-17T08:13:53Z', 76] },
107 | { name: '2020-08-17T09:31:04Z', value: ['2020-08-17T09:31:04Z', 77] },
108 | { name: '2020-08-17T10:02:39Z', value: ['2020-08-17T10:02:39Z', 78] },
109 | { name: '2020-08-17T10:45:19Z', value: ['2020-08-17T10:45:19Z', 79] },
110 | { name: '2020-08-17T10:57:12Z', value: ['2020-08-17T10:57:12Z', 80] },
111 | { name: '2020-08-17T11:01:16Z', value: ['2020-08-17T11:01:16Z', 81] },
112 | { name: '2020-08-17T11:57:50Z', value: ['2020-08-17T11:57:50Z', 82] },
113 | { name: '2020-08-17T12:10:51Z', value: ['2020-08-17T12:10:51Z', 83] },
114 | { name: '2020-08-17T12:25:26Z', value: ['2020-08-17T12:25:26Z', 84] },
115 | { name: '2020-08-17T13:17:59Z', value: ['2020-08-17T13:17:59Z', 85] },
116 | { name: '2020-08-17T13:19:34Z', value: ['2020-08-17T13:19:34Z', 86] },
117 | { name: '2020-08-17T14:09:22Z', value: ['2020-08-17T14:09:22Z', 87] },
118 | { name: '2020-08-17T14:33:56Z', value: ['2020-08-17T14:33:56Z', 88] },
119 | { name: '2020-08-17T16:53:39Z', value: ['2020-08-17T16:53:39Z', 89] },
120 | { name: '2020-08-18T01:15:48Z', value: ['2020-08-18T01:15:48Z', 90] },
121 | { name: '2020-08-18T01:25:49Z', value: ['2020-08-18T01:25:49Z', 91] },
122 | { name: '2020-08-18T01:28:50Z', value: ['2020-08-18T01:28:50Z', 92] },
123 | { name: '2020-08-18T01:32:25Z', value: ['2020-08-18T01:32:25Z', 93] },
124 | { name: '2020-08-18T01:41:28Z', value: ['2020-08-18T01:41:28Z', 94] },
125 | { name: '2020-08-18T02:04:54Z', value: ['2020-08-18T02:04:54Z', 95] },
126 | { name: '2020-08-18T02:10:19Z', value: ['2020-08-18T02:10:19Z', 96] },
127 | { name: '2020-08-18T02:21:15Z', value: ['2020-08-18T02:21:15Z', 97] },
128 | { name: '2020-08-18T02:22:04Z', value: ['2020-08-18T02:22:04Z', 98] },
129 | { name: '2020-08-18T02:40:44Z', value: ['2020-08-18T02:40:44Z', 99] },
130 | { name: '2020-08-18T03:24:32Z', value: ['2020-08-18T03:24:32Z', 100] },
131 | { name: '2020-08-18T03:45:50Z', value: ['2020-08-18T03:45:50Z', 101] },
132 | { name: '2020-08-18T03:51:17Z', value: ['2020-08-18T03:51:17Z', 102] },
133 | { name: '2020-08-18T05:18:07Z', value: ['2020-08-18T05:18:07Z', 103] },
134 | { name: '2020-08-18T05:31:16Z', value: ['2020-08-18T05:31:16Z', 104] },
135 | { name: '2020-08-18T05:36:33Z', value: ['2020-08-18T05:36:33Z', 105] },
136 | { name: '2020-08-18T05:46:21Z', value: ['2020-08-18T05:46:21Z', 106] },
137 | { name: '2020-08-18T06:04:28Z', value: ['2020-08-18T06:04:28Z', 107] },
138 | { name: '2020-08-18T06:17:10Z', value: ['2020-08-18T06:17:10Z', 108] },
139 | { name: '2020-08-18T06:23:10Z', value: ['2020-08-18T06:23:10Z', 109] },
140 | { name: '2020-08-18T06:33:42Z', value: ['2020-08-18T06:33:42Z', 110] },
141 | { name: '2020-08-18T06:36:26Z', value: ['2020-08-18T06:36:26Z', 111] },
142 | { name: '2020-08-18T07:11:16Z', value: ['2020-08-18T07:11:16Z', 112] },
143 | { name: '2020-08-18T07:50:41Z', value: ['2020-08-18T07:50:41Z', 113] },
144 | { name: '2020-08-18T08:33:23Z', value: ['2020-08-18T08:33:23Z', 114] },
145 | { name: '2020-08-18T08:44:33Z', value: ['2020-08-18T08:44:33Z', 115] },
146 | { name: '2020-08-18T08:57:49Z', value: ['2020-08-18T08:57:49Z', 116] },
147 | { name: '2020-08-18T09:31:35Z', value: ['2020-08-18T09:31:35Z', 117] },
148 | { name: '2020-08-18T09:44:41Z', value: ['2020-08-18T09:44:41Z', 118] },
149 | { name: '2020-08-18T14:28:04Z', value: ['2020-08-18T14:28:04Z', 119] },
150 | { name: '2020-08-18T14:37:28Z', value: ['2020-08-18T14:37:28Z', 120] },
151 | { name: '2020-08-18T14:59:59Z', value: ['2020-08-18T14:59:59Z', 121] },
152 | { name: '2020-08-19T01:28:32Z', value: ['2020-08-19T01:28:32Z', 122] },
153 | { name: '2020-08-19T03:05:53Z', value: ['2020-08-19T03:05:53Z', 123] },
154 | { name: '2020-08-19T03:21:19Z', value: ['2020-08-19T03:21:19Z', 124] },
155 | { name: '2020-08-19T03:30:49Z', value: ['2020-08-19T03:30:49Z', 125] },
156 | { name: '2020-08-19T05:23:12Z', value: ['2020-08-19T05:23:12Z', 126] },
157 | { name: '2020-08-19T05:46:14Z', value: ['2020-08-19T05:46:14Z', 127] },
158 | { name: '2020-08-19T06:33:13Z', value: ['2020-08-19T06:33:13Z', 128] },
159 | { name: '2020-08-19T06:56:45Z', value: ['2020-08-19T06:56:45Z', 129] },
160 | { name: '2020-08-19T07:22:28Z', value: ['2020-08-19T07:22:28Z', 130] },
161 | { name: '2020-08-19T08:00:09Z', value: ['2020-08-19T08:00:09Z', 131] },
162 | { name: '2020-08-19T08:15:29Z', value: ['2020-08-19T08:15:29Z', 132] },
163 | { name: '2020-08-19T08:26:05Z', value: ['2020-08-19T08:26:05Z', 133] },
164 | { name: '2020-08-19T08:40:09Z', value: ['2020-08-19T08:40:09Z', 134] },
165 | { name: '2020-08-19T08:43:42Z', value: ['2020-08-19T08:43:42Z', 135] },
166 | { name: '2020-08-19T08:44:14Z', value: ['2020-08-19T08:44:14Z', 136] },
167 | { name: '2020-08-19T08:45:58Z', value: ['2020-08-19T08:45:58Z', 137] },
168 | { name: '2020-08-19T09:01:42Z', value: ['2020-08-19T09:01:42Z', 138] },
169 | { name: '2020-08-19T09:24:16Z', value: ['2020-08-19T09:24:16Z', 139] },
170 | { name: '2020-08-19T10:05:18Z', value: ['2020-08-19T10:05:18Z', 140] },
171 | { name: '2020-08-19T11:13:32Z', value: ['2020-08-19T11:13:32Z', 141] },
172 | { name: '2020-08-19T12:34:19Z', value: ['2020-08-19T12:34:19Z', 142] },
173 | { name: '2020-08-19T13:34:18Z', value: ['2020-08-19T13:34:18Z', 143] },
174 | { name: '2020-08-19T14:13:52Z', value: ['2020-08-19T14:13:52Z', 144] },
175 | { name: '2020-08-19T15:05:00Z', value: ['2020-08-19T15:05:00Z', 145] },
176 | { name: '2020-08-19T15:17:20Z', value: ['2020-08-19T15:17:20Z', 146] },
177 | { name: '2020-08-19T15:24:08Z', value: ['2020-08-19T15:24:08Z', 147] },
178 | { name: '2020-08-19T17:05:25Z', value: ['2020-08-19T17:05:25Z', 148] },
179 | { name: '2020-08-19T17:29:45Z', value: ['2020-08-19T17:29:45Z', 149] },
180 | { name: '2020-08-20T00:54:03Z', value: ['2020-08-20T00:54:03Z', 150] },
181 | { name: '2020-08-20T00:58:49Z', value: ['2020-08-20T00:58:49Z', 151] },
182 | { name: '2020-08-20T01:08:35Z', value: ['2020-08-20T01:08:35Z', 152] },
183 | { name: '2020-08-20T02:00:21Z', value: ['2020-08-20T02:00:21Z', 153] },
184 | { name: '2020-08-20T02:17:45Z', value: ['2020-08-20T02:17:45Z', 154] },
185 | { name: '2020-08-20T03:10:31Z', value: ['2020-08-20T03:10:31Z', 155] },
186 | { name: '2020-08-20T05:09:17Z', value: ['2020-08-20T05:09:17Z', 156] },
187 | { name: '2020-08-20T05:33:33Z', value: ['2020-08-20T05:33:33Z', 157] },
188 | { name: '2020-08-20T07:41:31Z', value: ['2020-08-20T07:41:31Z', 158] },
189 | { name: '2020-08-20T07:52:55Z', value: ['2020-08-20T07:52:55Z', 159] },
190 | { name: '2020-08-20T07:56:57Z', value: ['2020-08-20T07:56:57Z', 160] },
191 | { name: '2020-08-20T08:28:17Z', value: ['2020-08-20T08:28:17Z', 161] },
192 | { name: '2020-08-20T08:31:09Z', value: ['2020-08-20T08:31:09Z', 162] },
193 | { name: '2020-08-20T09:33:03Z', value: ['2020-08-20T09:33:03Z', 163] },
194 | { name: '2020-08-20T09:53:23Z', value: ['2020-08-20T09:53:23Z', 164] },
195 | { name: '2020-08-20T10:01:01Z', value: ['2020-08-20T10:01:01Z', 165] },
196 | { name: '2020-08-20T13:28:35Z', value: ['2020-08-20T13:28:35Z', 166] },
197 | { name: '2020-08-20T14:54:23Z', value: ['2020-08-20T14:54:23Z', 167] },
198 | { name: '2020-08-20T15:58:41Z', value: ['2020-08-20T15:58:41Z', 168] },
199 | { name: '2020-08-20T16:05:26Z', value: ['2020-08-20T16:05:26Z', 169] },
200 | { name: '2020-08-21T01:00:35Z', value: ['2020-08-21T01:00:35Z', 170] },
201 | { name: '2020-08-21T01:36:19Z', value: ['2020-08-21T01:36:19Z', 171] },
202 | { name: '2020-08-21T01:38:31Z', value: ['2020-08-21T01:38:31Z', 172] },
203 | { name: '2020-08-21T02:32:50Z', value: ['2020-08-21T02:32:50Z', 173] },
204 | { name: '2020-08-21T02:34:59Z', value: ['2020-08-21T02:34:59Z', 174] },
205 | { name: '2020-08-21T02:47:14Z', value: ['2020-08-21T02:47:14Z', 175] },
206 | { name: '2020-08-21T03:40:56Z', value: ['2020-08-21T03:40:56Z', 176] },
207 | { name: '2020-08-21T03:50:59Z', value: ['2020-08-21T03:50:59Z', 177] },
208 | { name: '2020-08-21T05:37:10Z', value: ['2020-08-21T05:37:10Z', 178] },
209 | { name: '2020-08-21T05:53:37Z', value: ['2020-08-21T05:53:37Z', 179] },
210 | { name: '2020-08-21T05:59:50Z', value: ['2020-08-21T05:59:50Z', 180] },
211 | { name: '2020-08-21T07:54:38Z', value: ['2020-08-21T07:54:38Z', 181] },
212 | { name: '2020-08-21T08:21:21Z', value: ['2020-08-21T08:21:21Z', 182] },
213 | { name: '2020-08-21T08:41:32Z', value: ['2020-08-21T08:41:32Z', 183] },
214 | { name: '2020-08-21T10:00:20Z', value: ['2020-08-21T10:00:20Z', 184] },
215 | { name: '2020-08-22T02:17:25Z', value: ['2020-08-22T02:17:25Z', 185] },
216 | { name: '2020-08-22T02:37:39Z', value: ['2020-08-22T02:37:39Z', 186] },
217 | { name: '2020-08-22T04:03:12Z', value: ['2020-08-22T04:03:12Z', 187] },
218 | { name: '2020-08-22T06:49:06Z', value: ['2020-08-22T06:49:06Z', 188] },
219 | { name: '2020-08-22T15:15:51Z', value: ['2020-08-22T15:15:51Z', 189] },
220 | { name: '2020-08-23T12:02:48Z', value: ['2020-08-23T12:02:48Z', 190] },
221 | { name: '2020-08-23T13:23:31Z', value: ['2020-08-23T13:23:31Z', 191] },
222 | { name: '2020-08-24T03:32:33Z', value: ['2020-08-24T03:32:33Z', 192] },
223 | { name: '2020-08-24T08:58:36Z', value: ['2020-08-24T08:58:36Z', 193] },
224 | { name: '2020-08-24T09:12:28Z', value: ['2020-08-24T09:12:28Z', 194] },
225 | { name: '2020-08-24T13:08:03Z', value: ['2020-08-24T13:08:03Z', 195] },
226 | { name: '2020-08-24T14:41:39Z', value: ['2020-08-24T14:41:39Z', 196] },
227 | { name: '2020-08-25T01:49:23Z', value: ['2020-08-25T01:49:23Z', 197] },
228 | { name: '2020-08-25T08:11:13Z', value: ['2020-08-25T08:11:13Z', 198] },
229 | { name: '2020-08-26T04:57:55Z', value: ['2020-08-26T04:57:55Z', 199] },
230 | { name: '2020-08-26T08:22:52Z', value: ['2020-08-26T08:22:52Z', 200] },
231 | { name: '2020-08-26T13:35:11Z', value: ['2020-08-26T13:35:11Z', 201] },
232 | { name: '2020-08-27T02:56:08Z', value: ['2020-08-27T02:56:08Z', 202] },
233 | { name: '2020-08-27T10:28:29Z', value: ['2020-08-27T10:28:29Z', 203] },
234 | { name: '2020-08-28T06:29:53Z', value: ['2020-08-28T06:29:53Z', 204] },
235 | { name: '2020-08-28T08:42:39Z', value: ['2020-08-28T08:42:39Z', 205] },
236 | { name: '2020-08-31T06:21:38Z', value: ['2020-08-31T06:21:38Z', 206] },
237 | { name: '2020-09-01T03:04:28Z', value: ['2020-09-01T03:04:28Z', 207] },
238 | { name: '2020-09-01T03:09:25Z', value: ['2020-09-01T03:09:25Z', 208] },
239 | { name: '2020-09-01T07:21:21Z', value: ['2020-09-01T07:21:21Z', 209] },
240 | { name: '2020-09-02T10:03:49Z', value: ['2020-09-02T10:03:49Z', 210] },
241 | { name: '2020-09-02T16:25:22Z', value: ['2020-09-02T16:25:22Z', 211] },
242 | { name: '2020-09-03T03:05:30Z', value: ['2020-09-03T03:05:30Z', 212] },
243 | { name: '2020-09-04T03:37:38Z', value: ['2020-09-04T03:37:38Z', 213] },
244 | { name: '2020-09-04T06:12:41Z', value: ['2020-09-04T06:12:41Z', 214] },
245 | { name: '2020-09-09T13:59:56Z', value: ['2020-09-09T13:59:56Z', 215] },
246 | ],
247 | smooth: true,
248 | symbol: 'none',
249 | },
250 | ],
251 | }
252 |
--------------------------------------------------------------------------------
/laboratory/puppeteerTest.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 |
3 | const puppeteer = require('puppeteer')
4 | const options = require('./echartsOptions')
5 |
6 | const render = async (options) => {
7 | const browser = await puppeteer.launch({
8 | args: ['--no-sandbox'],
9 | })
10 |
11 | const page = await browser.newPage()
12 | await page.setContent(`
13 |
14 | `)
15 |
16 | await page.evaluate((options) => {
17 | window.chart = {
18 | options,
19 | }
20 | }, options)
21 |
22 | await page.addScriptTag({
23 | url: 'https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js',
24 | })
25 |
26 | //echarts 初始化脚本注入页面
27 | await page.addScriptTag({
28 | content: `
29 | (function (window) {
30 | let option = window.chart.options;
31 | var myChart = window.echarts.init(document.getElementById('container'), null, {
32 | renderer: 'svg'
33 | });
34 | myChart.setOption(option);
35 | })(this);
36 | `,
37 | })
38 |
39 | // const $el = await page.$('#container')
40 | // console.log($el.asElement())
41 |
42 | const eles = await page.$eval('#container svg', (el) => el.outerHTML)
43 |
44 | console.log(eles)
45 |
46 | await page.close()
47 | await browser.close()
48 | }
49 |
50 | render(options)
51 |
--------------------------------------------------------------------------------
/laboratory/testChartist.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 |
3 | const chartistSvg = require('svg-chartist')
4 |
5 | const data = {
6 | labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
7 | series: [
8 | [12, 9, 7, 8, 5],
9 | [2, 1, 3.5, 7, 3],
10 | [1, 3, 4, 5, 6],
11 | ],
12 | }
13 |
14 | const options = {
15 | fullWidth: true,
16 | chartPadding: {
17 | right: 40,
18 | },
19 | title: 'juejin-im/open-source',
20 | subtitle: 'Star 成长轨迹',
21 | }
22 |
23 | const opts = {
24 | options: options,
25 | }
26 |
27 | chartistSvg('line', data, opts).then((html) => {
28 | console.log(html)
29 | })
30 |
--------------------------------------------------------------------------------
/laboratory/testEchartSVG.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const echarts = require('echarts')
3 | const { JSDOM } = require('jsdom')
4 | const options = require('./echartsOptions')
5 | require('zrender/lib/svg/svg')
6 |
7 | const dom = new JSDOM(`
8 |
9 | `,
10 | {
11 | runScripts: 'dangerously',
12 | includeNodeLocations: true
13 | }
14 | )
15 |
16 | const chartContainer = dom.window.document.getElementById('app')
17 | global.window = dom.window
18 | global.document = global.window.document
19 | global.navigator = global.window.navigator
20 |
21 | const tempDocument = (new JSDOM(`...`)).window.document;
22 | var svg = tempDocument.createElementNS("http://www.w3.org/2000/svg", "svg");
23 | function cheatCreateElementNS (ns, name) {
24 | var el = svg
25 | el.createSVGPoint = () => {
26 | return {
27 | matrixTransform: () => {
28 | console.log(111)
29 | return el.createSVGPoint();
30 | }
31 | }
32 | };
33 | el.getScreenCTM = () => {
34 | return {
35 | e: {}
36 | }
37 | }
38 | return el;
39 | }
40 | document.createElementNS = cheatCreateElementNS;
41 |
42 | const chart = echarts.init(chartContainer, null, { renderer: 'svg' })
43 | chart.setOption(options)
44 |
45 | console.log(chartContainer.innerHTML)
46 |
--------------------------------------------------------------------------------
/laboratory/testLanguageData.js:
--------------------------------------------------------------------------------
1 | const data = {
2 | user: {
3 | repositories: {
4 | nodes: [
5 | {
6 | languages: {
7 | edges: [
8 | {
9 | size: 13735,
10 | node: {
11 | color: '#b07219',
12 | name: 'Java',
13 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
14 | },
15 | },
16 | {
17 | size: 4700,
18 | node: {
19 | color: '#f1e05a',
20 | name: 'JavaScript',
21 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
22 | },
23 | },
24 | ],
25 | totalSize: 18435,
26 | },
27 | },
28 | {
29 | languages: {
30 | edges: [
31 | {
32 | size: 1347,
33 | node: {
34 | color: '#563d7c',
35 | name: 'CSS',
36 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
37 | },
38 | },
39 | {
40 | size: 23421,
41 | node: {
42 | color: '#e34c26',
43 | name: 'HTML',
44 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
45 | },
46 | },
47 | {
48 | size: 190238,
49 | node: {
50 | color: '#f1e05a',
51 | name: 'JavaScript',
52 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
53 | },
54 | },
55 | ],
56 | totalSize: 215006,
57 | },
58 | },
59 | {
60 | languages: {
61 | edges: [
62 | {
63 | size: 20742,
64 | node: {
65 | color: '#f1e05a',
66 | name: 'JavaScript',
67 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
68 | },
69 | },
70 | ],
71 | totalSize: 20742,
72 | },
73 | },
74 | {
75 | languages: {
76 | edges: [
77 | {
78 | size: 4991,
79 | node: {
80 | color: '#b07219',
81 | name: 'Java',
82 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
83 | },
84 | },
85 | ],
86 | totalSize: 4991,
87 | },
88 | },
89 | {
90 | languages: {
91 | edges: [
92 | {
93 | size: 21800,
94 | node: {
95 | color: '#f1e05a',
96 | name: 'JavaScript',
97 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
98 | },
99 | },
100 | {
101 | size: 137,
102 | node: {
103 | color: '#e34c26',
104 | name: 'HTML',
105 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
106 | },
107 | },
108 | {
109 | size: 4687,
110 | node: {
111 | color: '#2c3e50',
112 | name: 'Vue',
113 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
114 | },
115 | },
116 | ],
117 | totalSize: 26624,
118 | },
119 | },
120 | {
121 | languages: {
122 | edges: [],
123 | totalSize: 0,
124 | },
125 | },
126 | {
127 | languages: {
128 | edges: [
129 | {
130 | size: 81937,
131 | node: {
132 | color: '#f1e05a',
133 | name: 'JavaScript',
134 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
135 | },
136 | },
137 | {
138 | size: 771,
139 | node: {
140 | color: '#2c3e50',
141 | name: 'Vue',
142 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
143 | },
144 | },
145 | {
146 | size: 2287,
147 | node: {
148 | color: '#563d7c',
149 | name: 'CSS',
150 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
151 | },
152 | },
153 | {
154 | size: 3854,
155 | node: {
156 | color: '#e34c26',
157 | name: 'HTML',
158 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
159 | },
160 | },
161 | ],
162 | totalSize: 88849,
163 | },
164 | },
165 | {
166 | languages: {
167 | edges: [
168 | {
169 | size: 86049,
170 | node: {
171 | color: '#f1e05a',
172 | name: 'JavaScript',
173 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
174 | },
175 | },
176 | {
177 | size: 1644,
178 | node: {
179 | color: '#2c3e50',
180 | name: 'Vue',
181 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
182 | },
183 | },
184 | {
185 | size: 2287,
186 | node: {
187 | color: '#563d7c',
188 | name: 'CSS',
189 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
190 | },
191 | },
192 | {
193 | size: 3854,
194 | node: {
195 | color: '#e34c26',
196 | name: 'HTML',
197 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
198 | },
199 | },
200 | {
201 | size: 220492,
202 | node: {
203 | color: '#b07219',
204 | name: 'Java',
205 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
206 | },
207 | },
208 | ],
209 | totalSize: 314326,
210 | },
211 | },
212 | {
213 | languages: {
214 | edges: [
215 | {
216 | size: 75401,
217 | node: {
218 | color: '#f1e05a',
219 | name: 'JavaScript',
220 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
221 | },
222 | },
223 | {
224 | size: 340657,
225 | node: {
226 | color: '#2c3e50',
227 | name: 'Vue',
228 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
229 | },
230 | },
231 | {
232 | size: 6076,
233 | node: {
234 | color: '#e34c26',
235 | name: 'HTML',
236 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
237 | },
238 | },
239 | ],
240 | totalSize: 422134,
241 | },
242 | },
243 | {
244 | languages: {
245 | edges: [
246 | {
247 | size: 1748,
248 | node: {
249 | color: '#3572A5',
250 | name: 'Python',
251 | id: 'MDg6TGFuZ3VhZ2UxNDU=',
252 | },
253 | },
254 | {
255 | size: 1527,
256 | node: {
257 | color: '#b07219',
258 | name: 'Java',
259 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
260 | },
261 | },
262 | {
263 | size: 8737,
264 | node: {
265 | color: '#f1e05a',
266 | name: 'JavaScript',
267 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
268 | },
269 | },
270 | {
271 | size: 3936,
272 | node: {
273 | color: '#438eff',
274 | name: 'Objective-C',
275 | id: 'MDg6TGFuZ3VhZ2UxNTY=',
276 | },
277 | },
278 | ],
279 | totalSize: 15948,
280 | },
281 | },
282 | {
283 | languages: {
284 | edges: [
285 | {
286 | size: 187,
287 | node: {
288 | color: '#f1e05a',
289 | name: 'JavaScript',
290 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
291 | },
292 | },
293 | {
294 | size: 577,
295 | node: {
296 | color: '#e34c26',
297 | name: 'HTML',
298 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
299 | },
300 | },
301 | {
302 | size: 2253,
303 | node: {
304 | color: '#2c3e50',
305 | name: 'Vue',
306 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
307 | },
308 | },
309 | ],
310 | totalSize: 3017,
311 | },
312 | },
313 | {
314 | languages: {
315 | edges: [
316 | {
317 | size: 637320,
318 | node: {
319 | color: '#f1e05a',
320 | name: 'JavaScript',
321 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
322 | },
323 | },
324 | {
325 | size: 230058,
326 | node: {
327 | color: '#2c3e50',
328 | name: 'Vue',
329 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
330 | },
331 | },
332 | {
333 | size: 2655,
334 | node: {
335 | color: '#e34c26',
336 | name: 'HTML',
337 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
338 | },
339 | },
340 | {
341 | size: 2248,
342 | node: {
343 | color: '#101F1F',
344 | name: 'AppleScript',
345 | id: 'MDg6TGFuZ3VhZ2UyNzk=',
346 | },
347 | },
348 | {
349 | size: 3665,
350 | node: {
351 | color: '#563d7c',
352 | name: 'CSS',
353 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
354 | },
355 | },
356 | ],
357 | totalSize: 875946,
358 | },
359 | },
360 | {
361 | languages: {
362 | edges: [
363 | {
364 | size: 4146,
365 | node: {
366 | color: '#f1e05a',
367 | name: 'JavaScript',
368 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
369 | },
370 | },
371 | ],
372 | totalSize: 4146,
373 | },
374 | },
375 | {
376 | languages: {
377 | edges: [
378 | {
379 | size: 31045,
380 | node: {
381 | color: '#f1e05a',
382 | name: 'JavaScript',
383 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
384 | },
385 | },
386 | ],
387 | totalSize: 31045,
388 | },
389 | },
390 | {
391 | languages: {
392 | edges: [
393 | {
394 | size: 25669,
395 | node: {
396 | color: '#f1e05a',
397 | name: 'JavaScript',
398 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
399 | },
400 | },
401 | {
402 | size: 1015,
403 | node: {
404 | color: '#e34c26',
405 | name: 'HTML',
406 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
407 | },
408 | },
409 | {
410 | size: 28420,
411 | node: {
412 | color: '#563d7c',
413 | name: 'CSS',
414 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
415 | },
416 | },
417 | ],
418 | totalSize: 55104,
419 | },
420 | },
421 | {
422 | languages: {
423 | edges: [],
424 | totalSize: 0,
425 | },
426 | },
427 | {
428 | languages: {
429 | edges: [
430 | {
431 | size: 378,
432 | node: {
433 | color: '#b07219',
434 | name: 'Java',
435 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
436 | },
437 | },
438 | {
439 | size: 753,
440 | node: {
441 | color: '#438eff',
442 | name: 'Objective-C',
443 | id: 'MDg6TGFuZ3VhZ2UxNTY=',
444 | },
445 | },
446 | {
447 | size: 32162,
448 | node: {
449 | color: '#00B4AB',
450 | name: 'Dart',
451 | id: 'MDg6TGFuZ3VhZ2UyNzc=',
452 | },
453 | },
454 | {
455 | size: 2114,
456 | node: {
457 | color: '#701516',
458 | name: 'Ruby',
459 | id: 'MDg6TGFuZ3VhZ2UxNDE=',
460 | },
461 | },
462 | ],
463 | totalSize: 35407,
464 | },
465 | },
466 | {
467 | languages: {
468 | edges: [
469 | {
470 | size: 380,
471 | node: {
472 | color: '#b07219',
473 | name: 'Java',
474 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
475 | },
476 | },
477 | {
478 | size: 753,
479 | node: {
480 | color: '#438eff',
481 | name: 'Objective-C',
482 | id: 'MDg6TGFuZ3VhZ2UxNTY=',
483 | },
484 | },
485 | {
486 | size: 66925,
487 | node: {
488 | color: '#00B4AB',
489 | name: 'Dart',
490 | id: 'MDg6TGFuZ3VhZ2UyNzc=',
491 | },
492 | },
493 | {
494 | size: 2114,
495 | node: {
496 | color: '#701516',
497 | name: 'Ruby',
498 | id: 'MDg6TGFuZ3VhZ2UxNDE=',
499 | },
500 | },
501 | ],
502 | totalSize: 70172,
503 | },
504 | },
505 | {
506 | languages: {
507 | edges: [
508 | {
509 | size: 253,
510 | node: {
511 | color: '#384d54',
512 | name: 'Dockerfile',
513 | id: 'MDg6TGFuZ3VhZ2U1MzU=',
514 | },
515 | },
516 | {
517 | size: 51999,
518 | node: {
519 | color: '#f1e05a',
520 | name: 'JavaScript',
521 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
522 | },
523 | },
524 | {
525 | size: 2057,
526 | node: {
527 | color: '#e34c26',
528 | name: 'HTML',
529 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
530 | },
531 | },
532 | ],
533 | totalSize: 54309,
534 | },
535 | },
536 | {
537 | languages: {
538 | edges: [
539 | {
540 | size: 22572,
541 | node: {
542 | color: '#f1e05a',
543 | name: 'JavaScript',
544 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
545 | },
546 | },
547 | ],
548 | totalSize: 22572,
549 | },
550 | },
551 | {
552 | languages: {
553 | edges: [
554 | {
555 | size: 16178,
556 | node: {
557 | color: '#b07219',
558 | name: 'Java',
559 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
560 | },
561 | },
562 | {
563 | size: 32379,
564 | node: {
565 | color: '#438eff',
566 | name: 'Objective-C',
567 | id: 'MDg6TGFuZ3VhZ2UxNTY=',
568 | },
569 | },
570 | {
571 | size: 276229,
572 | node: {
573 | color: '#00B4AB',
574 | name: 'Dart',
575 | id: 'MDg6TGFuZ3VhZ2UyNzc=',
576 | },
577 | },
578 | {
579 | size: 4228,
580 | node: {
581 | color: '#701516',
582 | name: 'Ruby',
583 | id: 'MDg6TGFuZ3VhZ2UxNDE=',
584 | },
585 | },
586 | ],
587 | totalSize: 329014,
588 | },
589 | },
590 | {
591 | languages: {
592 | edges: [
593 | {
594 | size: 38509,
595 | node: {
596 | color: '#b07219',
597 | name: 'Java',
598 | id: 'MDg6TGFuZ3VhZ2UxNTg=',
599 | },
600 | },
601 | {
602 | size: 1731,
603 | node: {
604 | color: '#701516',
605 | name: 'Ruby',
606 | id: 'MDg6TGFuZ3VhZ2UxNDE=',
607 | },
608 | },
609 | {
610 | size: 20891,
611 | node: {
612 | color: '#438eff',
613 | name: 'Objective-C',
614 | id: 'MDg6TGFuZ3VhZ2UxNTY=',
615 | },
616 | },
617 | {
618 | size: 30827,
619 | node: {
620 | color: '#00B4AB',
621 | name: 'Dart',
622 | id: 'MDg6TGFuZ3VhZ2UyNzc=',
623 | },
624 | },
625 | {
626 | size: 1287,
627 | node: {
628 | color: '#89e051',
629 | name: 'Shell',
630 | id: 'MDg6TGFuZ3VhZ2UxMzk=',
631 | },
632 | },
633 | ],
634 | totalSize: 93245,
635 | },
636 | },
637 | {
638 | languages: {
639 | edges: [
640 | {
641 | size: 225539,
642 | node: {
643 | color: '#3572A5',
644 | name: 'Python',
645 | id: 'MDg6TGFuZ3VhZ2UxNDU=',
646 | },
647 | },
648 | {
649 | size: 9372,
650 | node: {
651 | color: '#f1e05a',
652 | name: 'JavaScript',
653 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
654 | },
655 | },
656 | {
657 | size: 3728,
658 | node: {
659 | color: '#563d7c',
660 | name: 'CSS',
661 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
662 | },
663 | },
664 | {
665 | size: 19201,
666 | node: {
667 | color: '#e34c26',
668 | name: 'HTML',
669 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
670 | },
671 | },
672 | ],
673 | totalSize: 257840,
674 | },
675 | },
676 | {
677 | languages: {
678 | edges: [],
679 | totalSize: 0,
680 | },
681 | },
682 | {
683 | languages: {
684 | edges: [
685 | {
686 | size: 24677,
687 | node: {
688 | color: '#f1e05a',
689 | name: 'JavaScript',
690 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
691 | },
692 | },
693 | ],
694 | totalSize: 24677,
695 | },
696 | },
697 | {
698 | languages: {
699 | edges: [
700 | {
701 | size: 140037,
702 | node: {
703 | color: '#f1e05a',
704 | name: 'JavaScript',
705 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
706 | },
707 | },
708 | {
709 | size: 30415,
710 | node: {
711 | color: '#563d7c',
712 | name: 'CSS',
713 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
714 | },
715 | },
716 | {
717 | size: 1015,
718 | node: {
719 | color: '#e34c26',
720 | name: 'HTML',
721 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
722 | },
723 | },
724 | ],
725 | totalSize: 171467,
726 | },
727 | },
728 | {
729 | languages: {
730 | edges: [],
731 | totalSize: 0,
732 | },
733 | },
734 | {
735 | languages: {
736 | edges: [
737 | {
738 | size: 6672,
739 | node: {
740 | color: '#563d7c',
741 | name: 'CSS',
742 | id: 'MDg6TGFuZ3VhZ2UzMDg=',
743 | },
744 | },
745 | {
746 | size: 38617,
747 | node: {
748 | color: '#e34c26',
749 | name: 'HTML',
750 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
751 | },
752 | },
753 | ],
754 | totalSize: 45289,
755 | },
756 | },
757 | {
758 | languages: {
759 | edges: [],
760 | totalSize: 0,
761 | },
762 | },
763 | {
764 | languages: {
765 | edges: [
766 | {
767 | size: 23946,
768 | node: {
769 | color: '#f1e05a',
770 | name: 'JavaScript',
771 | id: 'MDg6TGFuZ3VhZ2UxNDA=',
772 | },
773 | },
774 | {
775 | size: 15829,
776 | node: {
777 | color: '#2b7489',
778 | name: 'TypeScript',
779 | id: 'MDg6TGFuZ3VhZ2UyODc=',
780 | },
781 | },
782 | {
783 | size: 545,
784 | node: {
785 | color: '#e34c26',
786 | name: 'HTML',
787 | id: 'MDg6TGFuZ3VhZ2U0MTc=',
788 | },
789 | },
790 | {
791 | size: 3495,
792 | node: {
793 | color: '#2c3e50',
794 | name: 'Vue',
795 | id: 'MDg6TGFuZ3VhZ2U0ODM=',
796 | },
797 | },
798 | ],
799 | totalSize: 43815,
800 | },
801 | },
802 | ],
803 | },
804 | },
805 | }
806 |
807 | let totalSize = 0
808 | const nodes = []
809 | data.user.repositories.nodes.forEach((l) => {
810 | totalSize += l.languages.totalSize
811 | if (l.languages.edges) {
812 | l.languages.edges.forEach((item) => {
813 | const exists = nodes.find((el) => el.id === item.node.id)
814 | if (exists) {
815 | exists.size += item.size
816 | } else {
817 | nodes.push({
818 | ...item.node,
819 | size: item.size,
820 | })
821 | }
822 | })
823 | }
824 | })
825 |
826 | nodes.sort((a, b) => b.size - a.size)
827 | const colors = nodes.map((item) => item.color)
828 |
829 | console.log(totalSize)
830 | console.log(nodes)
831 | console.log(colors)
832 |
--------------------------------------------------------------------------------
/laboratory/testStarData.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | const list = [{"starredAt":"2020-08-13T13:11:02Z"},{"starredAt":"2020-08-13T14:00:52Z"},{"starredAt":"2020-08-13T15:22:27Z"},{"starredAt":"2020-08-13T16:39:23Z"},{"starredAt":"2020-08-13T17:16:46Z"},{"starredAt":"2020-08-14T08:48:45Z"},{"starredAt":"2020-08-14T13:30:51Z"},{"starredAt":"2020-08-15T01:01:56Z"},{"starredAt":"2020-08-15T03:21:12Z"},{"starredAt":"2020-08-15T03:29:45Z"},{"starredAt":"2020-08-15T03:30:28Z"},{"starredAt":"2020-08-15T03:46:53Z"},{"starredAt":"2020-08-15T04:16:02Z"},{"starredAt":"2020-08-15T05:03:41Z"},{"starredAt":"2020-08-15T05:21:43Z"},{"starredAt":"2020-08-15T05:26:24Z"},{"starredAt":"2020-08-15T06:08:24Z"},{"starredAt":"2020-08-15T06:47:33Z"},{"starredAt":"2020-08-15T07:13:24Z"},{"starredAt":"2020-08-15T07:23:55Z"},{"starredAt":"2020-08-15T08:51:39Z"},{"starredAt":"2020-08-15T09:58:48Z"},{"starredAt":"2020-08-15T11:09:59Z"},{"starredAt":"2020-08-15T12:35:57Z"},{"starredAt":"2020-08-15T13:24:11Z"},{"starredAt":"2020-08-15T15:46:52Z"},{"starredAt":"2020-08-15T17:36:52Z"},{"starredAt":"2020-08-15T19:27:32Z"},{"starredAt":"2020-08-16T00:21:20Z"},{"starredAt":"2020-08-16T05:06:10Z"},{"starredAt":"2020-08-16T08:10:18Z"},{"starredAt":"2020-08-16T09:21:42Z"},{"starredAt":"2020-08-16T10:08:52Z"},{"starredAt":"2020-08-16T12:00:35Z"},{"starredAt":"2020-08-16T13:36:17Z"},{"starredAt":"2020-08-16T13:45:30Z"},{"starredAt":"2020-08-16T14:45:24Z"},{"starredAt":"2020-08-16T15:12:47Z"},{"starredAt":"2020-08-16T15:17:17Z"},{"starredAt":"2020-08-16T15:31:55Z"},{"starredAt":"2020-08-16T15:42:20Z"},{"starredAt":"2020-08-16T22:18:22Z"},{"starredAt":"2020-08-17T00:11:23Z"},{"starredAt":"2020-08-17T00:22:43Z"},{"starredAt":"2020-08-17T00:51:43Z"},{"starredAt":"2020-08-17T01:01:55Z"},{"starredAt":"2020-08-17T01:04:00Z"},{"starredAt":"2020-08-17T01:13:34Z"},{"starredAt":"2020-08-17T01:15:48Z"},{"starredAt":"2020-08-17T01:22:22Z"},{"starredAt":"2020-08-17T01:32:01Z"},{"starredAt":"2020-08-17T01:37:57Z"},{"starredAt":"2020-08-17T01:44:58Z"},{"starredAt":"2020-08-17T01:48:42Z"},{"starredAt":"2020-08-17T02:00:41Z"},{"starredAt":"2020-08-17T02:12:08Z"},{"starredAt":"2020-08-17T02:13:52Z"},{"starredAt":"2020-08-17T02:28:00Z"},{"starredAt":"2020-08-17T03:10:22Z"},{"starredAt":"2020-08-17T03:51:42Z"},{"starredAt":"2020-08-17T04:12:35Z"},{"starredAt":"2020-08-17T04:34:10Z"},{"starredAt":"2020-08-17T04:42:39Z"},{"starredAt":"2020-08-17T05:03:16Z"},{"starredAt":"2020-08-17T05:17:31Z"},{"starredAt":"2020-08-17T05:19:49Z"},{"starredAt":"2020-08-17T05:24:58Z"},{"starredAt":"2020-08-17T05:37:01Z"},{"starredAt":"2020-08-17T05:42:54Z"},{"starredAt":"2020-08-17T06:10:34Z"},{"starredAt":"2020-08-17T07:27:43Z"},{"starredAt":"2020-08-17T07:34:02Z"},{"starredAt":"2020-08-17T07:35:14Z"},{"starredAt":"2020-08-17T07:55:52Z"},{"starredAt":"2020-08-17T08:02:56Z"},{"starredAt":"2020-08-17T08:13:53Z"},{"starredAt":"2020-08-17T09:31:04Z"},{"starredAt":"2020-08-17T10:02:39Z"},{"starredAt":"2020-08-17T10:45:19Z"},{"starredAt":"2020-08-17T10:57:12Z"},{"starredAt":"2020-08-17T11:01:16Z"},{"starredAt":"2020-08-17T11:57:50Z"},{"starredAt":"2020-08-17T12:10:51Z"},{"starredAt":"2020-08-17T12:25:26Z"},{"starredAt":"2020-08-17T13:17:59Z"},{"starredAt":"2020-08-17T13:19:34Z"},{"starredAt":"2020-08-17T14:09:22Z"},{"starredAt":"2020-08-17T14:33:56Z"},{"starredAt":"2020-08-17T16:53:39Z"},{"starredAt":"2020-08-18T01:15:48Z"},{"starredAt":"2020-08-18T01:25:49Z"},{"starredAt":"2020-08-18T01:28:50Z"},{"starredAt":"2020-08-18T01:32:25Z"},{"starredAt":"2020-08-18T01:41:28Z"},{"starredAt":"2020-08-18T02:04:54Z"},{"starredAt":"2020-08-18T02:10:19Z"},{"starredAt":"2020-08-18T02:21:15Z"},{"starredAt":"2020-08-18T02:22:04Z"},{"starredAt":"2020-08-18T02:40:44Z"},{"starredAt":"2020-08-18T03:24:32Z"},{"starredAt":"2020-08-18T03:45:50Z"},{"starredAt":"2020-08-18T03:51:17Z"},{"starredAt":"2020-08-18T05:18:07Z"},{"starredAt":"2020-08-18T05:31:16Z"},{"starredAt":"2020-08-18T05:36:33Z"},{"starredAt":"2020-08-18T05:46:21Z"},{"starredAt":"2020-08-18T06:04:28Z"},{"starredAt":"2020-08-18T06:17:10Z"},{"starredAt":"2020-08-18T06:23:10Z"},{"starredAt":"2020-08-18T06:33:42Z"},{"starredAt":"2020-08-18T06:36:26Z"},{"starredAt":"2020-08-18T07:11:16Z"},{"starredAt":"2020-08-18T07:50:41Z"},{"starredAt":"2020-08-18T08:33:23Z"},{"starredAt":"2020-08-18T08:44:33Z"},{"starredAt":"2020-08-18T08:57:49Z"},{"starredAt":"2020-08-18T09:31:35Z"},{"starredAt":"2020-08-18T09:44:41Z"},{"starredAt":"2020-08-18T14:28:04Z"},{"starredAt":"2020-08-18T14:37:28Z"},{"starredAt":"2020-08-18T14:59:59Z"},{"starredAt":"2020-08-19T01:28:32Z"},{"starredAt":"2020-08-19T03:05:53Z"},{"starredAt":"2020-08-19T03:21:19Z"},{"starredAt":"2020-08-19T03:30:49Z"},{"starredAt":"2020-08-19T05:23:12Z"},{"starredAt":"2020-08-19T05:46:14Z"},{"starredAt":"2020-08-19T06:33:13Z"},{"starredAt":"2020-08-19T06:56:45Z"},{"starredAt":"2020-08-19T07:22:28Z"},{"starredAt":"2020-08-19T08:00:09Z"},{"starredAt":"2020-08-19T08:15:29Z"},{"starredAt":"2020-08-19T08:26:05Z"},{"starredAt":"2020-08-19T08:40:09Z"},{"starredAt":"2020-08-19T08:43:42Z"},{"starredAt":"2020-08-19T08:44:14Z"},{"starredAt":"2020-08-19T08:45:58Z"},{"starredAt":"2020-08-19T09:01:42Z"},{"starredAt":"2020-08-19T09:24:16Z"},{"starredAt":"2020-08-19T10:05:18Z"},{"starredAt":"2020-08-19T11:13:32Z"},{"starredAt":"2020-08-19T12:34:19Z"},{"starredAt":"2020-08-19T13:34:18Z"},{"starredAt":"2020-08-19T14:13:52Z"},{"starredAt":"2020-08-19T15:05:00Z"},{"starredAt":"2020-08-19T15:17:20Z"},{"starredAt":"2020-08-19T15:24:08Z"},{"starredAt":"2020-08-19T17:05:25Z"},{"starredAt":"2020-08-19T17:29:45Z"},{"starredAt":"2020-08-20T00:54:03Z"},{"starredAt":"2020-08-20T00:58:49Z"},{"starredAt":"2020-08-20T01:08:35Z"},{"starredAt":"2020-08-20T02:00:21Z"},{"starredAt":"2020-08-20T02:17:45Z"},{"starredAt":"2020-08-20T03:10:31Z"},{"starredAt":"2020-08-20T05:09:17Z"},{"starredAt":"2020-08-20T05:33:33Z"},{"starredAt":"2020-08-20T07:41:31Z"},{"starredAt":"2020-08-20T07:52:55Z"},{"starredAt":"2020-08-20T07:56:57Z"},{"starredAt":"2020-08-20T08:28:17Z"},{"starredAt":"2020-08-20T08:31:09Z"},{"starredAt":"2020-08-20T09:33:03Z"},{"starredAt":"2020-08-20T09:53:23Z"},{"starredAt":"2020-08-20T10:01:01Z"},{"starredAt":"2020-08-20T13:28:35Z"},{"starredAt":"2020-08-20T14:54:23Z"},{"starredAt":"2020-08-20T15:58:41Z"},{"starredAt":"2020-08-20T16:05:26Z"},{"starredAt":"2020-08-21T01:00:35Z"},{"starredAt":"2020-08-21T01:36:19Z"},{"starredAt":"2020-08-21T01:38:31Z"},{"starredAt":"2020-08-21T02:32:50Z"},{"starredAt":"2020-08-21T02:34:59Z"},{"starredAt":"2020-08-21T02:47:14Z"},{"starredAt":"2020-08-21T03:40:56Z"},{"starredAt":"2020-08-21T03:50:59Z"},{"starredAt":"2020-08-21T05:37:10Z"},{"starredAt":"2020-08-21T05:53:37Z"},{"starredAt":"2020-08-21T05:59:50Z"},{"starredAt":"2020-08-21T07:54:38Z"},{"starredAt":"2020-08-21T08:21:21Z"},{"starredAt":"2020-08-21T08:41:32Z"},{"starredAt":"2020-08-21T10:00:20Z"},{"starredAt":"2020-08-22T02:17:25Z"},{"starredAt":"2020-08-22T02:37:39Z"},{"starredAt":"2020-08-22T04:03:12Z"},{"starredAt":"2020-08-22T06:49:06Z"},{"starredAt":"2020-08-22T15:15:51Z"},{"starredAt":"2020-08-23T12:02:48Z"},{"starredAt":"2020-08-23T13:23:31Z"},{"starredAt":"2020-08-24T03:32:33Z"},{"starredAt":"2020-08-24T08:58:36Z"},{"starredAt":"2020-08-24T09:12:28Z"},{"starredAt":"2020-08-24T13:08:03Z"},{"starredAt":"2020-08-24T14:41:39Z"},{"starredAt":"2020-08-25T01:49:23Z"},{"starredAt":"2020-08-25T08:11:13Z"},{"starredAt":"2020-08-26T04:57:55Z"},{"starredAt":"2020-08-26T08:22:52Z"},{"starredAt":"2020-08-26T13:35:11Z"},{"starredAt":"2020-08-27T02:56:08Z"},{"starredAt":"2020-08-27T10:28:29Z"},{"starredAt":"2020-08-28T06:29:53Z"},{"starredAt":"2020-08-28T08:42:39Z"},{"starredAt":"2020-08-31T06:21:38Z"},{"starredAt":"2020-09-01T03:04:28Z"},{"starredAt":"2020-09-01T03:09:25Z"},{"starredAt":"2020-09-01T07:21:21Z"},{"starredAt":"2020-09-02T10:03:49Z"},{"starredAt":"2020-09-02T16:25:22Z"},{"starredAt":"2020-09-03T03:05:30Z"},{"starredAt":"2020-09-04T03:37:38Z"},{"starredAt":"2020-09-04T06:12:41Z"},{"starredAt":"2020-09-09T13:59:56Z"}]
3 |
4 | const result = list.map((item, index) => ({
5 | name: item.starredAt,
6 | value: [item.starredAt, index + 1],
7 | }))
8 |
9 | console.log(JSON.stringify(result))
10 |
11 | /**
12 |
13 | option = {
14 | title: {
15 | text: 'juejin-im/open-source',
16 | subtext: 'Star growth curve'
17 | },
18 | tooltip: {
19 | trigger: 'axis',
20 | axisPointer: {
21 | type: 'cross',
22 | label: {
23 | backgroundColor: '#6a7985'
24 | }
25 | }
26 | },
27 | toolbox: {
28 | feature: {
29 | saveAsImage: {}
30 | }
31 | },
32 | grid: {
33 | left: '2%',
34 | right: '1%',
35 | bottom: '1%',
36 | containLabel: true
37 | },
38 | xAxis: [
39 | {
40 | type: 'time',
41 | boundaryGap: false,
42 | }
43 | ],
44 | yAxis: {
45 | position: 'right'
46 | },
47 | series: [
48 | {
49 | // name: '邮件营销',
50 | type: 'line',
51 | // stack: '总量',
52 | areaStyle: {},
53 | data: [{"name":"2020-08-13T13:11:02Z","value":["2020-08-13T13:11:02Z",1]},{"name":"2020-08-13T14:00:52Z","value":["2020-08-13T14:00:52Z",2]},{"name":"2020-08-13T15:22:27Z","value":["2020-08-13T15:22:27Z",3]},{"name":"2020-08-13T16:39:23Z","value":["2020-08-13T16:39:23Z",4]},{"name":"2020-08-13T17:16:46Z","value":["2020-08-13T17:16:46Z",5]},{"name":"2020-08-14T08:48:45Z","value":["2020-08-14T08:48:45Z",6]},{"name":"2020-08-14T13:30:51Z","value":["2020-08-14T13:30:51Z",7]},{"name":"2020-08-15T01:01:56Z","value":["2020-08-15T01:01:56Z",8]},{"name":"2020-08-15T03:21:12Z","value":["2020-08-15T03:21:12Z",9]},{"name":"2020-08-15T03:29:45Z","value":["2020-08-15T03:29:45Z",10]},{"name":"2020-08-15T03:30:28Z","value":["2020-08-15T03:30:28Z",11]},{"name":"2020-08-15T03:46:53Z","value":["2020-08-15T03:46:53Z",12]},{"name":"2020-08-15T04:16:02Z","value":["2020-08-15T04:16:02Z",13]},{"name":"2020-08-15T05:03:41Z","value":["2020-08-15T05:03:41Z",14]},{"name":"2020-08-15T05:21:43Z","value":["2020-08-15T05:21:43Z",15]},{"name":"2020-08-15T05:26:24Z","value":["2020-08-15T05:26:24Z",16]},{"name":"2020-08-15T06:08:24Z","value":["2020-08-15T06:08:24Z",17]},{"name":"2020-08-15T06:47:33Z","value":["2020-08-15T06:47:33Z",18]},{"name":"2020-08-15T07:13:24Z","value":["2020-08-15T07:13:24Z",19]},{"name":"2020-08-15T07:23:55Z","value":["2020-08-15T07:23:55Z",20]},{"name":"2020-08-15T08:51:39Z","value":["2020-08-15T08:51:39Z",21]},{"name":"2020-08-15T09:58:48Z","value":["2020-08-15T09:58:48Z",22]},{"name":"2020-08-15T11:09:59Z","value":["2020-08-15T11:09:59Z",23]},{"name":"2020-08-15T12:35:57Z","value":["2020-08-15T12:35:57Z",24]},{"name":"2020-08-15T13:24:11Z","value":["2020-08-15T13:24:11Z",25]},{"name":"2020-08-15T15:46:52Z","value":["2020-08-15T15:46:52Z",26]},{"name":"2020-08-15T17:36:52Z","value":["2020-08-15T17:36:52Z",27]},{"name":"2020-08-15T19:27:32Z","value":["2020-08-15T19:27:32Z",28]},{"name":"2020-08-16T00:21:20Z","value":["2020-08-16T00:21:20Z",29]},{"name":"2020-08-16T05:06:10Z","value":["2020-08-16T05:06:10Z",30]},{"name":"2020-08-16T08:10:18Z","value":["2020-08-16T08:10:18Z",31]},{"name":"2020-08-16T09:21:42Z","value":["2020-08-16T09:21:42Z",32]},{"name":"2020-08-16T10:08:52Z","value":["2020-08-16T10:08:52Z",33]},{"name":"2020-08-16T12:00:35Z","value":["2020-08-16T12:00:35Z",34]},{"name":"2020-08-16T13:36:17Z","value":["2020-08-16T13:36:17Z",35]},{"name":"2020-08-16T13:45:30Z","value":["2020-08-16T13:45:30Z",36]},{"name":"2020-08-16T14:45:24Z","value":["2020-08-16T14:45:24Z",37]},{"name":"2020-08-16T15:12:47Z","value":["2020-08-16T15:12:47Z",38]},{"name":"2020-08-16T15:17:17Z","value":["2020-08-16T15:17:17Z",39]},{"name":"2020-08-16T15:31:55Z","value":["2020-08-16T15:31:55Z",40]},{"name":"2020-08-16T15:42:20Z","value":["2020-08-16T15:42:20Z",41]},{"name":"2020-08-16T22:18:22Z","value":["2020-08-16T22:18:22Z",42]},{"name":"2020-08-17T00:11:23Z","value":["2020-08-17T00:11:23Z",43]},{"name":"2020-08-17T00:22:43Z","value":["2020-08-17T00:22:43Z",44]},{"name":"2020-08-17T00:51:43Z","value":["2020-08-17T00:51:43Z",45]},{"name":"2020-08-17T01:01:55Z","value":["2020-08-17T01:01:55Z",46]},{"name":"2020-08-17T01:04:00Z","value":["2020-08-17T01:04:00Z",47]},{"name":"2020-08-17T01:13:34Z","value":["2020-08-17T01:13:34Z",48]},{"name":"2020-08-17T01:15:48Z","value":["2020-08-17T01:15:48Z",49]},{"name":"2020-08-17T01:22:22Z","value":["2020-08-17T01:22:22Z",50]},{"name":"2020-08-17T01:32:01Z","value":["2020-08-17T01:32:01Z",51]},{"name":"2020-08-17T01:37:57Z","value":["2020-08-17T01:37:57Z",52]},{"name":"2020-08-17T01:44:58Z","value":["2020-08-17T01:44:58Z",53]},{"name":"2020-08-17T01:48:42Z","value":["2020-08-17T01:48:42Z",54]},{"name":"2020-08-17T02:00:41Z","value":["2020-08-17T02:00:41Z",55]},{"name":"2020-08-17T02:12:08Z","value":["2020-08-17T02:12:08Z",56]},{"name":"2020-08-17T02:13:52Z","value":["2020-08-17T02:13:52Z",57]},{"name":"2020-08-17T02:28:00Z","value":["2020-08-17T02:28:00Z",58]},{"name":"2020-08-17T03:10:22Z","value":["2020-08-17T03:10:22Z",59]},{"name":"2020-08-17T03:51:42Z","value":["2020-08-17T03:51:42Z",60]},{"name":"2020-08-17T04:12:35Z","value":["2020-08-17T04:12:35Z",61]},{"name":"2020-08-17T04:34:10Z","value":["2020-08-17T04:34:10Z",62]},{"name":"2020-08-17T04:42:39Z","value":["2020-08-17T04:42:39Z",63]},{"name":"2020-08-17T05:03:16Z","value":["2020-08-17T05:03:16Z",64]},{"name":"2020-08-17T05:17:31Z","value":["2020-08-17T05:17:31Z",65]},{"name":"2020-08-17T05:19:49Z","value":["2020-08-17T05:19:49Z",66]},{"name":"2020-08-17T05:24:58Z","value":["2020-08-17T05:24:58Z",67]},{"name":"2020-08-17T05:37:01Z","value":["2020-08-17T05:37:01Z",68]},{"name":"2020-08-17T05:42:54Z","value":["2020-08-17T05:42:54Z",69]},{"name":"2020-08-17T06:10:34Z","value":["2020-08-17T06:10:34Z",70]},{"name":"2020-08-17T07:27:43Z","value":["2020-08-17T07:27:43Z",71]},{"name":"2020-08-17T07:34:02Z","value":["2020-08-17T07:34:02Z",72]},{"name":"2020-08-17T07:35:14Z","value":["2020-08-17T07:35:14Z",73]},{"name":"2020-08-17T07:55:52Z","value":["2020-08-17T07:55:52Z",74]},{"name":"2020-08-17T08:02:56Z","value":["2020-08-17T08:02:56Z",75]},{"name":"2020-08-17T08:13:53Z","value":["2020-08-17T08:13:53Z",76]},{"name":"2020-08-17T09:31:04Z","value":["2020-08-17T09:31:04Z",77]},{"name":"2020-08-17T10:02:39Z","value":["2020-08-17T10:02:39Z",78]},{"name":"2020-08-17T10:45:19Z","value":["2020-08-17T10:45:19Z",79]},{"name":"2020-08-17T10:57:12Z","value":["2020-08-17T10:57:12Z",80]},{"name":"2020-08-17T11:01:16Z","value":["2020-08-17T11:01:16Z",81]},{"name":"2020-08-17T11:57:50Z","value":["2020-08-17T11:57:50Z",82]},{"name":"2020-08-17T12:10:51Z","value":["2020-08-17T12:10:51Z",83]},{"name":"2020-08-17T12:25:26Z","value":["2020-08-17T12:25:26Z",84]},{"name":"2020-08-17T13:17:59Z","value":["2020-08-17T13:17:59Z",85]},{"name":"2020-08-17T13:19:34Z","value":["2020-08-17T13:19:34Z",86]},{"name":"2020-08-17T14:09:22Z","value":["2020-08-17T14:09:22Z",87]},{"name":"2020-08-17T14:33:56Z","value":["2020-08-17T14:33:56Z",88]},{"name":"2020-08-17T16:53:39Z","value":["2020-08-17T16:53:39Z",89]},{"name":"2020-08-18T01:15:48Z","value":["2020-08-18T01:15:48Z",90]},{"name":"2020-08-18T01:25:49Z","value":["2020-08-18T01:25:49Z",91]},{"name":"2020-08-18T01:28:50Z","value":["2020-08-18T01:28:50Z",92]},{"name":"2020-08-18T01:32:25Z","value":["2020-08-18T01:32:25Z",93]},{"name":"2020-08-18T01:41:28Z","value":["2020-08-18T01:41:28Z",94]},{"name":"2020-08-18T02:04:54Z","value":["2020-08-18T02:04:54Z",95]},{"name":"2020-08-18T02:10:19Z","value":["2020-08-18T02:10:19Z",96]},{"name":"2020-08-18T02:21:15Z","value":["2020-08-18T02:21:15Z",97]},{"name":"2020-08-18T02:22:04Z","value":["2020-08-18T02:22:04Z",98]},{"name":"2020-08-18T02:40:44Z","value":["2020-08-18T02:40:44Z",99]},{"name":"2020-08-18T03:24:32Z","value":["2020-08-18T03:24:32Z",100]},{"name":"2020-08-18T03:45:50Z","value":["2020-08-18T03:45:50Z",101]},{"name":"2020-08-18T03:51:17Z","value":["2020-08-18T03:51:17Z",102]},{"name":"2020-08-18T05:18:07Z","value":["2020-08-18T05:18:07Z",103]},{"name":"2020-08-18T05:31:16Z","value":["2020-08-18T05:31:16Z",104]},{"name":"2020-08-18T05:36:33Z","value":["2020-08-18T05:36:33Z",105]},{"name":"2020-08-18T05:46:21Z","value":["2020-08-18T05:46:21Z",106]},{"name":"2020-08-18T06:04:28Z","value":["2020-08-18T06:04:28Z",107]},{"name":"2020-08-18T06:17:10Z","value":["2020-08-18T06:17:10Z",108]},{"name":"2020-08-18T06:23:10Z","value":["2020-08-18T06:23:10Z",109]},{"name":"2020-08-18T06:33:42Z","value":["2020-08-18T06:33:42Z",110]},{"name":"2020-08-18T06:36:26Z","value":["2020-08-18T06:36:26Z",111]},{"name":"2020-08-18T07:11:16Z","value":["2020-08-18T07:11:16Z",112]},{"name":"2020-08-18T07:50:41Z","value":["2020-08-18T07:50:41Z",113]},{"name":"2020-08-18T08:33:23Z","value":["2020-08-18T08:33:23Z",114]},{"name":"2020-08-18T08:44:33Z","value":["2020-08-18T08:44:33Z",115]},{"name":"2020-08-18T08:57:49Z","value":["2020-08-18T08:57:49Z",116]},{"name":"2020-08-18T09:31:35Z","value":["2020-08-18T09:31:35Z",117]},{"name":"2020-08-18T09:44:41Z","value":["2020-08-18T09:44:41Z",118]},{"name":"2020-08-18T14:28:04Z","value":["2020-08-18T14:28:04Z",119]},{"name":"2020-08-18T14:37:28Z","value":["2020-08-18T14:37:28Z",120]},{"name":"2020-08-18T14:59:59Z","value":["2020-08-18T14:59:59Z",121]},{"name":"2020-08-19T01:28:32Z","value":["2020-08-19T01:28:32Z",122]},{"name":"2020-08-19T03:05:53Z","value":["2020-08-19T03:05:53Z",123]},{"name":"2020-08-19T03:21:19Z","value":["2020-08-19T03:21:19Z",124]},{"name":"2020-08-19T03:30:49Z","value":["2020-08-19T03:30:49Z",125]},{"name":"2020-08-19T05:23:12Z","value":["2020-08-19T05:23:12Z",126]},{"name":"2020-08-19T05:46:14Z","value":["2020-08-19T05:46:14Z",127]},{"name":"2020-08-19T06:33:13Z","value":["2020-08-19T06:33:13Z",128]},{"name":"2020-08-19T06:56:45Z","value":["2020-08-19T06:56:45Z",129]},{"name":"2020-08-19T07:22:28Z","value":["2020-08-19T07:22:28Z",130]},{"name":"2020-08-19T08:00:09Z","value":["2020-08-19T08:00:09Z",131]},{"name":"2020-08-19T08:15:29Z","value":["2020-08-19T08:15:29Z",132]},{"name":"2020-08-19T08:26:05Z","value":["2020-08-19T08:26:05Z",133]},{"name":"2020-08-19T08:40:09Z","value":["2020-08-19T08:40:09Z",134]},{"name":"2020-08-19T08:43:42Z","value":["2020-08-19T08:43:42Z",135]},{"name":"2020-08-19T08:44:14Z","value":["2020-08-19T08:44:14Z",136]},{"name":"2020-08-19T08:45:58Z","value":["2020-08-19T08:45:58Z",137]},{"name":"2020-08-19T09:01:42Z","value":["2020-08-19T09:01:42Z",138]},{"name":"2020-08-19T09:24:16Z","value":["2020-08-19T09:24:16Z",139]},{"name":"2020-08-19T10:05:18Z","value":["2020-08-19T10:05:18Z",140]},{"name":"2020-08-19T11:13:32Z","value":["2020-08-19T11:13:32Z",141]},{"name":"2020-08-19T12:34:19Z","value":["2020-08-19T12:34:19Z",142]},{"name":"2020-08-19T13:34:18Z","value":["2020-08-19T13:34:18Z",143]},{"name":"2020-08-19T14:13:52Z","value":["2020-08-19T14:13:52Z",144]},{"name":"2020-08-19T15:05:00Z","value":["2020-08-19T15:05:00Z",145]},{"name":"2020-08-19T15:17:20Z","value":["2020-08-19T15:17:20Z",146]},{"name":"2020-08-19T15:24:08Z","value":["2020-08-19T15:24:08Z",147]},{"name":"2020-08-19T17:05:25Z","value":["2020-08-19T17:05:25Z",148]},{"name":"2020-08-19T17:29:45Z","value":["2020-08-19T17:29:45Z",149]},{"name":"2020-08-20T00:54:03Z","value":["2020-08-20T00:54:03Z",150]},{"name":"2020-08-20T00:58:49Z","value":["2020-08-20T00:58:49Z",151]},{"name":"2020-08-20T01:08:35Z","value":["2020-08-20T01:08:35Z",152]},{"name":"2020-08-20T02:00:21Z","value":["2020-08-20T02:00:21Z",153]},{"name":"2020-08-20T02:17:45Z","value":["2020-08-20T02:17:45Z",154]},{"name":"2020-08-20T03:10:31Z","value":["2020-08-20T03:10:31Z",155]},{"name":"2020-08-20T05:09:17Z","value":["2020-08-20T05:09:17Z",156]},{"name":"2020-08-20T05:33:33Z","value":["2020-08-20T05:33:33Z",157]},{"name":"2020-08-20T07:41:31Z","value":["2020-08-20T07:41:31Z",158]},{"name":"2020-08-20T07:52:55Z","value":["2020-08-20T07:52:55Z",159]},{"name":"2020-08-20T07:56:57Z","value":["2020-08-20T07:56:57Z",160]},{"name":"2020-08-20T08:28:17Z","value":["2020-08-20T08:28:17Z",161]},{"name":"2020-08-20T08:31:09Z","value":["2020-08-20T08:31:09Z",162]},{"name":"2020-08-20T09:33:03Z","value":["2020-08-20T09:33:03Z",163]},{"name":"2020-08-20T09:53:23Z","value":["2020-08-20T09:53:23Z",164]},{"name":"2020-08-20T10:01:01Z","value":["2020-08-20T10:01:01Z",165]},{"name":"2020-08-20T13:28:35Z","value":["2020-08-20T13:28:35Z",166]},{"name":"2020-08-20T14:54:23Z","value":["2020-08-20T14:54:23Z",167]},{"name":"2020-08-20T15:58:41Z","value":["2020-08-20T15:58:41Z",168]},{"name":"2020-08-20T16:05:26Z","value":["2020-08-20T16:05:26Z",169]},{"name":"2020-08-21T01:00:35Z","value":["2020-08-21T01:00:35Z",170]},{"name":"2020-08-21T01:36:19Z","value":["2020-08-21T01:36:19Z",171]},{"name":"2020-08-21T01:38:31Z","value":["2020-08-21T01:38:31Z",172]},{"name":"2020-08-21T02:32:50Z","value":["2020-08-21T02:32:50Z",173]},{"name":"2020-08-21T02:34:59Z","value":["2020-08-21T02:34:59Z",174]},{"name":"2020-08-21T02:47:14Z","value":["2020-08-21T02:47:14Z",175]},{"name":"2020-08-21T03:40:56Z","value":["2020-08-21T03:40:56Z",176]},{"name":"2020-08-21T03:50:59Z","value":["2020-08-21T03:50:59Z",177]},{"name":"2020-08-21T05:37:10Z","value":["2020-08-21T05:37:10Z",178]},{"name":"2020-08-21T05:53:37Z","value":["2020-08-21T05:53:37Z",179]},{"name":"2020-08-21T05:59:50Z","value":["2020-08-21T05:59:50Z",180]},{"name":"2020-08-21T07:54:38Z","value":["2020-08-21T07:54:38Z",181]},{"name":"2020-08-21T08:21:21Z","value":["2020-08-21T08:21:21Z",182]},{"name":"2020-08-21T08:41:32Z","value":["2020-08-21T08:41:32Z",183]},{"name":"2020-08-21T10:00:20Z","value":["2020-08-21T10:00:20Z",184]},{"name":"2020-08-22T02:17:25Z","value":["2020-08-22T02:17:25Z",185]},{"name":"2020-08-22T02:37:39Z","value":["2020-08-22T02:37:39Z",186]},{"name":"2020-08-22T04:03:12Z","value":["2020-08-22T04:03:12Z",187]},{"name":"2020-08-22T06:49:06Z","value":["2020-08-22T06:49:06Z",188]},{"name":"2020-08-22T15:15:51Z","value":["2020-08-22T15:15:51Z",189]},{"name":"2020-08-23T12:02:48Z","value":["2020-08-23T12:02:48Z",190]},{"name":"2020-08-23T13:23:31Z","value":["2020-08-23T13:23:31Z",191]},{"name":"2020-08-24T03:32:33Z","value":["2020-08-24T03:32:33Z",192]},{"name":"2020-08-24T08:58:36Z","value":["2020-08-24T08:58:36Z",193]},{"name":"2020-08-24T09:12:28Z","value":["2020-08-24T09:12:28Z",194]},{"name":"2020-08-24T13:08:03Z","value":["2020-08-24T13:08:03Z",195]},{"name":"2020-08-24T14:41:39Z","value":["2020-08-24T14:41:39Z",196]},{"name":"2020-08-25T01:49:23Z","value":["2020-08-25T01:49:23Z",197]},{"name":"2020-08-25T08:11:13Z","value":["2020-08-25T08:11:13Z",198]},{"name":"2020-08-26T04:57:55Z","value":["2020-08-26T04:57:55Z",199]},{"name":"2020-08-26T08:22:52Z","value":["2020-08-26T08:22:52Z",200]},{"name":"2020-08-26T13:35:11Z","value":["2020-08-26T13:35:11Z",201]},{"name":"2020-08-27T02:56:08Z","value":["2020-08-27T02:56:08Z",202]},{"name":"2020-08-27T10:28:29Z","value":["2020-08-27T10:28:29Z",203]},{"name":"2020-08-28T06:29:53Z","value":["2020-08-28T06:29:53Z",204]},{"name":"2020-08-28T08:42:39Z","value":["2020-08-28T08:42:39Z",205]},{"name":"2020-08-31T06:21:38Z","value":["2020-08-31T06:21:38Z",206]},{"name":"2020-09-01T03:04:28Z","value":["2020-09-01T03:04:28Z",207]},{"name":"2020-09-01T03:09:25Z","value":["2020-09-01T03:09:25Z",208]},{"name":"2020-09-01T07:21:21Z","value":["2020-09-01T07:21:21Z",209]},{"name":"2020-09-02T10:03:49Z","value":["2020-09-02T10:03:49Z",210]},{"name":"2020-09-02T16:25:22Z","value":["2020-09-02T16:25:22Z",211]},{"name":"2020-09-03T03:05:30Z","value":["2020-09-03T03:05:30Z",212]},{"name":"2020-09-04T03:37:38Z","value":["2020-09-04T03:37:38Z",213]},{"name":"2020-09-04T06:12:41Z","value":["2020-09-04T06:12:41Z",214]},{"name":"2020-09-09T13:59:56Z","value":["2020-09-09T13:59:56Z",215]}],
54 | smooth: true,
55 | symbol: 'none'
56 | },
57 |
58 | ]
59 | };
60 | */
61 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "github-repo-charts",
3 | "version": "1.0.0",
4 | "description": "Github仓库生成指标图表📈",
5 | "private": true,
6 | "egg": {
7 | "typescript": true,
8 | "declarations": true
9 | },
10 | "scripts": {
11 | "serve": "vue-cli-service serve",
12 | "build": "vue-cli-service build",
13 | "start": "./node_modules/.bin/egg-scripts start --env=prod --daemon --title=github-repo-charts",
14 | "stop": "./node_modules/.bin/egg-scripts stop --title=github-repo-charts",
15 | "dev": "egg-bin dev",
16 | "debug": "egg-bin debug",
17 | "test-local": "./node_modules/.bin/egg-bin test",
18 | "test": "npm run lint && npm run test-local",
19 | "cov": "./node_modules/.bin/egg-bin cov",
20 | "tsc": "./node_modules/.bin/ets && ./node_modules/.bin/tsc -p tsconfig.json",
21 | "ci": "npm run lint && npm run cov && npm run tsc",
22 | "autod": "autod",
23 | "lint": "./node_modules/.bin/eslint . --ext .ts,.vue,.js --fix",
24 | "clean": "ets clean",
25 | "init:cz": "commitizen init cz-conventional-changelog --save --save-exact",
26 | "commit": "git add . && git-cz"
27 | },
28 | "dependencies": {
29 | "@types/echarts": "^4.6.5",
30 | "@types/joi": "^14.3.4",
31 | "apollo-fetch": "^0.7.0",
32 | "core-js": "^2.6.5",
33 | "crypto-js": "^4.0.0",
34 | "dayjs": "^1.8.23",
35 | "dotenv": "^8.2.0",
36 | "egg": "^2.6.1",
37 | "egg-cors": "^2.2.3",
38 | "egg-joi": "^1.0.7",
39 | "egg-jwt": "^3.1.7",
40 | "egg-redis": "^2.4.0",
41 | "egg-scripts": "^2.6.0",
42 | "joi": "^14.3.1",
43 | "jsdom": "^16.4.0",
44 | "log4js": "^6.1.2",
45 | "puppeteer": "^5.3.0",
46 | "vue": "^2.6.10",
47 | "vue-router": "^3.0.3",
48 | "vuex": "^3.0.1"
49 | },
50 | "devDependencies": {
51 | "@types/mocha": "^2.2.40",
52 | "@types/node": "^7.0.12",
53 | "@types/supertest": "^2.0.0",
54 | "@typescript-eslint/eslint-plugin": "^2.25.0",
55 | "@typescript-eslint/parser": "^2.25.0",
56 | "@vue/cli-plugin-babel": "^3.0.0",
57 | "@vue/cli-plugin-eslint": "^3.0.0",
58 | "@vue/cli-service": "^3.0.0",
59 | "@vue/eslint-config-prettier": "^5.0.0",
60 | "autod": "^3.0.1",
61 | "autod-egg": "^1.1.0",
62 | "babel-eslint": "^10.0.1",
63 | "commitizen": "^4.0.3",
64 | "cz-conventional-changelog": "^3.1.0",
65 | "egg-bin": "^4.11.0",
66 | "egg-ci": "^1.8.0",
67 | "egg-mock": "^3.16.0",
68 | "eslint": "^6.7.2",
69 | "eslint-config-egg": "^8.0.0",
70 | "eslint-config-prettier": "^6.10.1",
71 | "eslint-plugin-prettier": "^3.1.2",
72 | "eslint-plugin-vue": "^5.0.0",
73 | "lint-staged": "^10.0.9",
74 | "prettier": "^2.0.2",
75 | "reflect-metadata": "^0.1.13",
76 | "sass": "^1.26.10",
77 | "sass-loader": "^10.0.2",
78 | "tslib": "^1.11.1",
79 | "typescript": "^3.0.0",
80 | "validate-commit-msg": "^2.14.0",
81 | "vue-template-compiler": "^2.6.10",
82 | "yorkie": "^2.0.0"
83 | },
84 | "gitHooks": {
85 | "pre-commit": "lint-staged",
86 | "commit-msg": "validate-commit-msg"
87 | },
88 | "lint-staged": {
89 | "*.{js,ts,vue}": [
90 | "eslint --fix",
91 | "git add"
92 | ]
93 | },
94 | "engines": {
95 | "node": ">=8.9.0"
96 | },
97 | "author": "YangXin",
98 | "license": "MIT",
99 | "config": {
100 | "commitizen": {
101 | "path": "./node_modules/cz-conventional-changelog"
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es2017",
5 | "module": "commonjs",
6 | "strict": true,
7 | "noImplicitAny": false,
8 | "experimentalDecorators": true,
9 | "emitDecoratorMetadata": true,
10 | "charset": "utf8",
11 | "allowJs": false,
12 | "pretty": true,
13 | "noEmitOnError": false,
14 | "noUnusedLocals": true,
15 | "noUnusedParameters": true,
16 | "allowUnreachableCode": false,
17 | "allowUnusedLabels": false,
18 | "strictPropertyInitialization": false,
19 | "noFallthroughCasesInSwitch": true,
20 | "skipLibCheck": true,
21 | "skipDefaultLibCheck": true,
22 | "inlineSourceMap": true,
23 | "importHelpers": true
24 | },
25 | "exclude": [
26 | "app/public",
27 | "app/views",
28 | "node_modules*"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/typings/app/controller/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | import ExportHome from '../../../app/controller/home';
6 | import ExportRepo from '../../../app/controller/repo';
7 |
8 | declare module 'egg' {
9 | interface IController {
10 | home: ExportHome;
11 | repo: ExportRepo;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/typings/app/extend/context.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | import ExtendContext from '../../../app/extend/context';
6 | type ExtendContextType = typeof ExtendContext;
7 | declare module 'egg' {
8 | interface Context extends ExtendContextType { }
9 | }
--------------------------------------------------------------------------------
/typings/app/extend/helper.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | import ExtendIHelper from '../../../app/extend/helper';
6 | type ExtendIHelperType = typeof ExtendIHelper;
7 | declare module 'egg' {
8 | interface IHelper extends ExtendIHelperType { }
9 | }
--------------------------------------------------------------------------------
/typings/app/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | export * from 'egg';
6 | export as namespace Egg;
7 |
--------------------------------------------------------------------------------
/typings/app/service/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | type AnyClass = new (...args: any[]) => any;
6 | type AnyFunc = (...args: any[]) => T;
7 | type CanExportFunc = AnyFunc> | AnyFunc>;
8 | type AutoInstanceType : T> = U extends AnyClass ? InstanceType : U;
9 | import ExportFork from '../../../app/service/fork';
10 | import ExportHome from '../../../app/service/home';
11 | import ExportLanguage from '../../../app/service/language';
12 | import ExportStar from '../../../app/service/star';
13 |
14 | declare module 'egg' {
15 | interface IService {
16 | fork: AutoInstanceType;
17 | home: AutoInstanceType;
18 | language: AutoInstanceType;
19 | star: AutoInstanceType;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/typings/config/index.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | import { EggAppConfig } from 'egg';
6 | import ExportConfigDefault from '../../config/config.default';
7 | type ConfigDefault = ReturnType;
8 | type NewEggAppConfig = ConfigDefault;
9 | declare module 'egg' {
10 | interface EggAppConfig extends NewEggAppConfig { }
11 | }
--------------------------------------------------------------------------------
/typings/config/plugin.d.ts:
--------------------------------------------------------------------------------
1 | // This file is created by egg-ts-helper@1.25.7
2 | // Do not modify this file!!!!!!!!!
3 |
4 | import 'egg';
5 | import 'egg-onerror';
6 | import 'egg-session';
7 | import 'egg-i18n';
8 | import 'egg-watcher';
9 | import 'egg-multipart';
10 | import 'egg-security';
11 | import 'egg-development';
12 | import 'egg-logrotator';
13 | import 'egg-schedule';
14 | import 'egg-static';
15 | import 'egg-jsonp';
16 | import 'egg-view';
17 | import 'egg-cors';
18 | import 'egg-joi';
19 | import 'egg-redis';
20 | import { EggPluginItem } from 'egg';
21 | declare module 'egg' {
22 | interface EggPlugin {
23 | onerror?: EggPluginItem;
24 | session?: EggPluginItem;
25 | i18n?: EggPluginItem;
26 | watcher?: EggPluginItem;
27 | multipart?: EggPluginItem;
28 | security?: EggPluginItem;
29 | development?: EggPluginItem;
30 | logrotator?: EggPluginItem;
31 | schedule?: EggPluginItem;
32 | static?: EggPluginItem;
33 | jsonp?: EggPluginItem;
34 | view?: EggPluginItem;
35 | cors?: EggPluginItem;
36 | joi?: EggPluginItem;
37 | redis?: EggPluginItem;
38 | }
39 | }
--------------------------------------------------------------------------------
/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | import 'egg';
2 | import { ApolloFetch } from 'apollo-fetch';
3 |
4 | declare module 'egg' {
5 | interface Application {
6 | jwt: any;
7 | validator: any;
8 | apolloFetch: ApolloFetch
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | const path = require('path')
4 |
5 | module.exports = {
6 | publicPath: '/',
7 | pages: {
8 | index: {
9 | entry: 'html/src/main.js',
10 | template: 'html/public/index.html',
11 | },
12 | },
13 | chainWebpack: (config) => {
14 | config.resolve.alias
15 | .set('@', path.join(__dirname, 'html/src'))
16 | }
17 | }
18 |
--------------------------------------------------------------------------------