├── .babelrc ├── .editorconfig ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── new_component_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── QQGroup.png ├── README.md ├── README_EN.md ├── demoImg ├── construction-data.jpg ├── electronic-file.jpg └── manage-desk.jpg ├── icon.png ├── package.json ├── rollup.config.js ├── src ├── .eslintrc ├── components │ ├── activeRingChart │ │ ├── index.js │ │ └── style.less │ ├── borderBox1 │ │ ├── index.js │ │ └── style.less │ ├── borderBox10 │ │ ├── index.js │ │ └── style.less │ ├── borderBox11 │ │ ├── index.js │ │ └── style.less │ ├── borderBox12 │ │ ├── index.js │ │ └── style.less │ ├── borderBox13 │ │ ├── index.js │ │ └── style.less │ ├── borderBox2 │ │ ├── index.js │ │ └── style.less │ ├── borderBox3 │ │ ├── index.js │ │ └── style.less │ ├── borderBox4 │ │ ├── index.js │ │ └── style.less │ ├── borderBox5 │ │ ├── index.js │ │ └── style.less │ ├── borderBox6 │ │ ├── index.js │ │ └── style.less │ ├── borderBox7 │ │ ├── index.js │ │ └── style.less │ ├── borderBox8 │ │ ├── index.js │ │ └── style.less │ ├── borderBox9 │ │ ├── index.js │ │ └── style.less │ ├── capsuleChart │ │ ├── index.js │ │ └── style.less │ ├── charts │ │ ├── index.js │ │ └── style.less │ ├── conicalColumnChart │ │ ├── index.js │ │ └── style.less │ ├── decoration1 │ │ ├── index.js │ │ └── style.less │ ├── decoration10 │ │ ├── index.js │ │ └── style.less │ ├── decoration11 │ │ ├── index.js │ │ └── style.less │ ├── decoration12 │ │ ├── index.js │ │ └── style.less │ ├── decoration2 │ │ ├── index.js │ │ └── style.less │ ├── decoration3 │ │ ├── index.js │ │ └── style.less │ ├── decoration4 │ │ ├── index.js │ │ └── style.less │ ├── decoration5 │ │ ├── index.js │ │ └── style.less │ ├── decoration6 │ │ ├── index.js │ │ └── style.less │ ├── decoration7 │ │ ├── index.js │ │ └── style.less │ ├── decoration8 │ │ ├── index.js │ │ └── style.less │ ├── decoration9 │ │ ├── index.js │ │ └── style.less │ ├── digitalFlop │ │ ├── index.js │ │ └── style.less │ ├── flylineChart │ │ ├── index.js │ │ └── style.less │ ├── flylineChartEnhanced │ │ ├── index.js │ │ └── style.less │ ├── fullScreenContainer │ │ ├── index.js │ │ └── style.less │ ├── loading │ │ ├── index.js │ │ └── style.less │ ├── percentPond │ │ ├── index.js │ │ └── style.less │ ├── scrollBoard │ │ ├── index.js │ │ └── style.less │ ├── scrollRankingBoard │ │ ├── index.js │ │ └── style.less │ └── waterLevelPond │ │ ├── index.js │ │ └── style.less ├── index.js ├── test.js ├── use │ └── autoResize.js └── util │ └── index.js └── umdExample.html /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-0", 7 | "react" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": ["standard", "standard-react"], 4 | "env": { 5 | "es6": true 6 | }, 7 | "plugins": ["react"], 8 | "parserOptions": { 9 | "sourceType": "module" 10 | }, 11 | "rules": { 12 | // don't force es6 functions to include space before paren 13 | "space-before-function-paren": 0, 14 | 15 | // allow specifying true explicitly for boolean props 16 | "react/jsx-boolean-value": 0 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: 提交Bug反馈 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | ## Bug report 11 | 12 | #### 出现Bug的组件? 13 | 14 | #### 组件配置数据? 15 | 16 | 17 | #### 控制台错误输出? 18 | 19 | 20 | #### 期望情况? 21 | 22 | #### 实际情况? 23 | 24 | #### 其他相关信息 25 | 26 | - DataV版本 27 | - 浏览器版本 28 | - 其他 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: 新特性建议 4 | --- 5 | 6 | 7 | 8 | ## Feature request 9 | 10 | #### 这个特性解决了什么问题? 11 | 12 | #### 这个特性的实现形式? 13 | 14 | #### 是否愿意为此特性提交PR? 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new_component_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Component request 3 | about: 新组件建议 4 | --- 5 | 6 | 7 | 8 | 9 | ## Component request 10 | 11 | #### 新组件的类型? 12 | 13 | * [ ] 边框 14 | * [ ] 装饰 15 | * [ ] 图表 16 | * [ ] 其他 17 | 18 | #### 这个组件的功能描述 (边框及装饰类,请提供样图)? 19 | 20 | #### 是否愿意为此组件提交PR? 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **该PR的类型是?** (至少选择一个) 4 | 5 | - [ ] Bug修复 6 | - [ ] 新特性 7 | - [ ] 新组件 8 | 9 | **该PR是否向下兼容?** (选择任一) 10 | 11 | - [ ] 是 12 | - [ ] 否 13 | 14 | 如果为否,请描述冲突情况: 15 | 16 | **涉及到的ISSUE:** 17 | 18 | - [ ] 该PR如果涉及到某个ISSUE, 请在PR标题中描述出来 (例如. `fix #xxx[,#xxx]`, "xxx"为ISSUE序号) 19 | 20 | **是否在Chrome浏览器下进行过测试?** 21 | 22 | - [ ] 是 23 | - [ ] 否 24 | 25 | 如果这是一个**新特性**或**新组件**相关的PR,请提供如下信息 26 | 27 | - [ ] 添加该特性或组件的原因 28 | - [ ] 文档应该修改哪些信息 29 | - [ ] 测试相关 30 | 31 | 提交**新特性**或**新组件**前请先发起一个相关的ISSUE请求 32 | 33 | **其他信息:** 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | .rpt2_cache 10 | deploy/config.js 11 | lib 12 | es 13 | umd 14 | 15 | # misc 16 | .DS_Store 17 | .env 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | yarn.lock 27 | 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.run": "onSave", 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll.eslint": true 5 | } 6 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.5-alpha (2020-11-15) 2 | 3 | ### New 4 | 5 | - **decoration12:** New decoration(Radar scan). 6 | 7 | ### Optmization 8 | 9 | - **ScrollBoard:** Reduce redundant node rendering. 10 | - **ScrollRankingBoard:** Reduce redundant node rendering. 11 | - **ScrollRankingBoard:** Add value formatter. 12 | - **BorderBox:** Canonical class name. 13 | - **useAutoResize(hooks):** Add exception prompt. 14 | - **Decoration** add `dur` configuration. 15 | - **ActiveRingChart** add `digitalFlopUnit` configuration. 16 | 17 | # 1.2.4-alpha (2020-7-25) 18 | 19 | ### Bug 修复 20 | 21 | - **scrollBoard:** hover Error [(#9)](https://github.com/DataV-Team/DataV-React/issues/9). 22 | 23 | # 1.2.2-alpha (2020-7-04) 24 | 25 | ### Bug 修复 26 | 27 | - **ScrollRankingBoard:** 计算规则调整 [(#101)](https://github.com/DataV-Team/DataV/pull/101). 28 | - **scrollBoard:** key 生成策略调整 [(#8)](https://github.com/DataV-Team/DataV-React/issues/8). 29 | - **uuid:** uuid 生成策略调整 [(#108)](https://github.com/DataV-Team/DataV/issues/108). 30 | 31 | ### Perfect 32 | 33 | - **DigitalFlop:** 添加 `formatter` 配置. 34 | 35 | # 1.2.0-alpha (2020-6-14) 36 | 37 | ### Perfect 38 | 39 | - **BorderBox:** 添加 `backgroundColor` prop. 40 | - **BorderBox8:** 添加 `reverse` prop. 41 | - **DigitalFlop:** 添加 `rowGap` 配置. 42 | - **ScrollBoard:** 添加 `hoverPause` 配置. 43 | - **CapsuleChart:** 添加 `showValue` 配置. 44 | - **ActiveRightChart:** 添加 `showOriginValue` 配置. 45 | 46 | - **uuid:** 使用 `uuid` 生成唯一 id. 47 | 48 | # 1.1.7-alpha (2020-04-10) 49 | 50 | ### BUG 修复 51 | 52 | - **WaterLevelPond:** 组件切换到后台陷入死循环. 53 | - **CapsuleChart:** 胶囊图数值错误. 54 | 55 | ### Perfect 56 | 57 | - **Component:** 内部使用 useImperativeHandle 的组件默认经过 forwardRef 返回. 58 | 59 | # 1.1.3-alpha (2020-01-17) 60 | 61 | ### BUG 修复 62 | 63 | - **ActiveRingChart:** `parseInt` 精度损失. 64 | 65 | # 1.1.2-alpha (2020-01-10) 66 | 67 | ### Perfect 68 | 69 | - **AtiveRingChart:** 添加 digitalFlopToFixed 配置项. 70 | 71 | # 1.1.1-alpha (2020-01-08) 72 | 73 | ### New 74 | 75 | - **FlylineChartEnhanced:** Enhanced flylineChart . 76 | 77 | # 1.0.10-alpha (2019-12-27) 78 | 79 | ### Perfect 80 | 81 | - **ScrollRankingBoard:** 配置项 sort 控制是否自动排序. 82 | - **ScrollRankingBoard:** 通过 dangerouslySetInnerHTML 渲染 name 数据. 83 | 84 | # 1.0.8-alpha (2019-12-17) 85 | 86 | ### Feature 87 | 88 | - **BorderBox & Decoration:** **Configurable** color. 89 | 90 | ```html 91 | 92 | 93 | 94 | ``` 95 | 96 | - **ScrollBoard:** 配置 header index. 97 | 98 | ### New 99 | 100 | - **borderBox11** 101 | - **borderBox12** 102 | - **borderBox13** 103 | - **decoration11** 104 | 105 | # 1.0.7-alpha (2019-10-25) 106 | 107 | ### Perfect 108 | 109 | - **co:** 优化 Generator 异常. 110 | - **export:** 导出 co, useAutoResize. 111 | 112 | # 1.0.5-alpha (2019-10-24) 113 | 114 | ### Perfect 115 | 116 | - **Charts:** 优化内存泄漏. 117 | - **DigitalFlop:** 优化内存泄漏. 118 | 119 | # 1.0.4-alpha (2019-10-24) 120 | 121 | ### Bug 修复 122 | 123 | - **ActiveRingChart:** 优化内存泄漏. 124 | 125 | # 1.0.2-alpha (2019-09-27) 126 | 127 | ### Bug 修复 128 | 129 | - **co:** Generator 自动执行异常. 130 | 131 | ### 优化组件 132 | 133 | - **ActiveRingChart** 134 | - **DigitalFlop** 135 | - **FullScreenContainer** 136 | - **PercentPond** 137 | - **ScrollBoard** 138 | - **ScrollBankingBoard** 139 | - **WaterLevelPond** 140 | 141 | # 1.0.1-alpha (2019-09-24) 142 | 143 | ### Bug 修复 144 | 145 | - **ActiveRingChart:** 由于数据值为 0 而导致计算异常. 146 | 147 | # 1.0.0-alpha (2019-09-23) 148 | 149 | ### 初始化代码 150 | 151 | - **Vue to React:** 转换 **Vue** 组件 为 **React** 组件. 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-present, DataV-Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /QQGroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataV-Team/DataV-React/423998d8ebe6a964db29f2890cfb936d1d8a2e10/QQGroup.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [ENGLISH](./README_EN.md) 2 | 3 |

4 | 5 |

6 |

DataV-React

7 |

8 | 9 | LICENSE 10 | 11 | 12 | LICENSE 13 | 14 |

15 | 16 | ## DataV-React 是干什么的? 17 | 18 | - DataV-React 是一个基于**React**的数据可视化组件库(当然也有[Vue 版本](https://github.com/DataV-Team/DataV)) 19 | - 提供用于提升页面视觉效果的**SVG**边框和装饰 20 | - 提供常用的**图表**如折线图等 21 | - 飞线图/轮播表等其他组件 22 | 23 | ### 注意事项 24 | 25 | **使用了 React Hooks, 简化了许多内部工作。您需要 React 版本 16.8.0 及以上** 26 | 27 | ### npm 安装 28 | 29 | ```shell 30 | $ npm install @jiaminghi/data-view-react 31 | ``` 32 | 33 | ### 使用 34 | 35 | ```js 36 | import * as datav from "@jiaminghi/data-view-react"; 37 | 38 | datav.BorderBox1; 39 | 40 | // 或者 41 | import { BorderBox1 } from "@jiaminghi/data-view-react"; 42 | 43 | // 按需引入 44 | import BorderBox1 from "@jiaminghi/data-view-react/es/borderBox1"; 45 | ``` 46 | 47 | 详细文档及示例请移步[HomePage](http://datav-react.jiaminghi.com). 48 | 49 | ### UMD 版 50 | 51 | `UMD`版可直接使用`script`标签引入,引入后通过**datav**命名空间使用对应的组件,引入`data-view-react`前请确保已引入`react 和 react-dom`。 52 | 53 | [UMD 版使用示例](./umdExample.html) 54 | 55 | ### TODO 56 | 57 | * **地图组件** 58 | * **TS**重构组件库底层依赖 59 | 60 | ### 致谢 61 | 62 | 组件库的开发基于个人学习和兴趣,由于技术水平及经验的限制,组件尚有许多不完善之处,如有 BUG 可及时提交[issue](https://github.com/DataV-Team/DataV-React/issues/new?template=bug_report.md)或添加反馈群进行反馈,也欢迎提供指正和建议,感谢各位的支持。 63 | 64 | ### 反馈 65 | 66 | ![Feedback](./QQGroup.png) 67 | 68 | ### Demo 69 | 70 | Demo 页面使用了全屏组件,请 F11 全屏后查看。 71 | 72 | - [施工养护综合数据](http://datav-react.jiaminghi.com/demo/construction-data/index.html) 73 | 74 | ![construction-data](./demoImg/construction-data.jpg) 75 | 76 | - [机电运维管理台](http://datav-react.jiaminghi.com/demo/manage-desk/index.html) 77 | 78 | ![manage-desk](./demoImg/manage-desk.jpg) 79 | 80 | - [机电设备电子档案](http://datav-react.jiaminghi.com/demo/electronic-file/index.html) 81 | 82 | ![electronic-file](./demoImg/electronic-file.jpg) 83 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | [中文](./README.md) 2 | 3 |

4 | 5 |

6 |

DataV-React

7 |

8 | 9 | LICENSE 10 | 11 | 12 | LICENSE 13 | 14 |

15 | 16 | ## What is DataV-React? 17 | 18 | - DataV-React is a data **visualization** components library based on **React**(Of course there are also[Vue version](https://github.com/DataV-Team/DataV)). 19 | - Provide cool **SVG** borders and decorations. 20 | - Provide common **charts** such as line chart, etc.. 21 | - flying line chart, carousel table and etc. 22 | 23 | ### Precautions 24 | 25 | **Using React Hooks simplifies many internal work. You need React version 16.8.0 and above** 26 | 27 | ### Install with npm 28 | 29 | ```shell 30 | $ npm install @jiaminghi/data-view-react 31 | ``` 32 | 33 | ### use 34 | 35 | ```js 36 | import * as datav from "@jiaminghi/data-view-react"; 37 | 38 | datav.BorderBox1; 39 | 40 | // or 41 | import { BorderBox1 } from "@jiaminghi/data-view-react"; 42 | 43 | // Introduced on demand 44 | import BorderBox1 from "@jiaminghi/data-view-react/es/borderBox1"; 45 | ``` 46 | 47 | Detailed documents and examples can be viewed on the [HomePage](http://datav-react.jiaminghi.com). 48 | 49 | ### UMD version 50 | 51 | The `UMD` version can be directly imported using the `script` tag. After the introduction, the corresponding component is used through the **datav** namespace. Before introducing `data-view-react`, please ensure that `react and react-dom are introduced. 52 | 53 | [UMD version usage example](./umdExample.html) 54 | 55 | ### TODO 56 | 57 | * **Map Component** 58 | * Refactor underlying dependencies using **TS**. 59 | 60 | ### Acknowledgement 61 | 62 | The development of the component library is based on personal learning and interest. Due to technical level and experience limitations, there are still many imperfections in the components. If there are errors, you can submit [issue](https://github.com/DataV-Team/DataV-React/issues/new?template=bug_report.md) in time or add feedback groups for feedback. Welcome to provide corrections and suggestions. Thank you for your support. 63 | 64 | ### Feedback 65 | 66 | ![Feedback](./QQGroup.png) 67 | 68 | ### Demo 69 | 70 | The Demo page uses the full-screen component, please view it after F11 full screen. 71 | 72 | - [Construction Data](http://datav-react.jiaminghi.com/demo/construction-data/index.html) 73 | 74 | ![construction-data](./demoImg/construction-data.jpg) 75 | 76 | - [Manage-Desk](http://datav-react.jiaminghi.com/demo/manage-desk/index.html) 77 | 78 | ![manage-desk](./demoImg/manage-desk.jpg) 79 | 80 | - [Electronic-File](http://datav-react.jiaminghi.com/demo/electronic-file/index.html) 81 | 82 | ![electronic-file](./demoImg/electronic-file.jpg) 83 | -------------------------------------------------------------------------------- /demoImg/construction-data.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataV-Team/DataV-React/423998d8ebe6a964db29f2890cfb936d1d8a2e10/demoImg/construction-data.jpg -------------------------------------------------------------------------------- /demoImg/electronic-file.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataV-Team/DataV-React/423998d8ebe6a964db29f2890cfb936d1d8a2e10/demoImg/electronic-file.jpg -------------------------------------------------------------------------------- /demoImg/manage-desk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataV-Team/DataV-React/423998d8ebe6a964db29f2890cfb936d1d8a2e10/demoImg/manage-desk.jpg -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataV-Team/DataV-React/423998d8ebe6a964db29f2890cfb936d1d8a2e10/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jiaminghi/data-view-react", 3 | "version": "1.2.5", 4 | "description": "React Large screen data display component library", 5 | "author": "Duan Yu <949267840@qq.com>", 6 | "license": "MIT", 7 | "repository": "DataV-Team/DataV-React", 8 | "main": "lib/index/index.js", 9 | "module": "es/index/index.js", 10 | "unpkg": "umd/datav.js", 11 | "engines": { 12 | "node": ">=8", 13 | "npm": ">=5" 14 | }, 15 | "scripts": { 16 | "test": "cross-env CI=1 react-scripts test --env=jsdom", 17 | "test:watch": "react-scripts test --env=jsdom", 18 | "build": "rollup -c", 19 | "start": "rollup -c -w", 20 | "prepare": "yarn run build" 21 | }, 22 | "dependencies": { 23 | "@jiaminghi/charts": "^0.2" 24 | }, 25 | "peerDependencies": { 26 | "react": "^16.8.0", 27 | "react-dom": "^16.8.0" 28 | }, 29 | "devDependencies": { 30 | "@svgr/rollup": "^2.4.1", 31 | "babel-core": "^6.26.3", 32 | "babel-eslint": "^8.2.5", 33 | "babel-plugin-external-helpers": "^6.22.0", 34 | "babel-preset-env": "^1.7.0", 35 | "babel-preset-react": "^6.24.1", 36 | "babel-preset-stage-0": "^6.24.1", 37 | "classnames": "^2.2.6", 38 | "cross-env": "^5.1.4", 39 | "eslint": "^5.0.1", 40 | "eslint-config-standard": "^11.0.0", 41 | "eslint-config-standard-react": "^6.0.0", 42 | "eslint-plugin-import": "^2.13.0", 43 | "eslint-plugin-node": "^7.0.1", 44 | "eslint-plugin-promise": "^4.0.0", 45 | "eslint-plugin-react": "^7.10.0", 46 | "eslint-plugin-standard": "^3.1.0", 47 | "less": "^3.10.3", 48 | "prop-types": "^15.7.2", 49 | "react": "^16.8.6", 50 | "react-dom": "^16.8.6", 51 | "react-scripts": "^1.1.4", 52 | "rollup": "^1.21.4", 53 | "rollup-plugin-babel": "^3.0.7", 54 | "rollup-plugin-commonjs": "^9.1.3", 55 | "rollup-plugin-node-resolve": "^3.3.0", 56 | "rollup-plugin-peer-deps-external": "^2.2.0", 57 | "rollup-plugin-postcss": "^1.6.2", 58 | "rollup-plugin-replace": "^2.2.0", 59 | "rollup-plugin-uglify": "^6.0.3", 60 | "rollup-plugin-url": "^1.4.0" 61 | }, 62 | "files": [ 63 | "src", 64 | "lib", 65 | "es", 66 | "umd" 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import external from 'rollup-plugin-peer-deps-external' 4 | import postcss from 'rollup-plugin-postcss' 5 | import resolve from 'rollup-plugin-node-resolve' 6 | import replace from 'rollup-plugin-replace' 7 | import { uglify } from 'rollup-plugin-uglify' 8 | import url from 'rollup-plugin-url' 9 | import svgr from '@svgr/rollup' 10 | 11 | // 通过 mode 接口拿到 src/components 下的所有文件夹名作为打包后的模块 12 | const fs = require('fs') 13 | const path = require('path') 14 | const componentDir = 'src/components' 15 | const cModuleNames = fs.readdirSync(path.resolve(componentDir)) 16 | const cModuleMap = cModuleNames.reduce((prev, name) => { 17 | prev[name] = `${componentDir}/${name}/index.js` 18 | 19 | return prev 20 | }, {}) 21 | 22 | const plugins = [ 23 | external(), 24 | postcss(), 25 | url(), 26 | svgr(), 27 | babel({ 28 | exclude: 'node_modules/**', 29 | plugins: ['external-helpers'] 30 | }), 31 | resolve(), 32 | commonjs() 33 | ] 34 | 35 | export default [ 36 | { 37 | input: { 38 | index: 'src/index.js', 39 | ...cModuleMap 40 | }, 41 | output: [ 42 | { 43 | dir: 'lib', 44 | entryFileNames: '[name]/index.js', 45 | format: 'cjs', 46 | sourcemap: true 47 | }, 48 | { 49 | dir: 'es', 50 | entryFileNames: '[name]/index.js', 51 | format: 'es', 52 | sourcemap: true 53 | } 54 | ], 55 | plugins, 56 | experimentalCodeSplitting: true 57 | }, 58 | { 59 | input: 'src/index.js', 60 | output: { 61 | format: 'umd', 62 | file: 'umd/datav.js', 63 | name: 'datav' 64 | }, 65 | plugins: [...plugins, replace({ 'process.env.NODE_ENV': '"development"' })] 66 | }, 67 | { 68 | input: 'src/index.js', 69 | output: { 70 | format: 'umd', 71 | file: 'umd/datav.min.js', 72 | name: 'datav' 73 | }, 74 | plugins: [ 75 | ...plugins, 76 | replace({ 'process.env.NODE_ENV': '"production"' }), 77 | uglify() 78 | ] 79 | } 80 | ] 81 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/components/activeRingChart/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState, useEffect, useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import Charts from '@jiaminghi/charts' 8 | 9 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 10 | 11 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 12 | 13 | import DigitalFlop from '../digitalFlop' 14 | 15 | import { co } from '../../util' 16 | 17 | import './style.less' 18 | 19 | const defaultConfig = { 20 | /** 21 | * @description Ring radius 22 | * @type {String|Number} 23 | * @default radius = '50%' 24 | * @example radius = '50%' | 100 25 | */ 26 | radius: '50%', 27 | /** 28 | * @description Active ring radius 29 | * @type {String|Number} 30 | * @default activeRadius = '55%' 31 | * @example activeRadius = '55%' | 110 32 | */ 33 | activeRadius: '55%', 34 | /** 35 | * @description Ring data 36 | * @type {Array} 37 | * @default data = [{ name: '', value: 0 }] 38 | */ 39 | data: [{ name: '', value: 0 }], 40 | /** 41 | * @description Ring line width 42 | * @type {Number} 43 | * @default lineWidth = 20 44 | */ 45 | lineWidth: 20, 46 | /** 47 | * @description Active time gap (ms) 48 | * @type {Number} 49 | * @default activeTimeGap = 3000 50 | */ 51 | activeTimeGap: 3000, 52 | /** 53 | * @description Ring color (hex|rgb|rgba|color keywords) 54 | * @type {Array} 55 | * @default color = [Charts Default Color] 56 | * @example color = ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red'] 57 | */ 58 | color: [], 59 | /** 60 | * @description Digital flop style 61 | * @type {Object} 62 | */ 63 | digitalFlopStyle: { 64 | fontSize: 25, 65 | fill: '#fff' 66 | }, 67 | /** 68 | * @description Digital flop toFixed 69 | * @type {Number} 70 | */ 71 | digitalFlopToFixed: 0, 72 | /** 73 | * @description Digital flop unit 74 | * @type {String} 75 | */ 76 | digitalFlopUnit: '', 77 | /** 78 | * @description CRender animationCurve 79 | * @type {String} 80 | * @default animationCurve = 'easeOutCubic' 81 | */ 82 | animationCurve: 'easeOutCubic', 83 | /** 84 | * @description CRender animationFrame 85 | * @type {Number} 86 | * @default animationFrame = 50 87 | */ 88 | animationFrame: 50, 89 | /** 90 | * @description showOriginValue 91 | * @type {Boolean} 92 | * @default showOriginValue = false 93 | */ 94 | showOriginValue: false 95 | } 96 | 97 | const ActiveRingChart = ({ config = {}, className, style }) => { 98 | const [{ activeIndex, mergedConfig }, setState] = useState({ 99 | activeIndex: 0, 100 | mergedConfig: null 101 | }) 102 | 103 | const domRef = useRef(null) 104 | const chartRef = useRef(null) 105 | 106 | const digitalFlop = useMemo(() => { 107 | if (!mergedConfig) return {} 108 | 109 | const { digitalFlopStyle, digitalFlopToFixed, data, showOriginValue, digitalFlopUnit } = mergedConfig 110 | 111 | const value = data.map(({ value }) => value) 112 | 113 | let displayValue 114 | 115 | if (showOriginValue) { 116 | displayValue = value[activeIndex] 117 | } else { 118 | const sum = value.reduce((all, v) => all + v, 0) 119 | const percent = parseFloat((value[activeIndex] / sum) * 100) || 0 120 | 121 | displayValue = percent 122 | } 123 | 124 | return { 125 | content: showOriginValue ? `{nt}${digitalFlopUnit}` : `{nt}${digitalFlopUnit || '%'}`, 126 | number: [displayValue], 127 | style: digitalFlopStyle, 128 | toFixed: digitalFlopToFixed 129 | } 130 | }, [mergedConfig, activeIndex]) 131 | 132 | const ringName = useMemo( 133 | () => (!mergedConfig ? '' : mergedConfig.data[activeIndex].name), 134 | [mergedConfig, activeIndex] 135 | ) 136 | 137 | const fontSize = useMemo( 138 | () => 139 | !mergedConfig 140 | ? {} 141 | : { fontSize: `${mergedConfig.digitalFlopStyle.fontSize}px` }, 142 | [mergedConfig] 143 | ) 144 | 145 | function getRingOption(mergedConfig) { 146 | const radius = getRealRadius(mergedConfig) 147 | 148 | const newMergedConfig = { 149 | ...mergedConfig, 150 | data: mergedConfig.data.map(item => ({ ...item, radius })) 151 | } 152 | 153 | return { 154 | series: [ 155 | { 156 | type: 'pie', 157 | ...newMergedConfig, 158 | outsideLabel: { 159 | show: false 160 | } 161 | } 162 | ], 163 | color: newMergedConfig.color 164 | } 165 | } 166 | 167 | function getRealRadius({ radius, activeRadius, lineWidth }, active = false) { 168 | const maxRadius = Math.min(...chartRef.current.render.area) / 2 169 | 170 | const halfLineWidth = lineWidth / 2 171 | 172 | let realRadius = active ? activeRadius : radius 173 | 174 | if (typeof realRadius !== 'number') { 175 | realRadius = (parseInt(realRadius) / 100) * maxRadius 176 | } 177 | 178 | const insideRadius = realRadius - halfLineWidth 179 | const outSideRadius = realRadius + halfLineWidth 180 | 181 | return [insideRadius, outSideRadius] 182 | } 183 | 184 | function getOption(mergedConfig, activeIndex) { 185 | const radius = getRealRadius(mergedConfig) 186 | const active = getRealRadius(mergedConfig, true) 187 | 188 | let option = getRingOption(mergedConfig) 189 | 190 | return { 191 | ...option, 192 | series: option.series.reduce( 193 | (prev, serie, index) => 194 | index !== 0 195 | ? [...prev, serie] 196 | : [ 197 | ...prev, 198 | { 199 | ...serie, 200 | data: serie.data.map((item, i) => ({ 201 | ...item, 202 | radius: i === activeIndex ? active : radius 203 | })) 204 | } 205 | ], 206 | [] 207 | ) 208 | } 209 | } 210 | 211 | useEffect(() => { 212 | // 第一次时初始化 213 | chartRef.current || (chartRef.current = new Charts(domRef.current)) 214 | 215 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 216 | 217 | chartRef.current.setOption(getRingOption(mergedConfig), true) 218 | 219 | let activeIndex = 0 220 | 221 | function * loop() { 222 | while (true) { 223 | setState({ mergedConfig, activeIndex }) 224 | 225 | const option = getOption(mergedConfig, activeIndex) 226 | 227 | chartRef.current.setOption(option, true) 228 | 229 | const { activeTimeGap, data } = option.series[0] 230 | 231 | yield new Promise(resolve => setTimeout(resolve, activeTimeGap)) 232 | 233 | activeIndex += 1 234 | 235 | if (activeIndex >= data.length) { 236 | activeIndex = 0 237 | } 238 | } 239 | } 240 | 241 | return co(loop).end 242 | }, [config]) 243 | 244 | const classNames = useMemo( 245 | () => classnames('dv-active-ring-chart', className), 246 | [className] 247 | ) 248 | 249 | return ( 250 |
251 |
252 |
253 | 254 |
255 | {ringName} 256 |
257 |
258 |
259 | ) 260 | } 261 | 262 | ActiveRingChart.propTypes = { 263 | config: PropTypes.object, 264 | className: PropTypes.string, 265 | style: PropTypes.object 266 | } 267 | 268 | export default ActiveRingChart 269 | -------------------------------------------------------------------------------- /src/components/activeRingChart/style.less: -------------------------------------------------------------------------------- 1 | .dv-active-ring-chart { 2 | position: relative; 3 | 4 | .active-ring-chart-container { 5 | width: 100%; 6 | height: 100%; 7 | } 8 | 9 | .active-ring-info { 10 | position: absolute; 11 | width: 100%; 12 | height: 100%; 13 | left: 0px; 14 | top: 0px; 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: center; 18 | align-items: center; 19 | 20 | .dv-digital-flop { 21 | width: 100px; 22 | height: 30px; 23 | } 24 | 25 | .active-ring-name { 26 | width: 100px; 27 | height: 30px; 28 | color: #fff; 29 | text-align: center; 30 | vertical-align: middle; 31 | text-overflow: ellipsis; 32 | overflow: hidden; 33 | white-space: nowrap; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/components/borderBox1/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const border = ['left-top', 'right-top', 'left-bottom', 'right-bottom'] 15 | const defaultColor = ['#4fd2dd', '#235fa7'] 16 | 17 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 18 | const { width, height, domRef } = useAutoResize(ref) 19 | 20 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 21 | 22 | const classNames = useMemo(() => classnames('dv-border-box-1', className), [ 23 | className 24 | ]) 25 | 26 | return ( 27 |
28 | 29 | 37 | 38 | 39 | {border.map(borderName => ( 40 | 46 | 50 | 57 | 58 | 62 | 69 | 70 | 74 | 81 | 82 | 83 | ))} 84 | 85 |
{children}
86 |
87 | ) 88 | }) 89 | 90 | BorderBox.propTypes = { 91 | children: PropTypes.node, 92 | className: PropTypes.string, 93 | style: PropTypes.object, 94 | color: PropTypes.array, 95 | backgroundColor: PropTypes.string 96 | } 97 | 98 | export default BorderBox 99 | -------------------------------------------------------------------------------- /src/components/borderBox1/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-1 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .border { 7 | position: absolute; 8 | display: block; 9 | } 10 | 11 | .right-top { 12 | right: 0px; 13 | transform: rotateY(180deg); 14 | } 15 | 16 | .left-bottom { 17 | bottom: 0px; 18 | transform: rotateX(180deg); 19 | } 20 | 21 | .right-bottom { 22 | right: 0px; 23 | bottom: 0px; 24 | transform: rotateX(180deg) rotateY(180deg); 25 | } 26 | 27 | .border-box-content { 28 | position: relative; 29 | width: 100%; 30 | height: 100%; 31 | } 32 | } -------------------------------------------------------------------------------- /src/components/borderBox10/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const border = ['left-top', 'right-top', 'left-bottom', 'right-bottom'] 15 | const defaultColor = ['#1d48c4', '#d3e1f8'] 16 | 17 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 18 | const { width, height, domRef } = useAutoResize(ref) 19 | 20 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 21 | 22 | const classNames = useMemo(() => classnames('dv-border-box-10', className), [ 23 | className 24 | ]) 25 | 26 | const styles = useMemo(() => ({ 27 | boxShadow: `inset 0 0 25px 3px ${mergedColor[0]}`, 28 | ...style 29 | }), [style, mergedColor]) 30 | 31 | return ( 32 |
33 | 34 | 38 | 39 | 40 | {border.map(borderName => ( 41 | 47 | 51 | 52 | ))} 53 |
{children}
54 |
55 | ) 56 | }) 57 | 58 | BorderBox.propTypes = { 59 | children: PropTypes.node, 60 | className: PropTypes.string, 61 | style: PropTypes.object, 62 | color: PropTypes.array, 63 | backgroundColor: PropTypes.string 64 | } 65 | 66 | export default BorderBox 67 | -------------------------------------------------------------------------------- /src/components/borderBox10/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-10 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | border-radius: 6px; 6 | 7 | .dv-border-svg-container { 8 | position: absolute; 9 | display: block; 10 | } 11 | 12 | .right-top { 13 | right: 0px; 14 | transform: rotateY(180deg); 15 | } 16 | 17 | .left-bottom { 18 | bottom: 0px; 19 | transform: rotateX(180deg); 20 | } 21 | 22 | .right-bottom { 23 | right: 0px; 24 | bottom: 0px; 25 | transform: rotateX(180deg) rotateY(180deg); 26 | } 27 | 28 | .border-box-content { 29 | position: relative; 30 | width: 100%; 31 | height: 100%; 32 | } 33 | } -------------------------------------------------------------------------------- /src/components/borderBox11/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, useRef, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | import { fade } from '@jiaminghi/color' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import { uuid } from '../../util' 14 | 15 | import './style.less' 16 | 17 | const defaultColor = ['#8aaafb', '#1f33a2'] 18 | 19 | const BorderBox = forwardRef(({ children, className, style, color = [], titleWidth = 250, title = '', backgroundColor = 'transparent' }, ref) => { 20 | const filterId = useRef(`border-box-11-filterId-${uuid()}`).current 21 | 22 | const { width, height, domRef } = useAutoResize(ref) 23 | 24 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 25 | 26 | const classNames = useMemo(() => classnames('dv-border-box-11', className), [ 27 | className 28 | ]) 29 | 30 | return ( 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 70 | 71 | 79 | 80 | 88 | 89 | 99 | 100 | 109 | 116 | 117 | 118 | 127 | 134 | 135 | 136 | 145 | 152 | 153 | 154 | 163 | 170 | 171 | 172 | 181 | 188 | 189 | 190 | 199 | 206 | 207 | 208 | 217 | {title} 218 | 219 | 220 | 228 | 229 | 237 | 238 | 239 |
240 | {children} 241 |
242 |
243 | ) 244 | }) 245 | 246 | BorderBox.propTypes = { 247 | children: PropTypes.node, 248 | className: PropTypes.string, 249 | style: PropTypes.object, 250 | color: PropTypes.array, 251 | titleWidth: PropTypes.number, 252 | title: PropTypes.string, 253 | backgroundColor: PropTypes.string 254 | } 255 | 256 | export default BorderBox 257 | -------------------------------------------------------------------------------- /src/components/borderBox11/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-11 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | top: 0px; 11 | left: 0px; 12 | 13 | & > polyline { 14 | fill: none; 15 | stroke-width: 1; 16 | } 17 | } 18 | 19 | .border-box-content { 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | } 24 | } -------------------------------------------------------------------------------- /src/components/borderBox12/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, useRef, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | import { fade } from '@jiaminghi/color' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import { uuid } from '../../util' 14 | 15 | import './style.less' 16 | 17 | const defaultColor = ['#2e6099', '#7ce7fd'] 18 | 19 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 20 | const filterId = useRef(`border-box-12-filterId-${uuid()}`).current 21 | 22 | const { width, height, domRef } = useAutoResize(ref) 23 | 24 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 25 | 26 | const classNames = useMemo(() => classnames('dv-border-box-12', className), [ 27 | className 28 | ]) 29 | 30 | return ( 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | { 59 | width && height && 60 | 71 | } 72 | 73 | 81 | 82 | 90 | 91 | 103 | 104 | 116 | 117 |
118 | {children} 119 |
120 |
121 | ) 122 | }) 123 | 124 | BorderBox.propTypes = { 125 | children: PropTypes.node, 126 | className: PropTypes.string, 127 | style: PropTypes.object, 128 | color: PropTypes.array, 129 | backgroundColor: PropTypes.string 130 | } 131 | 132 | export default BorderBox 133 | -------------------------------------------------------------------------------- /src/components/borderBox12/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-12 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | top: 0px; 11 | left: 0px; 12 | } 13 | 14 | .border-box-content { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | } -------------------------------------------------------------------------------- /src/components/borderBox13/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#6586ec', '#2cf7fe'] 15 | 16 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-13', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 28 | 38 | 39 | 47 | 48 | 53 | 54 | 59 | 60 |
61 | {children} 62 |
63 |
64 | ) 65 | }) 66 | 67 | BorderBox.propTypes = { 68 | children: PropTypes.node, 69 | className: PropTypes.string, 70 | style: PropTypes.object, 71 | color: PropTypes.array, 72 | backgroundColor: PropTypes.string 73 | } 74 | 75 | export default BorderBox 76 | -------------------------------------------------------------------------------- /src/components/borderBox13/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-13 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | top: 0px; 11 | left: 0px; 12 | } 13 | 14 | .border-box-content { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | } -------------------------------------------------------------------------------- /src/components/borderBox2/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#fff', 'rgba(255, 255, 255, 0.6)'] 15 | 16 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-2', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 28 | 31 | 36 | 41 | 42 | 43 | 44 | 45 | 46 |
{children}
47 |
48 | ) 49 | }) 50 | 51 | BorderBox.propTypes = { 52 | children: PropTypes.node, 53 | className: PropTypes.string, 54 | style: PropTypes.object, 55 | color: PropTypes.array, 56 | backgroundColor: PropTypes.string 57 | } 58 | 59 | export default BorderBox 60 | -------------------------------------------------------------------------------- /src/components/borderBox2/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-2 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | top: 0px; 11 | left: 0px; 12 | 13 | & > polyline { 14 | fill: none; 15 | stroke-width: 1; 16 | } 17 | } 18 | 19 | .border-box-content { 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | } 24 | } -------------------------------------------------------------------------------- /src/components/borderBox3/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#2862b7', '#2862b7'] 15 | 16 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-3', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 28 | 31 | 37 | 43 | 49 | 55 | 56 | 57 |
{children}
58 |
59 | ) 60 | }) 61 | 62 | BorderBox.propTypes = { 63 | children: PropTypes.node, 64 | className: PropTypes.string, 65 | style: PropTypes.object, 66 | color: PropTypes.array, 67 | backgroundColor: PropTypes.string 68 | } 69 | 70 | export default BorderBox 71 | -------------------------------------------------------------------------------- /src/components/borderBox3/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-3 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | top: 0px; 11 | left: 0px; 12 | 13 | & > polyline { 14 | fill: none; 15 | } 16 | } 17 | 18 | .dv-bb3-line1 { 19 | stroke-width: 3; 20 | } 21 | 22 | .dv-bb3-line2 { 23 | stroke-width: 1; 24 | } 25 | 26 | .border-box-content { 27 | position: relative; 28 | width: 100%; 29 | height: 100%; 30 | } 31 | } -------------------------------------------------------------------------------- /src/components/borderBox4/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['red', 'rgba(0,0,255,0.8)'] 15 | 16 | const BorderBox = forwardRef(({ children, reverse = false, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-4', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 32 | 36 | 42 | 48 | 53 | 54 | 55 | 56 | 61 | 62 | 67 | 72 | 73 | 74 |
{children}
75 |
76 | ) 77 | }) 78 | 79 | BorderBox.propTypes = { 80 | children: PropTypes.node, 81 | reverse: PropTypes.bool, 82 | className: PropTypes.string, 83 | style: PropTypes.object, 84 | color: PropTypes.array, 85 | backgroundColor: PropTypes.string 86 | } 87 | 88 | // 指定 props 的默认值: 89 | BorderBox.defaultProps = { 90 | reverse: false, 91 | backgroundColor: 'transparent' 92 | } 93 | 94 | export default BorderBox 95 | -------------------------------------------------------------------------------- /src/components/borderBox4/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-4 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-reverse { 7 | transform: rotate(180deg); 8 | } 9 | 10 | .dv-border-svg-container { 11 | position: absolute; 12 | width: 100%; 13 | height: 100%; 14 | top: 0px; 15 | left: 0px; 16 | 17 | & > polyline { 18 | fill: none; 19 | } 20 | } 21 | 22 | .sw1 { 23 | stroke-width: 1; 24 | } 25 | 26 | .sw3 { 27 | stroke-width: 3px; 28 | stroke-linecap: round; 29 | } 30 | 31 | .dv-bb4-line-1 { 32 | .sw1; 33 | } 34 | 35 | .dv-bb4-line-2 { 36 | .sw1; 37 | } 38 | 39 | .dv-bb4-line-3 { 40 | .sw3; 41 | } 42 | 43 | .dv-bb4-line-4 { 44 | .sw3; 45 | } 46 | 47 | .dv-bb4-line-5 { 48 | .sw1; 49 | } 50 | 51 | .dv-bb4-line-6 { 52 | .sw1; 53 | } 54 | 55 | .dv-bb4-line-7 { 56 | .sw1; 57 | } 58 | 59 | .dv-bb4-line-8 { 60 | .sw3; 61 | } 62 | 63 | .dv-bb4-line-9 { 64 | .sw3; 65 | stroke-dasharray: 100 250; 66 | } 67 | 68 | .dv-bb4-line-10 { 69 | .sw1; 70 | stroke-dasharray: 80 270; 71 | } 72 | 73 | .border-box-content { 74 | position: relative; 75 | width: 100%; 76 | height: 100%; 77 | } 78 | } -------------------------------------------------------------------------------- /src/components/borderBox5/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['rgba(255, 255, 255, 0.35)', 'rgba(255, 255, 255, 0.20)'] 15 | 16 | const BorderBox = forwardRef(({ children, reverse = false, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-5', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 32 | 35 | 41 | 47 | 52 | 57 | 62 | 67 | 68 | 69 |
{children}
70 |
71 | ) 72 | }) 73 | 74 | BorderBox.propTypes = { 75 | children: PropTypes.node, 76 | reverse: PropTypes.bool, 77 | className: PropTypes.string, 78 | style: PropTypes.object, 79 | color: PropTypes.array, 80 | backgroundColor: PropTypes.string 81 | } 82 | 83 | // 指定 props 的默认值: 84 | BorderBox.defaultProps = { 85 | reverse: false, 86 | backgroundColor: 'transparent' 87 | } 88 | 89 | export default BorderBox 90 | -------------------------------------------------------------------------------- /src/components/borderBox5/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-5 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-reverse { 7 | transform: rotate(180deg); 8 | } 9 | 10 | .dv-border-svg-container { 11 | position: absolute; 12 | top: 0px; 13 | left: 0px; 14 | width: 100%; 15 | height: 100%; 16 | 17 | & > polyline { 18 | fill: none; 19 | } 20 | } 21 | 22 | .dv-bb5-line-1, .dv-bb5-line-2 { 23 | stroke-width: 1; 24 | } 25 | 26 | .dv-bb5-line-3, .dv-bb5-line-6 { 27 | stroke-width: 5; 28 | } 29 | 30 | .dv-bb5-line-4, .dv-bb5-line-5 { 31 | stroke-width: 2; 32 | } 33 | 34 | .border-box-content { 35 | position: relative; 36 | width: 100%; 37 | height: 100%; 38 | } 39 | } -------------------------------------------------------------------------------- /src/components/borderBox6/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['rgba(255, 255, 255, 0.35)', 'gray'] 15 | 16 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-6', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 53 | 54 | 55 |
{children}
56 |
57 | ) 58 | }) 59 | 60 | BorderBox.propTypes = { 61 | children: PropTypes.node, 62 | className: PropTypes.string, 63 | style: PropTypes.object, 64 | color: PropTypes.array, 65 | backgroundColor: PropTypes.string 66 | } 67 | 68 | export default BorderBox 69 | -------------------------------------------------------------------------------- /src/components/borderBox6/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-6 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | top: 0px; 9 | left: 0px; 10 | width: 100%; 11 | height: 100%; 12 | 13 | & > polyline { 14 | fill: none; 15 | stroke-width: 1; 16 | } 17 | } 18 | 19 | .border-box-content { 20 | position: relative; 21 | width: 100%; 22 | height: 100%; 23 | } 24 | } -------------------------------------------------------------------------------- /src/components/borderBox7/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['rgba(128,128,128,0.3)', 'rgba(128,128,128,0.5)'] 15 | 16 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-border-box-7', className), [ 22 | className 23 | ]) 24 | 25 | const styles = useMemo(() => ({ 26 | boxShadow: `inset 0 0 40px ${mergedColor[0]}`, 27 | border: `1px solid ${mergedColor[0]}`, 28 | backgroundColor, 29 | ...style 30 | }), [style, mergedColor, backgroundColor]) 31 | 32 | return ( 33 |
34 | 35 | 36 | 41 | 47 | 52 | 53 | 58 | 64 | 69 | 70 | 71 |
{children}
72 |
73 | ) 74 | }) 75 | 76 | BorderBox.propTypes = { 77 | children: PropTypes.node, 78 | className: PropTypes.string, 79 | style: PropTypes.object, 80 | color: PropTypes.array, 81 | backgroundColor: PropTypes.string 82 | } 83 | 84 | export default BorderBox 85 | -------------------------------------------------------------------------------- /src/components/borderBox7/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-7 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | top: 0px; 9 | left: 0px; 10 | width: 100%; 11 | height: 100%; 12 | 13 | & > polyline { 14 | fill: none; 15 | stroke-linecap: round; 16 | } 17 | } 18 | 19 | .dv-bb7-line-width-2 { 20 | stroke-width: 2; 21 | } 22 | 23 | .dv-bb7-line-width-5 { 24 | stroke-width: 5; 25 | } 26 | 27 | .border-box-content { 28 | position: relative; 29 | width: 100%; 30 | height: 100%; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/borderBox8/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import { uuid } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultColor = ['#235fa7', '#4fd2dd'] 17 | 18 | const BorderBox = forwardRef(( 19 | { 20 | children, 21 | className, 22 | style, 23 | color = [], 24 | dur = 3, 25 | backgroundColor = 'transparent', 26 | reverse = false 27 | }, 28 | ref 29 | ) => { 30 | const { width, height, domRef } = useAutoResize(ref) 31 | 32 | const [{ path, gradient, mask }] = useState(() => { 33 | const id = uuid() 34 | 35 | return { 36 | path: `border-box-8-path-${id}`, 37 | gradient: `border-box-8-gradient-${id}`, 38 | mask: `border-box-8-mask-${id}` 39 | } 40 | }) 41 | 42 | const pathD = useMemo(() => 43 | reverse 44 | ? `M 2.5, 2.5 L 2.5, ${height - 2.5} L ${width - 2.5}, ${height - 2.5} L ${width - 2.5}, 2.5 L 2.5, 2.5` 45 | : `M2.5, 2.5 L${width - 2.5}, 2.5 L${width - 2.5}, ${height - 2.5} L2.5, ${height - 2.5} L2.5, 2.5` 46 | , [width, height, reverse]) 47 | 48 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 49 | 50 | const length = useMemo(() => (width + height - 5) * 2, [width, height]) 51 | 52 | const classNames = useMemo(() => classnames('dv-border-box-8', className), [ 53 | className 54 | ]) 55 | 56 | return ( 57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 90 | 91 | 92 | 93 |
{children}
94 |
95 | ) 96 | }) 97 | 98 | BorderBox.propTypes = { 99 | children: PropTypes.node, 100 | className: PropTypes.string, 101 | style: PropTypes.object, 102 | color: PropTypes.array, 103 | dur: PropTypes.number, 104 | backgroundColor: PropTypes.string, 105 | reverse: PropTypes.bool 106 | } 107 | 108 | export default BorderBox 109 | -------------------------------------------------------------------------------- /src/components/borderBox8/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-8 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | left: 0px; 11 | top: 0px; 12 | } 13 | 14 | .border-box-content { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | } -------------------------------------------------------------------------------- /src/components/borderBox9/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import { uuid } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultColor = ['#11eefd', '#0078d2'] 17 | 18 | const BorderBox = forwardRef(({ children, className, style, color = [], backgroundColor = 'transparent' }, ref) => { 19 | const { width, height, domRef } = useAutoResize(ref) 20 | 21 | const [{ gradientId, maskId }] = useState(() => { 22 | const id = uuid() 23 | 24 | return { 25 | gradientId: `border-box-9-gradient-${id}`, 26 | maskId: `border-box-9-mask-${id}` 27 | } 28 | }) 29 | 30 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 31 | 32 | const classNames = useMemo(() => classnames('dv-border-box-9', className), [ 33 | className 34 | ]) 35 | 36 | return ( 37 |
38 | 39 | 40 | 41 | 48 | 55 | 56 | 63 | 64 | 65 | 72 | 73 | 74 | 75 | 76 | 82 | 88 | 89 | 96 | 103 | 112 | 113 | 120 | 127 | 128 | 135 | 144 | 145 | 146 | 147 | 155 | 156 | 164 | 165 | 166 |
{children}
167 |
168 | ) 169 | }) 170 | 171 | BorderBox.propTypes = { 172 | children: PropTypes.node, 173 | className: PropTypes.string, 174 | style: PropTypes.object, 175 | color: PropTypes.array, 176 | backgroundColor: PropTypes.string 177 | } 178 | 179 | export default BorderBox 180 | -------------------------------------------------------------------------------- /src/components/borderBox9/style.less: -------------------------------------------------------------------------------- 1 | .dv-border-box-9 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .dv-border-svg-container { 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | left: 0px; 11 | top: 0px; 12 | } 13 | 14 | .border-box-content { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | } -------------------------------------------------------------------------------- /src/components/capsuleChart/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import './style.less' 12 | 13 | const defaultConfig = { 14 | /** 15 | * @description Capsule chart data 16 | * @type {Array} 17 | * @default data = [] 18 | * @example data = [{ name: 'foo1', value: 100 }, { name: 'foo2', value: 100 }] 19 | */ 20 | data: [], 21 | /** 22 | * @description Colors (hex|rgb|rgba|color keywords) 23 | * @type {Array} 24 | * @default color = ['#37a2da', '#32c5e9', '#67e0e3', '#9fe6b8', '#ffdb5c', '#ff9f7f', '#fb7293'] 25 | * @example color = ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red'] 26 | */ 27 | colors: [ 28 | '#37a2da', 29 | '#32c5e9', 30 | '#67e0e3', 31 | '#9fe6b8', 32 | '#ffdb5c', 33 | '#ff9f7f', 34 | '#fb7293' 35 | ], 36 | /** 37 | * @description Chart unit 38 | * @type {String} 39 | * @default unit = '' 40 | */ 41 | unit: '', 42 | /** 43 | * @description Show item value 44 | * @type {Boolean} 45 | * @default showValue = false 46 | */ 47 | showValue: false 48 | } 49 | 50 | const CapsuleChart = ({ config = {}, className, style }) => { 51 | const [{ mergedConfig, labelData, capsuleLength, capsuleValue }, setState] = useState({ 52 | mergedConfig: null, 53 | labelData: [], 54 | capsuleLength: [], 55 | capsuleValue: [] 56 | }) 57 | 58 | useEffect(() => { 59 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 60 | 61 | const { data } = mergedConfig 62 | 63 | if (!data.length) return 64 | 65 | const capsuleValue = data.map(({ value }) => value) 66 | 67 | const maxValue = Math.max(...capsuleValue) 68 | 69 | const oneFifth = maxValue / 5 70 | 71 | setState({ 72 | mergedConfig, 73 | capsuleValue, 74 | capsuleLength: capsuleValue.map(v => (maxValue ? v / maxValue : 0)), 75 | labelData: [...new Set(new Array(6).fill(0).map((v, i) => Math.ceil(i * oneFifth)))] 76 | }) 77 | }, [config]) 78 | 79 | const classNames = useMemo(() => classnames('dv-capsule-chart', className), [ 80 | className 81 | ]) 82 | 83 | return ( 84 |
85 | {!!mergedConfig && ( 86 | 87 |
88 | {mergedConfig.data.map(({ name }) => ( 89 |
{name}
90 | ))} 91 |
 
92 |
93 | 94 |
95 | {capsuleLength.map((capsule, index) => ( 96 |
97 |
106 | { 107 | mergedConfig.showValue && 108 |
109 | { capsuleValue[index] } 110 |
111 | } 112 |
113 |
114 | ))} 115 | 116 |
117 | {labelData.map((label, index) => ( 118 |
{label}
119 | ))} 120 |
121 |
122 | 123 | {!!mergedConfig.unit && ( 124 |
{mergedConfig.unit}
125 | )} 126 |
127 | )} 128 |
129 | ) 130 | } 131 | 132 | CapsuleChart.propTypes = { 133 | config: PropTypes.object, 134 | className: PropTypes.string, 135 | style: PropTypes.object 136 | } 137 | 138 | export default CapsuleChart 139 | -------------------------------------------------------------------------------- /src/components/capsuleChart/style.less: -------------------------------------------------------------------------------- 1 | .dv-capsule-chart { 2 | position: relative; 3 | display: flex; 4 | flex-direction: row; 5 | box-sizing: border-box; 6 | padding: 10px; 7 | color: #fff; 8 | 9 | .label-column { 10 | display: flex; 11 | flex-direction: column; 12 | justify-content: space-between; 13 | box-sizing: border-box; 14 | padding-right: 10px; 15 | text-align: right; 16 | font-size: 12px; 17 | 18 | div { 19 | height: 20px; 20 | line-height: 20px; 21 | } 22 | } 23 | 24 | .capsule-container { 25 | flex: 1; 26 | display: flex; 27 | flex-direction: column; 28 | justify-content: space-between; 29 | } 30 | 31 | .capsule-item { 32 | box-shadow: 0 0 3px #999; 33 | height: 10px; 34 | margin: 5px 0px; 35 | border-radius: 5px; 36 | 37 | .capsule-item-column { 38 | position: relative; 39 | height: 8px; 40 | margin-top: 1px; 41 | border-radius: 5px; 42 | transition: all 0.3s; 43 | display: flex; 44 | justify-content: flex-end; 45 | align-items: center; 46 | 47 | .capsule-item-value { 48 | font-size: 12px; 49 | transform: translateX(100%); 50 | } 51 | } 52 | } 53 | 54 | .unit-label { 55 | height: 20px; 56 | font-size: 12px; 57 | position: relative; 58 | display: flex; 59 | justify-content: space-between; 60 | align-items: center; 61 | } 62 | 63 | .unit-text { 64 | text-align: right; 65 | display: flex; 66 | align-items: flex-end; 67 | font-size: 12px; 68 | line-height: 20px; 69 | margin-left: 10px; 70 | } 71 | } -------------------------------------------------------------------------------- /src/components/charts/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import Chart from '@jiaminghi/charts' 8 | 9 | import useAutoResize from '../../use/autoResize' 10 | 11 | import './style.less' 12 | 13 | const Charts = forwardRef(({ option = {}, className, style }, ref) => { 14 | const { width, height, domRef } = useAutoResize(ref) 15 | 16 | const chartRef = useRef(null) 17 | 18 | const chartInstanceofRef = useRef(null) 19 | 20 | useEffect(() => { 21 | chartInstanceofRef.current || 22 | (chartInstanceofRef.current = new Chart(chartRef.current)) 23 | 24 | chartInstanceofRef.current.setOption(option || {}, true) 25 | }, [option]) 26 | 27 | useEffect(() => { 28 | chartInstanceofRef.current.resize() 29 | }, [width, height]) 30 | 31 | const classNames = useMemo( 32 | () => classnames('dv-charts-container', className), 33 | [className] 34 | ) 35 | 36 | return ( 37 |
38 |
39 |
40 | ) 41 | }) 42 | 43 | Charts.propTypes = { 44 | option: PropTypes.object, 45 | className: PropTypes.string, 46 | style: PropTypes.object 47 | } 48 | 49 | export default Charts 50 | -------------------------------------------------------------------------------- /src/components/charts/style.less: -------------------------------------------------------------------------------- 1 | .dv-charts-container { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .charts-canvas-container { 7 | width: 100%; 8 | height: 100%; 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/conicalColumnChart/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import './style.less' 14 | 15 | const defaultConfig = { 16 | /** 17 | * @description Chart data 18 | * @type {Array} 19 | * @default data = [] 20 | */ 21 | data: [], 22 | /** 23 | * @description Chart img 24 | * @type {Array} 25 | * @default img = [] 26 | */ 27 | img: [], 28 | /** 29 | * @description Chart font size 30 | * @type {Number} 31 | * @default fontSize = 12 32 | */ 33 | fontSize: 12, 34 | /** 35 | * @description Img side length 36 | * @type {Number} 37 | * @default imgSideLength = 30 38 | */ 39 | imgSideLength: 30, 40 | /** 41 | * @description Column color 42 | * @type {String} 43 | * @default columnColor = 'rgba(0, 194, 255, 0.4)' 44 | */ 45 | columnColor: 'rgba(0, 194, 255, 0.4)', 46 | /** 47 | * @description Text color 48 | * @type {String} 49 | * @default textColor = '#fff' 50 | */ 51 | textColor: '#fff', 52 | /** 53 | * @description Show value 54 | * @type {Boolean} 55 | * @default showValue = false 56 | */ 57 | showValue: false 58 | } 59 | 60 | function getData(mergedConfig) { 61 | let { data } = mergedConfig 62 | 63 | data = deepClone(data, true) 64 | 65 | data.sort(({ value: a }, { value: b }) => { 66 | if (a > b) return -1 67 | if (a < b) return 1 68 | if (a === b) return 0 69 | }) 70 | 71 | const max = data[0] ? data[0].value : 10 72 | 73 | data = data.map(item => ({ 74 | ...item, 75 | percent: item.value / max 76 | })) 77 | 78 | return data 79 | } 80 | 81 | const ConicalColumnChart = forwardRef(({ config = {}, className, style }, ref) => { 82 | const { width, height, domRef } = useAutoResize(ref) 83 | 84 | const { mergedConfig, column } = useMemo(calcData, [config, width, height]) 85 | 86 | function calcData() { 87 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 88 | 89 | mergedConfig.data = getData(mergedConfig) 90 | 91 | return { mergedConfig, column: getColumn(mergedConfig) } 92 | } 93 | 94 | function getColumn(mergedConfig) { 95 | const { imgSideLength, fontSize, data } = mergedConfig 96 | 97 | const itemNum = data.length 98 | const gap = width / (itemNum + 1) 99 | 100 | const useAbleHeight = height - imgSideLength - fontSize - 5 101 | const svgBottom = height - fontSize - 5 102 | 103 | return data.map((item, i) => { 104 | const { percent } = item 105 | 106 | const middleXPos = gap * (i + 1) 107 | const leftXPos = gap * i 108 | const rightXpos = gap * (i + 2) 109 | 110 | const middleYPos = svgBottom - useAbleHeight * percent 111 | const controlYPos = useAbleHeight * percent * 0.6 + middleYPos 112 | 113 | const d = ` 114 | M${leftXPos}, ${svgBottom} 115 | Q${middleXPos}, ${controlYPos} ${middleXPos},${middleYPos} 116 | M${middleXPos},${middleYPos} 117 | Q${middleXPos}, ${controlYPos} ${rightXpos},${svgBottom} 118 | L${leftXPos}, ${svgBottom} 119 | Z 120 | ` 121 | 122 | const textY = (svgBottom + middleYPos) / 2 + fontSize / 2 123 | 124 | return { 125 | ...item, 126 | d, 127 | x: middleXPos, 128 | y: middleYPos, 129 | textY 130 | } 131 | }) 132 | } 133 | 134 | const classNames = useMemo( 135 | () => classnames('dv-conical-column-chart', className), 136 | [className] 137 | ) 138 | 139 | return ( 140 |
141 | 142 | {column.map((item, i) => ( 143 | 144 | 145 | 151 | {item.name} 152 | 153 | {!!mergedConfig.img.length && ( 154 | 161 | )} 162 | {mergedConfig.showValue && ( 163 | 169 | {item.value} 170 | 171 | )} 172 | 173 | ))} 174 | 175 |
176 | ) 177 | }) 178 | 179 | ConicalColumnChart.propTypes = { 180 | config: PropTypes.object, 181 | className: PropTypes.string, 182 | style: PropTypes.object 183 | } 184 | 185 | export default ConicalColumnChart 186 | -------------------------------------------------------------------------------- /src/components/conicalColumnChart/style.less: -------------------------------------------------------------------------------- 1 | .dv-conical-column-chart { 2 | width: 100%; 3 | height: 100%; 4 | 5 | text { 6 | text-anchor: middle; 7 | } 8 | } -------------------------------------------------------------------------------- /src/components/decoration1/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#fff', '#0de7c2'] 15 | 16 | const pointSideLength = 2.5 17 | 18 | const halfPointSideLength = pointSideLength / 2 19 | 20 | const svgWH = [200, 50] 21 | 22 | const rowNum = 4 23 | 24 | const rowPoints = 20 25 | 26 | function getPoints() { 27 | const [w, h] = svgWH 28 | 29 | const horizontalGap = w / (rowPoints + 1) 30 | const verticalGap = h / (rowNum + 1) 31 | 32 | const points = new Array(rowNum) 33 | .fill(0) 34 | .map((foo, i) => 35 | new Array(rowPoints) 36 | .fill(0) 37 | .map((foo, j) => [horizontalGap * (j + 1), verticalGap * (i + 1)]) 38 | ) 39 | 40 | return points.reduce((all, item) => [...all, ...item], []) 41 | } 42 | 43 | const Decoration = forwardRef(({ className, style, color = [] }, ref) => { 44 | const { width, height, domRef } = useAutoResize(ref) 45 | 46 | function calcSVGData() { 47 | const points = getPoints() 48 | 49 | return { 50 | points, 51 | rects: [points[rowPoints * 2 - 1], points[rowPoints * 2 - 3]], 52 | svgScale: [width / svgWH[0], height / svgWH[1]] 53 | } 54 | } 55 | 56 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 57 | 58 | const { svgScale, points, rects } = useMemo(calcSVGData, [width, height]) 59 | 60 | const classNames = useMemo(() => classnames('dv-decoration-1', className), [ 61 | className 62 | ]) 63 | 64 | return ( 65 |
66 | 71 | {points.reduce((prev, point, i) => { 72 | return Math.random() > 0.6 73 | ? [ 74 | ...prev, 75 | 83 | {Math.random() > 0.6 && ( 84 | 91 | )} 92 | 93 | ] 94 | : prev 95 | }, [])} 96 | {!!rects[0] && ( 97 | 104 | 110 | 116 | 122 | 128 | 129 | )} 130 | {!!rects[1] && ( 131 | 138 | 144 | 150 | 151 | )} 152 | 153 |
154 | ) 155 | }) 156 | 157 | Decoration.propTypes = { 158 | className: PropTypes.string, 159 | style: PropTypes.object, 160 | color: PropTypes.array 161 | } 162 | 163 | export default Decoration 164 | -------------------------------------------------------------------------------- /src/components/decoration1/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-1 { 2 | width: 100%; 3 | height: 100%; 4 | 5 | svg { 6 | transform-origin: left top; 7 | } 8 | } -------------------------------------------------------------------------------- /src/components/decoration10/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import { uuid } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultColor = ['#00c2ff', 'rgba(0, 194, 255, 0.3)'] 17 | 18 | const Decoration = forwardRef(({ className, style, color = [] }, ref) => { 19 | const { width, height, domRef } = useAutoResize(ref) 20 | 21 | const { 22 | animationId1, 23 | animationId2, 24 | animationId3, 25 | animationId4, 26 | animationId5, 27 | animationId6, 28 | animationId7 29 | } = useRef({ 30 | animationId1: `d10ani1${uuid()}`, 31 | animationId2: `d10ani2${uuid()}`, 32 | animationId3: `d10ani3${uuid()}`, 33 | animationId4: `d10ani4${uuid()}`, 34 | animationId5: `d10ani5${uuid()}`, 35 | animationId6: `d10ani6${uuid()}`, 36 | animationId7: `d10ani7${uuid()}` 37 | }).current 38 | 39 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 40 | 41 | const classNames = useMemo(() => classnames('dv-decoration-10', className), [ 42 | className 43 | ]) 44 | 45 | return ( 46 |
47 | 48 | 53 | 54 | 61 | 69 | 76 | 77 | 78 | 85 | 93 | 100 | 101 | 102 | 109 | 117 | 124 | 125 | 126 | 127 | 135 | 136 | 137 | 138 | 146 | 153 | 154 | 155 | 156 | 164 | 171 | 172 | 173 | 174 | 182 | 189 | 190 | 191 |
192 | ) 193 | }) 194 | 195 | Decoration.propTypes = { 196 | className: PropTypes.string, 197 | style: PropTypes.object, 198 | color: PropTypes.array 199 | } 200 | 201 | export default Decoration 202 | -------------------------------------------------------------------------------- /src/components/decoration10/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-10 { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | } -------------------------------------------------------------------------------- /src/components/decoration11/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | import { fade } from '@jiaminghi/color' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import './style.less' 14 | 15 | const defaultColor = ['#1a98fc', '#2cf7fe'] 16 | 17 | const BorderBox = forwardRef(({ children, className, style, color = [] }, ref) => { 18 | const { width, height, domRef } = useAutoResize(ref) 19 | 20 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 21 | 22 | const classNames = useMemo(() => classnames('dv-decoration-11', className), [ 23 | className 24 | ]) 25 | 26 | return ( 27 |
28 | 29 | 34 | 35 | 40 | 41 | 46 | 47 | 52 | 53 | 61 | 62 | 67 | 68 | 73 | 74 | 75 |
76 | {children} 77 |
78 |
79 | ) 80 | }) 81 | 82 | BorderBox.propTypes = { 83 | children: PropTypes.node, 84 | className: PropTypes.string, 85 | style: PropTypes.object, 86 | color: PropTypes.array 87 | } 88 | 89 | export default BorderBox 90 | -------------------------------------------------------------------------------- /src/components/decoration11/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-11 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | 7 | .decoration-content { 8 | position: absolute; 9 | top: 0px; 10 | left: 0px; 11 | width: 100%; 12 | height: 100%; 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | } 17 | } -------------------------------------------------------------------------------- /src/components/decoration12/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef, useRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone, getCircleRadianPoint } from '@jiaminghi/c-render/lib/plugin/util' 9 | import { fade } from '@jiaminghi/color' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | import { uuid } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultColor = ['#2783ce', '#2cf7fe'] 17 | 18 | const segment = 30 19 | 20 | const sectorAngle = Math.PI / 3 21 | 22 | const ringNum = 3 23 | 24 | const ringWidth = 1 25 | 26 | const showSplitLine = true 27 | 28 | const BorderBox = forwardRef(({ children, className, style, color = [], scanDur = 3, haloDur = 2 }, ref) => { 29 | const { width, height, domRef } = useAutoResize(ref) 30 | 31 | const x = width / 2 32 | 33 | const y = height / 2 34 | 35 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 36 | 37 | const pathD = useMemo(() => { 38 | const startAngle = -Math.PI / 2 39 | const angleGap = sectorAngle / segment 40 | const r = width / 4 41 | let lastEndPoints = getCircleRadianPoint(x, y, r, startAngle) 42 | 43 | return new Array(segment) 44 | .fill('') 45 | .map((_, i) => { 46 | const endPoints = getCircleRadianPoint(x, y, r, startAngle - (i + 1) * angleGap).map(_ => _.toFixed(5)) 47 | const d = `M${lastEndPoints.join(',')} A${r}, ${r} 0 0 0 ${endPoints.join(',')}` 48 | lastEndPoints = endPoints 49 | return d 50 | }) 51 | }, [x, y, width]) 52 | 53 | const pathColor = useMemo(() => { 54 | const color = mergedColor[0] 55 | const colorGap = 100 / (segment - 1) 56 | 57 | return new Array(segment) 58 | .fill(color) 59 | .map((_, i) => fade(color, 100 - i * colorGap)) 60 | }, [mergedColor]) 61 | 62 | const circleR = useMemo(() => { 63 | const radiusGap = (width / 2 - ringWidth / 2) / ringNum 64 | 65 | return new Array(ringNum) 66 | .fill(0) 67 | .map((_, i) => radiusGap * (i + 1)) 68 | }, [width]) 69 | 70 | const splitLinePoints = useMemo(() => { 71 | const angleGap = Math.PI / 6 72 | const r = width / 2 73 | return new Array(6) 74 | .fill('') 75 | .map((_, i) => { 76 | const startAngle = angleGap * (i + 1) 77 | const endAngle = startAngle + Math.PI 78 | const startPoint = getCircleRadianPoint(x, y, r, startAngle) 79 | const endPoint = getCircleRadianPoint(x, y, r, endAngle) 80 | return `${startPoint.join(',')} ${endPoint.join(',')}` 81 | }) 82 | }, [x, y, width]) 83 | 84 | const arcD = useMemo(() => { 85 | const angleGap = Math.PI / 6 86 | const r = width / 2 - 1 87 | 88 | return new Array(4) 89 | .fill('') 90 | .map((_, i) => { 91 | const startAngle = angleGap * (3 * i + 1) 92 | const endAngle = startAngle + angleGap 93 | const startPoint = getCircleRadianPoint(x, y, r, startAngle) 94 | const endPoint = getCircleRadianPoint(x, y, r, endAngle) 95 | return `M${startPoint.join(',')} A${x}, ${y} 0 0 1 ${endPoint.join(',')}` 96 | }) 97 | }, [x, y, width]) 98 | 99 | const idRef = useRef({ 100 | gId: `decoration-12-g-${uuid()}`, 101 | gradientId: `decoration-12-gradient-${uuid()}` 102 | }) 103 | 104 | const classNames = useMemo(() => classnames('dv-decoration-12', className), [ 105 | className 106 | ]) 107 | 108 | return ( 109 |
110 | 111 | 112 | 113 | { 114 | pathD.map((d, i) => ) 121 | } 122 | 123 | 124 | 128 | 129 | 130 | 131 | 132 | 133 | { 134 | circleR.map(r => ) 143 | } 144 | 145 | 152 | 158 | 164 | 165 | 166 | 172 | 173 | { 174 | showSplitLine && 175 | { 176 | splitLinePoints.map(p => ) 183 | } 184 | 185 | 186 | } 187 | 188 | { 189 | arcD.map(d => ) 196 | } 197 | 198 | 199 | 206 | 207 | 208 | 209 |
210 | {children} 211 |
212 |
213 | ) 214 | }) 215 | 216 | BorderBox.propTypes = { 217 | children: PropTypes.node, 218 | className: PropTypes.string, 219 | style: PropTypes.object, 220 | color: PropTypes.array, 221 | scanDur: PropTypes.number, 222 | haloDur: PropTypes.number 223 | } 224 | 225 | export default BorderBox 226 | -------------------------------------------------------------------------------- /src/components/decoration12/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-12 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | 7 | .decoration-content { 8 | position: absolute; 9 | top: 0px; 10 | left: 0px; 11 | width: 100%; 12 | height: 100%; 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | } 17 | } -------------------------------------------------------------------------------- /src/components/decoration2/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#3faacb', '#fff'] 15 | 16 | const Decoration = forwardRef(({ reverse = false, dur = 6, className, style, color = [] }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | function calcSVGData() { 20 | return reverse 21 | ? { w: 1, h: height, x: width / 2, y: 0 } 22 | : { w: width, h: 1, x: 0, y: height / 2 } 23 | } 24 | 25 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 26 | 27 | const { x, y, w, h } = useMemo(calcSVGData, [reverse, width, height]) 28 | 29 | const classNames = useMemo(() => classnames('dv-decoration-2', className), [ 30 | className 31 | ]) 32 | 33 | return ( 34 |
35 | 36 | 37 | 47 | 48 | 49 | 50 | 60 | 61 | 62 |
63 | ) 64 | }) 65 | 66 | Decoration.propTypes = { 67 | dur: PropTypes.number, 68 | reverse: PropTypes.bool, 69 | className: PropTypes.string, 70 | style: PropTypes.object, 71 | color: PropTypes.array 72 | } 73 | 74 | // 指定 props 的默认值: 75 | Decoration.defaultProps = { 76 | reverse: false, 77 | dur: 6 78 | } 79 | 80 | export default Decoration 81 | -------------------------------------------------------------------------------- /src/components/decoration2/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-2 { 2 | display: flex; 3 | width: 100%; 4 | height: 100%; 5 | justify-content: center; 6 | align-items: center; 7 | } -------------------------------------------------------------------------------- /src/components/decoration3/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['#7acaec', 'transparent'] 15 | 16 | const pointSideLength = 7 17 | 18 | const svgWH = [300, 35] 19 | 20 | const rowNum = 2 21 | 22 | const rowPoints = 25 23 | 24 | const halfPointSideLength = pointSideLength / 2 25 | 26 | function getPoints() { 27 | const [w, h] = svgWH 28 | 29 | const horizontalGap = w / (rowPoints + 1) 30 | const verticalGap = h / (rowNum + 1) 31 | 32 | let points = new Array(rowNum) 33 | .fill(0) 34 | .map((foo, i) => 35 | new Array(rowPoints) 36 | .fill(0) 37 | .map((foo, j) => [horizontalGap * (j + 1), verticalGap * (i + 1)]) 38 | ) 39 | 40 | return points.reduce((all, item) => [...all, ...item], []) 41 | } 42 | 43 | const Decoration = forwardRef(({ className, style, color = [] }, ref) => { 44 | const { width, height, domRef } = useAutoResize(ref) 45 | 46 | function calcSVGData() { 47 | return { 48 | points: getPoints(), 49 | svgScale: [width / svgWH[0], height / svgWH[1]] 50 | } 51 | } 52 | 53 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 54 | 55 | const { svgScale, points } = useMemo(calcSVGData, [width, height]) 56 | 57 | const classNames = useMemo(() => classnames('dv-decoration-3', className), [ 58 | className 59 | ]) 60 | 61 | return ( 62 |
63 | 68 | {points.map((point, i) => ( 69 | 77 | {Math.random() > 0.6 && ( 78 | 85 | )} 86 | 87 | ))} 88 | 89 |
90 | ) 91 | }) 92 | 93 | Decoration.propTypes = { 94 | className: PropTypes.string, 95 | style: PropTypes.object, 96 | color: PropTypes.array 97 | } 98 | 99 | export default Decoration 100 | -------------------------------------------------------------------------------- /src/components/decoration3/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-3 { 2 | width: 100%; 3 | height: 100%; 4 | 5 | svg { 6 | transform-origin: left top; 7 | } 8 | } -------------------------------------------------------------------------------- /src/components/decoration4/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 9 | 10 | import useAutoResize from '../../use/autoResize' 11 | 12 | import './style.less' 13 | 14 | const defaultColor = ['rgba(255, 255, 255, 0.3)', 'rgba(255, 255, 255, 0.3)'] 15 | 16 | const Decoration = forwardRef(({ reverse = false, dur = 3, className, style, color = [] }, ref) => { 17 | const { width, height, domRef } = useAutoResize(ref) 18 | 19 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 20 | 21 | const classNames = useMemo(() => classnames('dv-decoration-4', className), [ 22 | className 23 | ]) 24 | 25 | return ( 26 |
27 |
35 | 36 | 40 | 48 | 49 |
50 |
51 | ) 52 | }) 53 | 54 | Decoration.propTypes = { 55 | dur: PropTypes.number, 56 | reverse: PropTypes.bool, 57 | className: PropTypes.string, 58 | style: PropTypes.object, 59 | color: PropTypes.array 60 | } 61 | 62 | // 指定 props 的默认值: 63 | Decoration.defaultProps = { 64 | reverse: false, 65 | dur: 3 66 | } 67 | 68 | export default Decoration 69 | -------------------------------------------------------------------------------- /src/components/decoration4/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-4 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | 6 | .container { 7 | display: flex; 8 | overflow: hidden; 9 | position: absolute; 10 | flex: 1; 11 | } 12 | 13 | .normal { 14 | animation: ani-height ease-in-out infinite; 15 | left: 50%; 16 | margin-left: -2px; 17 | } 18 | 19 | .reverse { 20 | animation: ani-width ease-in-out infinite; 21 | top: 50%; 22 | margin-top: -2px; 23 | } 24 | 25 | @keyframes ani-height { 26 | 0% { 27 | height: 0%; 28 | } 29 | 30 | 70% { 31 | height: 100%; 32 | } 33 | 34 | 100% { 35 | height: 100%; 36 | } 37 | } 38 | 39 | @keyframes ani-width { 40 | 0% { 41 | width: 0%; 42 | } 43 | 44 | 70% { 45 | width: 100%; 46 | } 47 | 48 | 100% { 49 | width: 100%; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/decoration5/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { getPolylineLength, deepMerge } from '@jiaminghi/charts/lib/util' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import './style.less' 14 | 15 | const defaultColor = ['#3f96a5', '#3f96a5'] 16 | 17 | const Decoration = forwardRef(({ className, dur = 1.2, style, color = [] }, ref) => { 18 | const { width, height, domRef } = useAutoResize(ref) 19 | 20 | function calcSVGData() { 21 | let line1Points = [ 22 | [0, height * 0.2], 23 | [width * 0.18, height * 0.2], 24 | [width * 0.2, height * 0.4], 25 | [width * 0.25, height * 0.4], 26 | [width * 0.27, height * 0.6], 27 | [width * 0.72, height * 0.6], 28 | [width * 0.75, height * 0.4], 29 | [width * 0.8, height * 0.4], 30 | [width * 0.82, height * 0.2], 31 | [width, height * 0.2] 32 | ] 33 | 34 | let line2Points = [[width * 0.3, height * 0.8], [width * 0.7, height * 0.8]] 35 | 36 | const line1Length = getPolylineLength(line1Points) 37 | const line2Length = getPolylineLength(line2Points) 38 | 39 | line1Points = line1Points.map(point => point.join(',')).join(' ') 40 | line2Points = line2Points.map(point => point.join(',')).join(' ') 41 | 42 | return { line1Points, line2Points, line1Length, line2Length } 43 | } 44 | 45 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 46 | 47 | const { line1Points, line2Points, line1Length, line2Length } = useMemo( 48 | calcSVGData, 49 | [width, height] 50 | ) 51 | 52 | const classNames = useMemo(() => classnames('dv-decoration-5', className), [ 53 | className 54 | ]) 55 | 56 | return ( 57 |
58 | 59 | 65 | 77 | 78 | 84 | 96 | 97 | 98 |
99 | ) 100 | }) 101 | 102 | Decoration.propTypes = { 103 | dur: PropTypes.number, 104 | className: PropTypes.string, 105 | style: PropTypes.object, 106 | color: PropTypes.array 107 | } 108 | 109 | export default Decoration 110 | -------------------------------------------------------------------------------- /src/components/decoration5/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-5 { 2 | width: 100%; 3 | height: 100%; 4 | } -------------------------------------------------------------------------------- /src/components/decoration6/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import { randomExtend } from '../../util' 14 | 15 | import './style.less' 16 | 17 | const defaultColor = ['#7acaec', '#7acaec'] 18 | 19 | const svgWH = [300, 35] 20 | 21 | const rowNum = 1 22 | const rowPoints = 40 23 | 24 | const rectWidth = 7 25 | const halfRectWidth = rectWidth / 2 26 | 27 | function getPoints() { 28 | const [w, h] = svgWH 29 | 30 | const horizontalGap = w / (rowPoints + 1) 31 | const verticalGap = h / (rowNum + 1) 32 | 33 | let points = new Array(rowNum) 34 | .fill(0) 35 | .map((foo, i) => 36 | new Array(rowPoints) 37 | .fill(0) 38 | .map((foo, j) => [horizontalGap * (j + 1), verticalGap * (i + 1)]) 39 | ) 40 | 41 | return points.reduce((all, item) => [...all, ...item], []) 42 | } 43 | 44 | function getData() { 45 | const [, h] = svgWH 46 | 47 | const heights = new Array(rowNum * rowPoints) 48 | .fill(0) 49 | .map(foo => 50 | Math.random() > 0.8 51 | ? randomExtend(0.7 * h, h) 52 | : randomExtend(0.2 * h, 0.5 * h) 53 | ) 54 | 55 | const minHeights = new Array(rowNum * rowPoints) 56 | .fill(0) 57 | .map((foo, i) => heights[i] * Math.random()) 58 | 59 | const randoms = new Array(rowNum * rowPoints) 60 | .fill(0) 61 | .map(foo => Math.random() + 1.5) 62 | 63 | return { heights, minHeights, randoms } 64 | } 65 | 66 | const Decoration = forwardRef(({ className, style, color = [] }, ref) => { 67 | const { width, height, domRef } = useAutoResize(ref) 68 | 69 | function calcSVGData() { 70 | return { 71 | ...getData(), 72 | points: getPoints(), 73 | svgScale: [width / svgWH[0], height / svgWH[1]] 74 | } 75 | } 76 | 77 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 78 | 79 | const { points, heights, minHeights, randoms, svgScale } = useMemo( 80 | calcSVGData, 81 | [width, height] 82 | ) 83 | 84 | const classNames = useMemo(() => classnames('dv-decoration-6', className), [ 85 | [className] 86 | ]) 87 | 88 | return ( 89 |
90 | 95 | {points.map((point, i) => ( 96 | 0.5 ? 0 : 1]} 99 | x={point[0] - halfRectWidth} 100 | y={point[1] - heights[i] / 2} 101 | width={rectWidth} 102 | height={heights[i]} 103 | > 104 | 115 | 125 | 126 | ))} 127 | 128 |
129 | ) 130 | }) 131 | 132 | Decoration.propTypes = { 133 | className: PropTypes.string, 134 | style: PropTypes.object, 135 | color: PropTypes.array 136 | } 137 | 138 | export default Decoration 139 | -------------------------------------------------------------------------------- /src/components/decoration6/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-6 { 2 | width: 100%; 3 | height: 100%; 4 | 5 | svg { 6 | transform-origin: left top; 7 | } 8 | } -------------------------------------------------------------------------------- /src/components/decoration7/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import './style.less' 12 | 13 | const defaultColor = ['#1dc1f5', '#1dc1f5'] 14 | 15 | const Decoration = ({ children, className, style, color = [] }) => { 16 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 17 | 18 | const classNames = useMemo(() => classnames('dv-decoration-7', className), [ 19 | className 20 | ]) 21 | 22 | return ( 23 |
24 | 25 | 31 | 37 | 38 | {children} 39 | 40 | 46 | 52 | 53 |
54 | ) 55 | } 56 | 57 | Decoration.propTypes = { 58 | children: PropTypes.node, 59 | className: PropTypes.string, 60 | style: PropTypes.object, 61 | color: PropTypes.array 62 | } 63 | 64 | export default Decoration 65 | -------------------------------------------------------------------------------- /src/components/decoration7/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-7 { 2 | display: flex; 3 | width: 100%; 4 | height: 100%; 5 | justify-content: center; 6 | align-items: center; 7 | } -------------------------------------------------------------------------------- /src/components/decoration8/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import './style.less' 14 | 15 | const defaultColor = ['#3f96a5', '#3f96a5'] 16 | 17 | const Decoration = forwardRef(({ reverse = false, className, style, color = [] }, ref) => { 18 | const { width, height, domRef } = useAutoResize(ref) 19 | 20 | const xPos = pos => (!reverse ? pos : width - pos) 21 | 22 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 23 | 24 | const [pointsOne, pointsTwo, pointsThree] = useMemo( 25 | () => [ 26 | `${xPos(0)}, 0 ${xPos(30)}, ${height / 2}`, 27 | `${xPos(20)}, 0 ${xPos(50)}, ${height / 2} ${xPos(width)}, ${height / 2}`, 28 | `${xPos(0)}, ${height - 3}, ${xPos(200)}, ${height - 3}` 29 | ], 30 | [reverse, width, height] 31 | ) 32 | 33 | const classNames = useMemo(() => classnames('dv-decoration-8', className), [ 34 | className 35 | ]) 36 | 37 | return ( 38 |
39 | 40 | 46 | 47 | 53 | 54 | 60 | 61 |
62 | ) 63 | }) 64 | 65 | Decoration.propTypes = { 66 | reverse: PropTypes.bool, 67 | className: PropTypes.string, 68 | style: PropTypes.object, 69 | color: PropTypes.array 70 | } 71 | 72 | // 指定 props 的默认值: 73 | Decoration.defaultProps = { 74 | reverse: false 75 | } 76 | 77 | export default Decoration 78 | -------------------------------------------------------------------------------- /src/components/decoration8/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-8 { 2 | display: flex; 3 | width: 100%; 4 | height: 100%; 5 | } -------------------------------------------------------------------------------- /src/components/decoration9/index.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { fade } from '@jiaminghi/color' 8 | 9 | import { deepMerge } from '@jiaminghi/charts/lib/util' 10 | 11 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 12 | 13 | import useAutoResize from '../../use/autoResize' 14 | 15 | import { uuid } from '../../util' 16 | 17 | import './style.less' 18 | 19 | const defaultColor = ['rgba(3, 166, 224, 0.8)', 'rgba(3, 166, 224, 0.5)'] 20 | 21 | const svgWH = [100, 100] 22 | 23 | const Decoration = forwardRef(({ children, className, style, color = [], dur = 3 }, ref) => { 24 | const { width, height, domRef } = useAutoResize(ref) 25 | 26 | const polygonIdRef = useRef(`decoration-9-polygon-${uuid()}`) 27 | 28 | const mergedColor = useMemo(() => deepMerge(deepClone(defaultColor, true), color || []), [color]) 29 | 30 | const svgScale = useMemo(() => { 31 | const [w, h] = svgWH 32 | 33 | return [width / w, height / h] 34 | }, [width, height]) 35 | 36 | const classNames = useMemo(() => classnames('dv-decoration-9', className), [ 37 | className 38 | ]) 39 | 40 | return ( 41 |
42 | 47 | 48 | 52 | 53 | 54 | 63 | 70 | 71 | 72 | 81 | 88 | 89 | 90 | 99 | {new Array(20).fill(0).map((foo, i) => ( 100 | 0.4 ? 'transparent' : mergedColor[0] 106 | } 107 | > 108 | 116 | 117 | ))} 118 | 119 | 128 | 129 | 130 | {children} 131 |
132 | ) 133 | }) 134 | 135 | Decoration.propTypes = { 136 | children: PropTypes.node, 137 | className: PropTypes.string, 138 | style: PropTypes.object, 139 | color: PropTypes.array, 140 | dur: PropTypes.number 141 | } 142 | 143 | export default Decoration 144 | -------------------------------------------------------------------------------- /src/components/decoration9/style.less: -------------------------------------------------------------------------------- 1 | .dv-decoration-9 { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | 9 | svg { 10 | position: absolute; 11 | left: 0px; 12 | top: 0px; 13 | transform-origin: left top; 14 | } 15 | } -------------------------------------------------------------------------------- /src/components/digitalFlop/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import CRender from '@jiaminghi/c-render' 8 | 9 | import '@jiaminghi/charts/lib/extend/index' 10 | 11 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 12 | 13 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 14 | 15 | import './style.less' 16 | 17 | const defaultConfig = { 18 | /** 19 | * @description Number for digital flop 20 | * @type {Array} 21 | * @default number = [] 22 | * @example number = [10] 23 | */ 24 | number: [], 25 | /** 26 | * @description Content formatter 27 | * @type {String} 28 | * @default content = '' 29 | * @example content = '{nt}个' 30 | */ 31 | content: '', 32 | /** 33 | * @description Number toFixed 34 | * @type {Number} 35 | * @default toFixed = 0 36 | */ 37 | toFixed: 0, 38 | /** 39 | * @description Text align 40 | * @type {String} 41 | * @default textAlign = 'center' 42 | * @example textAlign = 'center' | 'left' | 'right' 43 | */ 44 | textAlign: 'center', 45 | /** 46 | * @description rowGap 47 | * @type {Number} 48 | *@default rowGap = 0 49 | */ 50 | rowGap: 0, 51 | /** 52 | * @description Text style configuration 53 | * @type {Object} {CRender Class Style} 54 | */ 55 | style: { 56 | fontSize: 30, 57 | fill: '#3de7c9' 58 | }, 59 | /** 60 | * @description Number formatter 61 | * @type {Null|Function} 62 | */ 63 | formatter: undefined, 64 | /** 65 | * @description CRender animationCurve 66 | * @type {String} 67 | * @default animationCurve = 'easeOutCubic' 68 | */ 69 | animationCurve: 'easeOutCubic', 70 | /** 71 | * @description CRender animationFrame 72 | * @type {String} 73 | * @default animationFrame = 50 74 | */ 75 | animationFrame: 50 76 | } 77 | 78 | const DigitalFlop = ({ config = {}, className, style }) => { 79 | const domRef = useRef(null) 80 | const rendererRef = useRef(null) 81 | const graphRef = useRef(null) 82 | 83 | function getGraph(mergedConfig) { 84 | const { animationCurve, animationFrame } = mergedConfig 85 | 86 | return rendererRef.current.add({ 87 | name: 'numberText', 88 | animationCurve, 89 | animationFrame, 90 | shape: getShape(mergedConfig), 91 | style: getStyle(mergedConfig) 92 | }) 93 | } 94 | 95 | function getShape({ number, content, toFixed, textAlign, rowGap, formatter }) { 96 | const [w, h] = rendererRef.current.area 97 | 98 | const position = [w / 2, h / 2] 99 | 100 | if (textAlign === 'left') position[0] = 0 101 | if (textAlign === 'right') position[0] = w 102 | 103 | return { number, content, toFixed, position, rowGap, formatter } 104 | } 105 | 106 | function getStyle({ style, textAlign }) { 107 | return deepMerge(style, { 108 | textAlign, 109 | textBaseline: 'middle' 110 | }) 111 | } 112 | 113 | useEffect(() => { 114 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 115 | 116 | if (!rendererRef.current) { 117 | rendererRef.current = new CRender(domRef.current) 118 | 119 | graphRef.current = getGraph(mergedConfig) 120 | } 121 | 122 | const graph = graphRef.current 123 | graph.animationEnd() 124 | 125 | const shape = getShape(mergedConfig) 126 | 127 | const cacheNum = graph.shape.number.length 128 | const shapeNum = shape.number.length 129 | 130 | cacheNum !== shapeNum && (graph.shape.number = shape.number) 131 | 132 | const { animationCurve, animationFrame } = mergedConfig 133 | 134 | Object.assign(graph, { animationCurve, animationFrame }) 135 | 136 | graph.animation('style', getStyle(mergedConfig), true) 137 | graph.animation('shape', shape) 138 | }, [config]) 139 | 140 | const classNames = useMemo(() => classnames('dv-digital-flop', className), [ 141 | className 142 | ]) 143 | 144 | return ( 145 |
146 | 147 |
148 | ) 149 | } 150 | 151 | DigitalFlop.propTypes = { 152 | config: PropTypes.object, 153 | className: PropTypes.string, 154 | style: PropTypes.object 155 | } 156 | 157 | export default DigitalFlop 158 | -------------------------------------------------------------------------------- /src/components/digitalFlop/style.less: -------------------------------------------------------------------------------- 1 | .dv-digital-flop { 2 | canvas { 3 | width: 100%; 4 | height: 100%; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/components/flylineChart/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useRef, useCallback, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | 13 | import { randomExtend, getPointDistance, uuid } from '../../util' 14 | 15 | import './style.less' 16 | 17 | const defaultConfig = { 18 | /** 19 | * @description Flyline chart center point 20 | * @type {Array} 21 | * @default centerPoint = [0, 0] 22 | */ 23 | centerPoint: [0, 0], 24 | /** 25 | * @description Flyline start points 26 | * @type {Array>} 27 | * @default points = [] 28 | * @example points = [[10, 10], [100, 100]] 29 | */ 30 | points: [], 31 | /** 32 | * @description Flyline width 33 | * @type {Number} 34 | * @default lineWidth = 1 35 | */ 36 | lineWidth: 1, 37 | /** 38 | * @description Orbit color 39 | * @type {String} 40 | * @default orbitColor = 'rgba(103, 224, 227, .2)' 41 | */ 42 | orbitColor: 'rgba(103, 224, 227, .2)', 43 | /** 44 | * @description Flyline color 45 | * @type {String} 46 | * @default orbitColor = '#ffde93' 47 | */ 48 | flylineColor: '#ffde93', 49 | /** 50 | * @description K value 51 | * @type {Number} 52 | * @default k = -0.5 53 | * @example k = -1 ~ 1 54 | */ 55 | k: -0.5, 56 | /** 57 | * @description Flyline curvature 58 | * @type {Number} 59 | * @default curvature = 5 60 | */ 61 | curvature: 5, 62 | /** 63 | * @description Flyline radius 64 | * @type {Number} 65 | * @default flylineRadius = 100 66 | */ 67 | flylineRadius: 100, 68 | /** 69 | * @description Flyline animation duration 70 | * @type {Array} 71 | * @default duration = [20, 30] 72 | */ 73 | duration: [20, 30], 74 | /** 75 | * @description Relative points position 76 | * @type {Boolean} 77 | * @default relative = true 78 | */ 79 | relative: true, 80 | /** 81 | * @description Back ground image url 82 | * @type {String} 83 | * @default bgImgUrl = '' 84 | * @example bgImgUrl = './img/bg.jpg' 85 | */ 86 | bgImgUrl: '', 87 | /** 88 | * @description Text configuration 89 | * @type {Object} 90 | */ 91 | text: { 92 | /** 93 | * @description Text offset 94 | * @type {Array} 95 | * @default offset = [0, 15] 96 | */ 97 | offset: [0, 15], 98 | /** 99 | * @description Text color 100 | * @type {String} 101 | * @default color = '#ffdb5c' 102 | */ 103 | color: '#ffdb5c', 104 | /** 105 | * @description Text font size 106 | * @type {Number} 107 | * @default fontSize = 12 108 | */ 109 | fontSize: 12 110 | }, 111 | /** 112 | * @description Halo configuration 113 | * @type {Object} 114 | */ 115 | halo: { 116 | /** 117 | * @description Weather to show halo 118 | * @type {Boolean} 119 | * @default show = true 120 | * @example show = true | false 121 | */ 122 | show: true, 123 | /** 124 | * @description Halo animation duration (10 = 1s) 125 | * @type {Number} 126 | * @default duration = 30 127 | */ 128 | duration: 30, 129 | /** 130 | * @description Halo color 131 | * @type {String} 132 | * @default color = '#fb7293' 133 | */ 134 | color: '#fb7293', 135 | /** 136 | * @description Halo max radius 137 | * @type {Number} 138 | * @default radius = 120 139 | */ 140 | radius: 120 141 | }, 142 | /** 143 | * @description Center point img configuration 144 | * @type {Object} 145 | */ 146 | centerPointImg: { 147 | /** 148 | * @description Center point img width 149 | * @type {Number} 150 | * @default width = 40 151 | */ 152 | width: 40, 153 | /** 154 | * @description Center point img height 155 | * @type {Number} 156 | * @default height = 40 157 | */ 158 | height: 40, 159 | /** 160 | * @description Center point img url 161 | * @type {String} 162 | * @default url = '' 163 | */ 164 | url: '' 165 | }, 166 | /** 167 | * @description Points img configuration 168 | * @type {Object} 169 | * @default radius = 120 170 | */ 171 | pointsImg: { 172 | /** 173 | * @description Points img width 174 | * @type {Number} 175 | * @default width = 15 176 | */ 177 | width: 15, 178 | /** 179 | * @description Points img height 180 | * @type {Number} 181 | * @default height = 15 182 | */ 183 | height: 15, 184 | /** 185 | * @description Points img url 186 | * @type {String} 187 | * @default url = '' 188 | */ 189 | url: '' 190 | } 191 | } 192 | 193 | function getControlPoint([sx, sy], [ex, ey], { curvature, k }) { 194 | const [mx, my] = [(sx + ex) / 2, (sy + ey) / 2] 195 | 196 | const distance = getPointDistance([sx, sy], [ex, ey]) 197 | 198 | const targetLength = distance / curvature 199 | const disDived = targetLength / 2 200 | 201 | let [dx, dy] = [mx, my] 202 | 203 | do { 204 | dx += disDived 205 | dy = my - k * mx + k * dx 206 | } while (getPointDistance([mx, my], [dx, dy]) < targetLength) 207 | 208 | return [dx, dy] 209 | } 210 | 211 | const FlyLineChart = forwardRef(({ config = {}, dev = false, className, style }, ref) => { 212 | const { width, height, domRef } = useAutoResize(ref) 213 | 214 | const { unique, gradientId, gradient2Id } = useRef({ 215 | unique: Math.random(), 216 | gradientId: `gradient-id-${uuid()}`, 217 | gradient2Id: `gradient2-id-${uuid()}` 218 | }).current 219 | 220 | const { mergedConfig, paths, times, texts } = useMemo(calcData, [ 221 | config, 222 | width, 223 | height 224 | ]) 225 | 226 | const [lengths, setLengths] = useState([]) 227 | 228 | const pathDomRef = useRef([]) 229 | 230 | function calcData() { 231 | const mergedConfig = getMergedConfig() 232 | 233 | const paths = createFlylinePaths(mergedConfig) 234 | 235 | const { duration, points } = mergedConfig 236 | 237 | const times = points.map(foo => randomExtend(...duration) / 10) 238 | 239 | const texts = points.map(({ text }) => text) 240 | 241 | return { mergedConfig, paths, times, texts } 242 | } 243 | 244 | function getMergedConfig() { 245 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 246 | 247 | mergedConfig.points = mergedConfig.points.map(item => { 248 | if (Array.isArray(item)) { 249 | return { position: item, text: '' } 250 | } 251 | 252 | return item 253 | }) 254 | 255 | return mergedConfig 256 | } 257 | 258 | function createFlylinePaths(mergedConfig) { 259 | let { centerPoint, relative } = mergedConfig 260 | let points = mergedConfig.points.map(({ position }) => position) 261 | 262 | if (relative) { 263 | centerPoint = [width * centerPoint[0], height * centerPoint[1]] 264 | points = points.map(([x, y]) => [width * x, height * y]) 265 | } 266 | 267 | return points.map(point => { 268 | const controlPoint = getControlPoint(centerPoint, point, mergedConfig) 269 | 270 | return [point, controlPoint, centerPoint] 271 | }) 272 | } 273 | 274 | const consoleClickPos = useCallback( 275 | ({ offsetX, offsetY }) => { 276 | if (!dev) return 277 | 278 | const relativeX = (offsetX / width).toFixed(2) 279 | const relativeY = (offsetY / height).toFixed(2) 280 | 281 | console.warn( 282 | `dv-flyline-chart DEV: \n Click Position is [${offsetX}, ${offsetY}] \n Relative Position is [${relativeX}, ${relativeY}]` 283 | ) 284 | }, 285 | [width, height, dev] 286 | ) 287 | 288 | useEffect(() => { 289 | const lengths = paths.map((foo, i) => 290 | pathDomRef.current[i].getTotalLength() 291 | ) 292 | 293 | setLengths(lengths) 294 | }, [paths]) 295 | 296 | const classNames = useMemo(() => classnames('dv-flyline-chart', className), [ 297 | className 298 | ]) 299 | 300 | return ( 301 |
310 | {!!mergedConfig && ( 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | {!!paths[0] && ( 324 | 329 | 335 | 341 | 342 | )} 343 | 344 | 345 | {!!paths[0] && ( 346 | 353 | )} 354 | 355 | 356 | {!!paths[0] && ( 357 | 361 | )} 362 | 363 | 364 | {!!paths[0] && mergedConfig.halo.show && ( 365 | 370 | )} 371 | 372 | {paths.map((path, i) => ( 373 | 374 | 375 | (pathDomRef.current[i] = e)} 378 | d={`M${path[0].toString()} Q${path[1].toString()} ${path[2].toString()}`} 379 | fill='transparent' 380 | /> 381 | 382 | 383 | 388 | 389 | {lengths[i] && ( 390 | 396 | 403 | 404 | )} 405 | 406 | 407 | 413 | 419 | 420 | 421 | 422 | 429 | 430 | 436 | {texts[i]} 437 | 438 | 439 | ))} 440 | 441 | )} 442 |
443 | ) 444 | }) 445 | 446 | FlyLineChart.propTypes = { 447 | config: PropTypes.object, 448 | dev: PropTypes.bool, 449 | className: PropTypes.string, 450 | style: PropTypes.object 451 | } 452 | 453 | // 指定 props 的默认值: 454 | FlyLineChart.defaultProps = { 455 | dev: false 456 | } 457 | 458 | export default FlyLineChart 459 | -------------------------------------------------------------------------------- /src/components/flylineChart/style.less: -------------------------------------------------------------------------------- 1 | .dv-flyline-chart { 2 | display: flex; 3 | flex-direction: column; 4 | background-size: 100% 100%; 5 | 6 | polyline { 7 | transition: all 0.3s; 8 | } 9 | 10 | text { 11 | text-anchor: middle; 12 | dominant-baseline: middle; 13 | } 14 | } -------------------------------------------------------------------------------- /src/components/flylineChartEnhanced/style.less: -------------------------------------------------------------------------------- 1 | .dv-flyline-chart-enhanced { 2 | display: flex; 3 | flex-direction: column; 4 | background-size: 100% 100%; 5 | 6 | text { 7 | text-anchor: middle; 8 | dominant-baseline: middle; 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/fullScreenContainer/index.js: -------------------------------------------------------------------------------- 1 | import React, { useLayoutEffect, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import useAutoResize from '../../use/autoResize' 6 | 7 | import './style.less' 8 | 9 | const FullScreenContainer = forwardRef(({ children, className, style }, ref) => { 10 | const { domRef } = useAutoResize(ref) 11 | 12 | useLayoutEffect(() => { 13 | const { width, height } = window.screen 14 | 15 | Object.assign(domRef.current.style, { 16 | width: `${width}px`, 17 | height: `${height}px` 18 | }) 19 | 20 | domRef.current.style.transform = `scale(${document.body.clientWidth / 21 | width})` 22 | }) 23 | 24 | return ( 25 |
31 | {children} 32 |
33 | ) 34 | }) 35 | 36 | FullScreenContainer.propTypes = { 37 | children: PropTypes.node, 38 | className: PropTypes.string, 39 | style: PropTypes.object 40 | } 41 | 42 | export default FullScreenContainer 43 | -------------------------------------------------------------------------------- /src/components/fullScreenContainer/style.less: -------------------------------------------------------------------------------- 1 | #dv-full-screen-container { 2 | position: fixed; 3 | top: 0px; 4 | left: 0px; 5 | overflow: hidden; 6 | transform-origin: left top; 7 | z-index: 999; 8 | } -------------------------------------------------------------------------------- /src/components/loading/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import './style.less' 8 | 9 | const Loading = ({ children, className, style }) => { 10 | const classNames = useMemo(() => classnames('dv-loading', className), [ 11 | className 12 | ]) 13 | 14 | return ( 15 |
16 | 17 | 27 | 34 | 40 | 41 | 42 | 52 | 59 | 65 | 66 | 67 |
{children}
68 |
69 | ) 70 | } 71 | 72 | Loading.propTypes = { 73 | children: PropTypes.node, 74 | className: PropTypes.string, 75 | style: PropTypes.object 76 | } 77 | 78 | export default Loading 79 | -------------------------------------------------------------------------------- /src/components/loading/style.less: -------------------------------------------------------------------------------- 1 | .dv-loading { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | 9 | .loading-tip { 10 | font-size: 15px; 11 | } 12 | } -------------------------------------------------------------------------------- /src/components/percentPond/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useRef, useMemo } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import { uuid } from '../../util' 12 | 13 | import './style.less' 14 | 15 | const defaultConfig = { 16 | /** 17 | * @description Value 18 | * @type {Number} 19 | * @default value = 0 20 | */ 21 | value: 0, 22 | /** 23 | * @description Colors (hex|rgb|rgba|color keywords) 24 | * @type {Array} 25 | * @default colors = ['#00BAFF', '#3DE7C9'] 26 | * @example colors = ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red'] 27 | */ 28 | colors: ['#3DE7C9', '#00BAFF'], 29 | /** 30 | * @description Border width 31 | * @type {Number} 32 | * @default borderWidth = 3 33 | */ 34 | borderWidth: 3, 35 | /** 36 | * @description Gap between border and pond 37 | * @type {Number} 38 | * @default borderGap = 3 39 | */ 40 | borderGap: 3, 41 | /** 42 | * @description Line dash 43 | * @type {Array} 44 | * @default lineDash = [5, 1] 45 | */ 46 | lineDash: [5, 1], 47 | /** 48 | * @description Text color 49 | * @type {String} 50 | * @default textColor = '#fff' 51 | */ 52 | textColor: '#fff', 53 | /** 54 | * @description Border radius 55 | * @type {Number} 56 | * @default borderRadius = 5 57 | */ 58 | borderRadius: 5, 59 | /** 60 | * @description Local Gradient 61 | * @type {Boolean} 62 | * @default localGradient = false 63 | * @example localGradient = false | true 64 | */ 65 | localGradient: false, 66 | /** 67 | * @description Formatter 68 | * @type {String} 69 | * @default formatter = '{value}%' 70 | */ 71 | formatter: '{value}%' 72 | } 73 | 74 | const PercentPond = ({ config = {}, className, style }) => { 75 | const domRef = useRef(null) 76 | 77 | const { gradientId1, gradientId2 } = useRef({ 78 | gradientId1: `percent-pond-gradientId1-${uuid()}`, 79 | gradientId2: `percent-pond-gradientId2-${uuid()}` 80 | }).current 81 | 82 | const [{ width, height, mergedConfig }, setState] = useState({ 83 | width: 0, 84 | height: 0, 85 | 86 | mergedConfig: null 87 | }) 88 | 89 | const rectWidth = useMemo(() => { 90 | if (!mergedConfig) return 0 91 | 92 | const { borderWidth } = mergedConfig 93 | 94 | return width - borderWidth 95 | }, [mergedConfig, width]) 96 | 97 | const rectHeight = useMemo(() => { 98 | if (!mergedConfig) return 0 99 | 100 | const { borderWidth } = mergedConfig 101 | 102 | return height - borderWidth 103 | }, [mergedConfig, height]) 104 | 105 | const points = useMemo(() => { 106 | const halfHeight = height / 2 107 | 108 | if (!mergedConfig) return `0, ${halfHeight} 0, ${halfHeight}` 109 | 110 | const { borderWidth, borderGap, value } = mergedConfig 111 | 112 | const polylineLength = 113 | ((width - (borderWidth + borderGap) * 2) / 100) * value 114 | 115 | return ` 116 | ${borderWidth + borderGap}, ${halfHeight} 117 | ${borderWidth + borderGap + polylineLength}, ${halfHeight + 0.001} 118 | ` 119 | }, [mergedConfig, width, height]) 120 | 121 | const polylineWidth = useMemo(() => { 122 | if (!mergedConfig) return 0 123 | 124 | const { borderWidth, borderGap } = mergedConfig 125 | 126 | return height - (borderWidth + borderGap) * 2 127 | }, [mergedConfig, height]) 128 | 129 | const linearGradient = useMemo(() => { 130 | if (!mergedConfig) return [] 131 | 132 | const { colors } = mergedConfig 133 | 134 | const colorNum = colors.length 135 | 136 | const colorOffsetGap = 100 / (colorNum - 1) 137 | 138 | return colors.map((c, i) => [colorOffsetGap * i, c]) 139 | }, [mergedConfig]) 140 | 141 | const polylineGradient = useMemo(() => { 142 | if (!mergedConfig) return gradientId2 143 | 144 | if (mergedConfig.localGradient) return gradientId1 145 | 146 | return gradientId2 147 | }, [gradientId1, gradientId2, mergedConfig]) 148 | 149 | const gradient2XPos = useMemo(() => { 150 | if (!mergedConfig) return '100%' 151 | 152 | const { value } = mergedConfig 153 | 154 | return `${200 - value}%` 155 | }, [mergedConfig]) 156 | 157 | const details = useMemo(() => { 158 | if (!mergedConfig) return '' 159 | 160 | const { value, formatter } = mergedConfig 161 | 162 | return formatter.replace('{value}', value) 163 | }, [mergedConfig]) 164 | 165 | useEffect(() => { 166 | const { clientWidth: width, clientHeight: height } = domRef.current 167 | 168 | setState({ 169 | width, 170 | height, 171 | mergedConfig: deepMerge(deepClone(defaultConfig, true), config || {}) 172 | }) 173 | }, [config]) 174 | 175 | const classNames = useMemo(() => classnames('dv-percent-pond', className), [ 176 | className 177 | ]) 178 | 179 | return ( 180 |
181 | 182 | 183 | 184 | {linearGradient.map(lc => ( 185 | 186 | ))} 187 | 188 | 189 | 196 | {linearGradient.map(lc => ( 197 | 198 | ))} 199 | 200 | 201 | 0 ? rectWidth : 0} 210 | height={rectHeight > 0 ? rectHeight : 0} 211 | /> 212 | 218 | 224 | {details} 225 | 226 | 227 |
228 | ) 229 | } 230 | 231 | PercentPond.propTypes = { 232 | config: PropTypes.object, 233 | className: PropTypes.string, 234 | style: PropTypes.object 235 | } 236 | 237 | export default PercentPond 238 | -------------------------------------------------------------------------------- /src/components/percentPond/style.less: -------------------------------------------------------------------------------- 1 | .dv-percent-pond { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | 6 | svg { 7 | position: absolute; 8 | left: 0px; 9 | top: 0px; 10 | width: 100%; 11 | height: 100%; 12 | } 13 | 14 | polyline { 15 | transition: all 0.3s; 16 | } 17 | 18 | text { 19 | font-size: 25px; 20 | font-weight: bold; 21 | text-anchor: middle; 22 | dominant-baseline: middle; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/scrollBoard/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useRef, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | import { co } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultConfig = { 17 | /** 18 | * @description Board header 19 | * @type {Array} 20 | * @default header = [] 21 | * @example header = ['column1', 'column2', 'column3'] 22 | */ 23 | header: [], 24 | /** 25 | * @description Board data 26 | * @type {Array} 27 | * @default data = [] 28 | */ 29 | data: [], 30 | /** 31 | * @description Row num 32 | * @type {Number} 33 | * @default rowNum = 5 34 | */ 35 | rowNum: 5, 36 | /** 37 | * @description Header background color 38 | * @type {String} 39 | * @default headerBGC = '#00BAFF' 40 | */ 41 | headerBGC: '#00BAFF', 42 | /** 43 | * @description Odd row background color 44 | * @type {String} 45 | * @default oddRowBGC = '#003B51' 46 | */ 47 | oddRowBGC: '#003B51', 48 | /** 49 | * @description Even row background color 50 | * @type {String} 51 | * @default evenRowBGC = '#003B51' 52 | */ 53 | evenRowBGC: '#0A2732', 54 | /** 55 | * @description Scroll wait time 56 | * @type {Number} 57 | * @default waitTime = 2000 58 | */ 59 | waitTime: 2000, 60 | /** 61 | * @description Header height 62 | * @type {Number} 63 | * @default headerHeight = 35 64 | */ 65 | headerHeight: 35, 66 | /** 67 | * @description Column width 68 | * @type {Array} 69 | * @default columnWidth = [] 70 | */ 71 | columnWidth: [], 72 | /** 73 | * @description Column align 74 | * @type {Array} 75 | * @default align = [] 76 | * @example align = ['left', 'center', 'right'] 77 | */ 78 | align: [], 79 | /** 80 | * @description Show index 81 | * @type {Boolean} 82 | * @default index = false 83 | */ 84 | index: false, 85 | /** 86 | * @description index Header 87 | * @type {String} 88 | * @default indexHeader = '#' 89 | */ 90 | indexHeader: '#', 91 | /** 92 | * @description Carousel type 93 | * @type {String} 94 | * @default carousel = 'single' 95 | * @example carousel = 'single' | 'page' 96 | */ 97 | carousel: 'single', 98 | /** 99 | * @description Pause scroll when mouse hovered 100 | * @type {Boolean} 101 | * @default hoverPause = true 102 | * @example hoverPause = true | false 103 | */ 104 | hoverPause: true 105 | } 106 | 107 | function calcHeaderData({ header, index, indexHeader }) { 108 | if (!header.length) { 109 | return [] 110 | } 111 | 112 | header = [...header] 113 | 114 | if (index) header.unshift(indexHeader) 115 | 116 | return header 117 | } 118 | 119 | function calcRows({ data, index, headerBGC, rowNum }) { 120 | if (index) { 121 | data = data.map((row, i) => { 122 | row = [...row] 123 | 124 | const indexTag = `${i + 125 | 1}` 126 | 127 | row.unshift(indexTag) 128 | 129 | return row 130 | }) 131 | } 132 | 133 | data = data.map((ceils, i) => ({ ceils, rowIndex: i })) 134 | 135 | const rowLength = data.length 136 | 137 | if (rowLength > rowNum && rowLength < 2 * rowNum) { 138 | data = [...data, ...data] 139 | } 140 | 141 | return data.map((d, i) => ({ ...d, scroll: i })) 142 | } 143 | 144 | function calcAligns(mergedConfig, header) { 145 | const columnNum = header.length 146 | 147 | let aligns = new Array(columnNum).fill('left') 148 | 149 | const { align } = mergedConfig 150 | 151 | return deepMerge(aligns, align) 152 | } 153 | 154 | const ScrollBoard = forwardRef(({ onClick, config = {}, className, style, onMouseOver }, ref) => { 155 | const { width, height, domRef } = useAutoResize(ref) 156 | 157 | const [state, setState] = useState({ 158 | mergedConfig: null, 159 | 160 | header: [], 161 | 162 | rows: [], 163 | 164 | widths: [], 165 | 166 | heights: [], 167 | 168 | aligns: [] 169 | }) 170 | 171 | const { mergedConfig, header, rows, widths, heights, aligns } = state 172 | 173 | const stateRef = useRef({ 174 | ...state, 175 | rowsData: [], 176 | avgHeight: 0, 177 | animationIndex: 0 178 | }) 179 | 180 | Object.assign(stateRef.current, state) 181 | 182 | function onResize() { 183 | if (!mergedConfig) return 184 | 185 | const widths = calcWidths(mergedConfig, stateRef.current.rowsData) 186 | 187 | const heights = calcHeights(mergedConfig, header) 188 | 189 | const data = { widths, heights } 190 | 191 | Object.assign(stateRef.current, data) 192 | setState(state => ({ ...state, ...data })) 193 | } 194 | 195 | function calcData() { 196 | const mergedConfig = deepMerge( 197 | deepClone(defaultConfig, true), 198 | config || {} 199 | ) 200 | 201 | const header = calcHeaderData(mergedConfig) 202 | 203 | const rows = calcRows(mergedConfig) 204 | 205 | const widths = calcWidths(mergedConfig, stateRef.current.rowsData) 206 | 207 | const heights = calcHeights(mergedConfig, header) 208 | 209 | const aligns = calcAligns(mergedConfig, header) 210 | 211 | const data = { 212 | mergedConfig, 213 | header, 214 | rows, 215 | widths, 216 | aligns, 217 | heights 218 | } 219 | 220 | Object.assign(stateRef.current, data, { 221 | rowsData: rows, 222 | animationIndex: 0 223 | }) 224 | 225 | setState(state => ({ ...state, ...data })) 226 | } 227 | 228 | function calcWidths({ columnWidth, header }, rowsData) { 229 | const usedWidth = columnWidth.reduce((all, w) => all + w, 0) 230 | 231 | let columnNum = 0 232 | if (rowsData[0]) { 233 | columnNum = rowsData[0].ceils.length 234 | } else if (header.length) { 235 | columnNum = header.length 236 | } 237 | 238 | const avgWidth = (width - usedWidth) / (columnNum - columnWidth.length) 239 | 240 | const widths = new Array(columnNum).fill(avgWidth) 241 | 242 | return deepMerge(widths, columnWidth) 243 | } 244 | 245 | function calcHeights({ headerHeight, rowNum, data }, header) { 246 | let allHeight = height 247 | 248 | if (header.length) allHeight -= headerHeight 249 | 250 | const avgHeight = allHeight / rowNum 251 | 252 | Object.assign(stateRef.current, { avgHeight }) 253 | 254 | return new Array(data.length).fill(avgHeight) 255 | } 256 | 257 | function * animation(start = false) { 258 | let { 259 | avgHeight, 260 | animationIndex, 261 | mergedConfig: { waitTime, carousel, rowNum }, 262 | rowsData 263 | } = stateRef.current 264 | 265 | const rowLength = rowsData.length 266 | 267 | if (start) yield new Promise(resolve => setTimeout(resolve, waitTime)) 268 | 269 | const animationNum = carousel === 'single' ? 1 : rowNum 270 | 271 | let rows = rowsData.slice(animationIndex) 272 | rows.push(...rowsData.slice(0, animationIndex)) 273 | rows = rows.slice(0, carousel === 'page' ? rowNum * 2 : rowNum + 1) 274 | 275 | const heights = new Array(rowLength).fill(avgHeight) 276 | setState(state => ({ ...state, rows, heights })) 277 | 278 | yield new Promise(resolve => setTimeout(resolve, 300)) 279 | 280 | animationIndex += animationNum 281 | 282 | const back = animationIndex - rowLength 283 | if (back >= 0) animationIndex = back 284 | 285 | const newHeights = [...heights] 286 | newHeights.splice(0, animationNum, ...new Array(animationNum).fill(0)) 287 | 288 | Object.assign(stateRef.current, { animationIndex }) 289 | setState(state => ({ ...state, heights: newHeights })) 290 | } 291 | 292 | function emitEvent(handle, ri, ci, row, ceil) { 293 | const { ceils, rowIndex } = row 294 | 295 | handle && handle({ row: ceils, ceil, rowIndex, columnIndex: ci }) 296 | } 297 | 298 | function handleHover(enter, ri, ci, row, ceil) { 299 | if (enter) emitEvent(onMouseOver, ri, ci, row, ceil) 300 | 301 | if (!mergedConfig.hoverPause) return 302 | 303 | const { pause, resume } = task.current 304 | 305 | enter && pause && resume ? pause() : (function() { if (resume) resume() })() 306 | } 307 | 308 | const getBackgroundColor = rowIndex => 309 | mergedConfig[rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC'] 310 | 311 | const task = useRef({}) 312 | 313 | useEffect(() => { 314 | calcData() 315 | 316 | let start = true 317 | 318 | function * loop() { 319 | while (true) { 320 | yield * animation(start) 321 | 322 | start = false 323 | 324 | const { waitTime } = stateRef.current.mergedConfig 325 | 326 | yield new Promise(resolve => setTimeout(resolve, waitTime - 300)) 327 | } 328 | } 329 | 330 | const { 331 | mergedConfig: { rowNum }, 332 | rows: rowsData 333 | } = stateRef.current 334 | 335 | const rowLength = rowsData.length 336 | 337 | if (rowNum >= rowLength) return 338 | 339 | task.current = co(loop) 340 | 341 | return task.current.end 342 | }, [config, domRef.current]) 343 | 344 | useEffect(onResize, [width, height, domRef.current]) 345 | 346 | const classNames = useMemo(() => classnames('dv-scroll-board', className), [ 347 | className 348 | ]) 349 | 350 | return ( 351 |
352 | {!!header.length && !!mergedConfig && ( 353 |
357 | {header.map((headerItem, i) => ( 358 |
369 | ))} 370 |
371 | )} 372 | 373 | {!!mergedConfig && ( 374 |
381 | {rows.map((row, ri) => ( 382 |
391 | {row.ceils.map((ceil, ci) => ( 392 |
emitEvent(onClick, ri, ci, row, ceil)} 399 | onMouseEnter={() => handleHover(true, ri, ci, row, ceil)} 400 | onMouseLeave={() => handleHover(false)} 401 | /> 402 | ))} 403 |
404 | ))} 405 |
406 | )} 407 |
408 | ) 409 | }) 410 | 411 | ScrollBoard.propTypes = { 412 | config: PropTypes.object, 413 | onClick: PropTypes.func, 414 | onMouseOver: PropTypes.func, 415 | className: PropTypes.string, 416 | style: PropTypes.object 417 | } 418 | 419 | export default ScrollBoard 420 | -------------------------------------------------------------------------------- /src/components/scrollBoard/style.less: -------------------------------------------------------------------------------- 1 | .dv-scroll-board { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | color: #fff; 6 | 7 | .text { 8 | padding: 0 10px; 9 | box-sizing: border-box; 10 | white-space: nowrap; 11 | overflow: hidden; 12 | text-overflow: ellipsis; 13 | } 14 | 15 | .header { 16 | display: flex; 17 | flex-direction: row; 18 | font-size: 15px; 19 | 20 | .header-item { 21 | .text; 22 | transition: all 0.3s; 23 | } 24 | } 25 | 26 | .rows { 27 | overflow: hidden; 28 | 29 | .row-item { 30 | display: flex; 31 | font-size: 14px; 32 | transition: all 0.3s; 33 | } 34 | 35 | .ceil { 36 | .text; 37 | } 38 | 39 | .index { 40 | border-radius: 3px; 41 | padding: 0px 3px; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/components/scrollRankingBoard/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState, useMemo, forwardRef } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import useAutoResize from '../../use/autoResize' 12 | import { co } from '../../util' 13 | 14 | import './style.less' 15 | 16 | const defaultConfig = { 17 | /** 18 | * @description Board data 19 | * @type {Array} 20 | * @default data = [] 21 | */ 22 | data: [], 23 | /** 24 | * @description Row num 25 | * @type {Number} 26 | * @default rowNum = 5 27 | */ 28 | rowNum: 5, 29 | /** 30 | * @description Scroll wait time 31 | * @type {Number} 32 | * @default waitTime = 2000 33 | */ 34 | waitTime: 2000, 35 | /** 36 | * @description Carousel type 37 | * @type {String} 38 | * @default carousel = 'single' 39 | * @example carousel = 'single' | 'page' 40 | */ 41 | carousel: 'single', 42 | /** 43 | * @description Value unit 44 | * @type {String} 45 | * @default unit = '' 46 | * @example unit = 'ton' 47 | */ 48 | unit: '', 49 | /** 50 | * @description Auto sort by value 51 | * @type {Boolean} 52 | * @default sort = true 53 | */ 54 | sort: true, 55 | /** 56 | * @description Value formatter 57 | * @type {Function} 58 | * @default valueFormatter = null 59 | */ 60 | valueFormatter: null 61 | } 62 | 63 | function calcRows({ data, rowNum, sort }) { 64 | sort && data.sort(({ value: a }, { value: b }) => { 65 | if (a > b) return -1 66 | if (a < b) return 1 67 | if (a === b) return 0 68 | }) 69 | 70 | const value = data.map(({ value }) => value) 71 | 72 | const min = Math.min(...value) || 0 73 | 74 | // 最小值的绝对值 75 | const minAbs = Math.abs(min) 76 | 77 | const max = Math.max(...value) || 0 78 | 79 | // 最大值的绝对值 80 | const maxAbs = Math.abs(max) 81 | 82 | // 总数为最大值与最小值的绝对值相加 83 | const total = maxAbs + minAbs 84 | 85 | data = data.map((row, i) => ({ 86 | ...row, 87 | ranking: i + 1, 88 | percent: total && ((row.value + minAbs) / total * 100) 89 | })) 90 | 91 | const rowLength = data.length 92 | 93 | if (rowLength > rowNum && rowLength < 2 * rowNum) { 94 | data = [...data, ...data] 95 | } 96 | 97 | data = data.map((d, i) => ({ ...d, scroll: i })) 98 | 99 | return data 100 | } 101 | 102 | const ScrollRankingBoard = forwardRef(({ config = {}, className, style }, ref) => { 103 | const { width, height, domRef } = useAutoResize(ref) 104 | 105 | const [state, setState] = useState({ 106 | mergedConfig: null, 107 | 108 | rows: [], 109 | 110 | heights: [] 111 | }) 112 | 113 | const { mergedConfig, rows, heights } = state 114 | 115 | const stateRef = useRef({ 116 | ...state, 117 | rowsData: [], 118 | avgHeight: 0, 119 | animationIndex: 0 120 | }) 121 | 122 | const heightRef = useRef(height) 123 | 124 | Object.assign(stateRef.current, state) 125 | 126 | function onResize(onresize = false) { 127 | if (!mergedConfig) return 128 | 129 | const heights = calcHeights(mergedConfig, onresize) 130 | 131 | if (heights !== undefined) { 132 | Object.assign(stateRef.current, { heights }) 133 | setState(state => ({ ...state, heights })) 134 | } 135 | } 136 | 137 | function calcData() { 138 | const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) 139 | 140 | const rows = calcRows(mergedConfig) 141 | 142 | const heights = calcHeights(mergedConfig) 143 | 144 | const data = { mergedConfig, rows } 145 | 146 | heights !== undefined && Object.assign(data, { heights }) 147 | 148 | Object.assign(stateRef.current, data, { rowsData: rows, animationIndex: 0 }) 149 | 150 | setState(state => ({ ...state, ...data })) 151 | } 152 | 153 | function calcHeights({ rowNum, data }, onresize = false) { 154 | const avgHeight = height / rowNum 155 | 156 | Object.assign(stateRef.current, { avgHeight }) 157 | 158 | if (!onresize) { 159 | return new Array(data.length).fill(avgHeight) 160 | } 161 | } 162 | 163 | function * animation(start = false) { 164 | let { 165 | avgHeight, 166 | animationIndex, 167 | mergedConfig: { waitTime, carousel, rowNum }, 168 | rowsData 169 | } = stateRef.current 170 | 171 | const rowLength = rowsData.length 172 | 173 | if (start) yield new Promise(resolve => setTimeout(resolve, waitTime)) 174 | 175 | const animationNum = carousel === 'single' ? 1 : rowNum 176 | 177 | let rows = rowsData.slice(animationIndex) 178 | rows.push(...rowsData.slice(0, animationIndex)) 179 | rows = rows.slice(0, rowNum + 1) 180 | 181 | const heights = new Array(rowLength).fill(avgHeight) 182 | setState(state => ({ ...state, rows, heights })) 183 | 184 | yield new Promise(resolve => setTimeout(resolve, 300)) 185 | 186 | animationIndex += animationNum 187 | 188 | const back = animationIndex - rowLength 189 | if (back >= 0) animationIndex = back 190 | 191 | const newHeights = [...heights] 192 | newHeights.splice(0, animationNum, ...new Array(animationNum).fill(0)) 193 | 194 | Object.assign(stateRef.current, { animationIndex }) 195 | setState(state => ({ ...state, heights: newHeights })) 196 | } 197 | 198 | useEffect(() => { 199 | calcData() 200 | 201 | let start = true 202 | 203 | function * loop() { 204 | while (true) { 205 | yield * animation(start) 206 | 207 | start = false 208 | 209 | const { waitTime } = stateRef.current.mergedConfig 210 | 211 | yield new Promise(resolve => setTimeout(resolve, waitTime - 300)) 212 | } 213 | } 214 | 215 | const { 216 | mergedConfig: { rowNum }, 217 | rows: rowsData 218 | } = stateRef.current 219 | 220 | const rowLength = rowsData.length 221 | 222 | if (rowNum >= rowLength) return 223 | 224 | return co(loop).end 225 | }, [config, domRef.current]) 226 | 227 | useEffect(() => { 228 | if (heightRef.current === 0 && height !== 0) { 229 | onResize() 230 | 231 | heightRef.current = height 232 | } else { 233 | onResize(true) 234 | } 235 | }, [width, height, domRef.current]) 236 | 237 | const classNames = useMemo( 238 | () => classnames('dv-scroll-ranking-board', className), 239 | [className] 240 | ) 241 | 242 | return ( 243 |
244 | {rows.map((item, i) => ( 245 |
250 |
251 |
No.{item.ranking}
252 |
253 |
254 | {mergedConfig.valueFormatter ? mergedConfig.valueFormatter(item) : item.value + mergedConfig.unit} 255 |
256 |
257 | 258 |
259 |
263 |
264 |
265 |
266 |
267 | ))} 268 |
269 | ) 270 | }) 271 | 272 | ScrollRankingBoard.propTypes = { 273 | config: PropTypes.object, 274 | className: PropTypes.string, 275 | style: PropTypes.object 276 | } 277 | 278 | export default ScrollRankingBoard 279 | -------------------------------------------------------------------------------- /src/components/scrollRankingBoard/style.less: -------------------------------------------------------------------------------- 1 | @color: #1370fb; 2 | 3 | .dv-scroll-ranking-board { 4 | width: 100%; 5 | height: 100%; 6 | color: #fff; 7 | overflow: hidden; 8 | 9 | .row-item { 10 | transition: all 0.3s; 11 | display: flex; 12 | flex-direction: column; 13 | justify-content: center; 14 | overflow: hidden; 15 | } 16 | 17 | .ranking-info { 18 | display: flex; 19 | width: 100%; 20 | font-size: 13px; 21 | 22 | .rank { 23 | width: 40px; 24 | color: @color; 25 | } 26 | 27 | .info-name { 28 | flex: 1; 29 | } 30 | } 31 | 32 | .ranking-column { 33 | border-bottom: 2px solid fade(@color, 50); 34 | margin-top: 5px; 35 | 36 | .inside-column { 37 | position: relative; 38 | height: 6px; 39 | background-color: @color; 40 | margin-bottom: 2px; 41 | border-radius: 1px; 42 | overflow: hidden; 43 | } 44 | 45 | .shine { 46 | position: absolute; 47 | left: 0%; 48 | top: 2px; 49 | height: 2px; 50 | width: 50px; 51 | transform: translateX(-100%); 52 | background: radial-gradient(rgb(40, 248, 255) 5%, transparent 80%); 53 | animation: shine 3s ease-in-out infinite alternate; 54 | } 55 | } 56 | } 57 | 58 | @keyframes shine { 59 | 80% { 60 | left: 0%; 61 | transform: translateX(-100%); 62 | } 63 | 64 | 100% { 65 | left: 100%; 66 | transform: translateX(0%); 67 | } 68 | } -------------------------------------------------------------------------------- /src/components/waterLevelPond/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useMemo, useState } from 'react' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | import classnames from 'classnames' 6 | 7 | import { deepMerge } from '@jiaminghi/charts/lib/util/index' 8 | 9 | import { deepClone } from '@jiaminghi/c-render/lib/plugin/util' 10 | 11 | import CRender from '@jiaminghi/c-render' 12 | 13 | import { co, uuid } from '../../util' 14 | 15 | import './style.less' 16 | 17 | const defaultConfig = { 18 | /** 19 | * @description Data 20 | * @type {Array} 21 | * @default data = [] 22 | * @example data = [60, 40] 23 | */ 24 | data: [], 25 | /** 26 | * @description Shape of wanter level pond 27 | * @type {String} 28 | * @default shape = 'rect' 29 | * @example shape = 'rect' | 'roundRect' | 'round' 30 | */ 31 | shape: 'rect', 32 | /** 33 | * @description Water wave number 34 | * @type {Number} 35 | * @default waveNum = 3 36 | */ 37 | waveNum: 3, 38 | /** 39 | * @description Water wave height (px) 40 | * @type {Number} 41 | * @default waveHeight = 40 42 | */ 43 | waveHeight: 40, 44 | /** 45 | * @description Wave opacity 46 | * @type {Number} 47 | * @default waveOpacity = 0.4 48 | */ 49 | waveOpacity: 0.4, 50 | /** 51 | * @description Colors (hex|rgb|rgba|color keywords) 52 | * @type {Array} 53 | * @default colors = ['#00BAFF', '#3DE7C9'] 54 | * @example colors = ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red'] 55 | */ 56 | colors: ['#3DE7C9', '#00BAFF'], 57 | /** 58 | * @description Formatter 59 | * @type {String} 60 | * @default formatter = '{value}%' 61 | */ 62 | formatter: '{value}%' 63 | } 64 | 65 | function drawed({ shape: { points } }, { ctx, area }) { 66 | const firstPoint = points[0] 67 | const lastPoint = points.slice(-1)[0] 68 | 69 | const h = area[1] 70 | 71 | ctx.lineTo(lastPoint[0], h) 72 | ctx.lineTo(firstPoint[0], h) 73 | 74 | ctx.closePath() 75 | 76 | ctx.fill() 77 | } 78 | 79 | function mergeOffset([x, y], [ox, oy]) { 80 | return [x + ox, y + oy] 81 | } 82 | 83 | function calcSvgBorderGradient({ colors }) { 84 | const colorNum = colors.length 85 | 86 | const colorOffsetGap = 100 / (colorNum - 1) 87 | 88 | return colors.map((c, i) => [colorOffsetGap * i, c]) 89 | } 90 | 91 | function calcDetails({ data, formatter }) { 92 | if (!data.length) { 93 | return '' 94 | } 95 | 96 | const maxValue = Math.max(...data) 97 | 98 | return formatter.replace('{value}', maxValue) 99 | } 100 | 101 | function getWaveShapes({ waveNum, waveHeight, data }, [w, h]) { 102 | const pointsNum = waveNum * 4 + 4 103 | 104 | const pointXGap = w / waveNum / 2 105 | 106 | return data.map(v => { 107 | let points = new Array(pointsNum).fill(0).map((foo, j) => { 108 | const x = w - pointXGap * j 109 | 110 | const startY = (1 - v / 100) * h 111 | 112 | const y = j % 2 === 0 ? startY : startY - waveHeight 113 | 114 | return [x, y] 115 | }) 116 | 117 | points = points.map(p => mergeOffset(p, [pointXGap * 2, 0])) 118 | 119 | return { points } 120 | }) 121 | } 122 | 123 | function getWaveStyle({ colors, waveOpacity }, area) { 124 | return { 125 | gradientColor: colors, 126 | gradientType: 'linear', 127 | gradientParams: [0, 0, 0, area[1]], 128 | gradientWith: 'fill', 129 | opacity: waveOpacity, 130 | translate: [0, 0] 131 | } 132 | } 133 | 134 | function getWave(mergedConfig, renderer) { 135 | const area = renderer.area 136 | const shapes = getWaveShapes(mergedConfig, area) 137 | const style = getWaveStyle(mergedConfig, area) 138 | 139 | return shapes.map(shape => 140 | renderer.add({ 141 | name: 'smoothline', 142 | animationFrame: 300, 143 | shape, 144 | style, 145 | drawed 146 | }) 147 | ) 148 | } 149 | 150 | function * animationWave(waves, renderer) { 151 | waves.forEach(graph => { 152 | graph.attr('style', { translate: [0, 0] }) 153 | 154 | graph.animation( 155 | 'style', 156 | { 157 | translate: [renderer.area[0], 0] 158 | }, 159 | true 160 | ) 161 | }) 162 | 163 | yield renderer.launchAnimation() 164 | } 165 | 166 | const WaterLevelPond = ({ config = {}, className, style }) => { 167 | const [renderer, setRenderer] = useState(null) 168 | 169 | const gradientId = useRef(`water-level-pond-${uuid()}`).current 170 | 171 | const domRef = useRef(null) 172 | 173 | const mergedConfig = useMemo( 174 | () => deepMerge(deepClone(defaultConfig, true), config), 175 | [config] 176 | ) 177 | 178 | const svgBorderGradient = useMemo(() => calcSvgBorderGradient(mergedConfig), [ 179 | mergedConfig 180 | ]) 181 | 182 | const details = useMemo(() => calcDetails(mergedConfig), [mergedConfig]) 183 | 184 | const radius = useMemo(() => { 185 | const { shape } = mergedConfig 186 | 187 | if (shape === 'round') return '50%' 188 | 189 | if (shape === 'rect') return '0' 190 | 191 | if (shape === 'roundRect') return '10px' 192 | 193 | return '0' 194 | }, [mergedConfig]) 195 | 196 | const shape = useMemo(() => { 197 | const { shape } = mergedConfig 198 | 199 | return shape || 'rect' 200 | }, [mergedConfig]) 201 | 202 | useEffect(() => { 203 | let innerRenderer = renderer 204 | 205 | if (!renderer) { 206 | innerRenderer = new CRender(domRef.current) 207 | 208 | setRenderer(innerRenderer) 209 | } 210 | 211 | function * loop() { 212 | yield new Promise(resolve => setTimeout(resolve, 30)) 213 | 214 | const wave = getWave(mergedConfig, innerRenderer) 215 | 216 | while (true) { 217 | yield * animationWave(wave, innerRenderer) 218 | 219 | if (!innerRenderer.graphs.length) return 220 | } 221 | } 222 | 223 | const { end } = co(loop) 224 | 225 | return () => { 226 | innerRenderer.delAllGraph() 227 | 228 | // 处理 renderer.launchAnimation 返回 undefined,导致长时间占用主线程(待 cender 下版本,处理后删除下面代码) 229 | innerRenderer.graphs.forEach(_ => _.pauseAnimation()) 230 | innerRenderer.animationStatus = false 231 | 232 | end() 233 | } 234 | }, [mergedConfig]) 235 | 236 | const classNames = useMemo( 237 | () => classnames('dv-water-pond-level', className), 238 | [className] 239 | ) 240 | 241 | return ( 242 |
243 | {!!renderer && ( 244 | 245 | 246 | 247 | {svgBorderGradient.map(lc => ( 248 | 249 | ))} 250 | 251 | 252 | 253 | 259 | {details} 260 | 261 | 262 | {!shape || shape === 'round' ? ( 263 | 270 | ) : ( 271 | 280 | )} 281 | 282 | )} 283 | 284 | 285 |
286 | ) 287 | } 288 | 289 | WaterLevelPond.propTypes = { 290 | config: PropTypes.object, 291 | className: PropTypes.string, 292 | style: PropTypes.object 293 | } 294 | 295 | export default WaterLevelPond 296 | -------------------------------------------------------------------------------- /src/components/waterLevelPond/style.less: -------------------------------------------------------------------------------- 1 | .dv-water-pond-level { 2 | position: relative; 3 | 4 | svg { 5 | position: absolute; 6 | width: 100%; 7 | height: 100%; 8 | top: 0px; 9 | left: 0px; 10 | } 11 | 12 | text { 13 | font-size: 25px; 14 | font-weight: bold; 15 | text-anchor: middle; 16 | dominant-baseline: middle; 17 | } 18 | 19 | ellipse, 20 | rect { 21 | fill: none; 22 | stroke-width: 3; 23 | } 24 | 25 | canvas { 26 | margin-top: 8px; 27 | margin-left: 8px; 28 | width: calc(~"100% - 16px"); 29 | height: calc(~"100% - 16px"); 30 | box-sizing: border-box; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * IMPORT COMPONENTS 3 | */ 4 | export { default as FullScreenContainer } from './components/fullScreenContainer' 5 | export { default as Loading } from './components/loading' 6 | 7 | // border box 8 | export { default as BorderBox1 } from './components/borderBox1' 9 | export { default as BorderBox2 } from './components/borderBox2' 10 | export { default as BorderBox3 } from './components/borderBox3' 11 | export { default as BorderBox4 } from './components/borderBox4' 12 | export { default as BorderBox5 } from './components/borderBox5' 13 | export { default as BorderBox6 } from './components/borderBox6' 14 | export { default as BorderBox7 } from './components/borderBox7' 15 | export { default as BorderBox8 } from './components/borderBox8' 16 | export { default as BorderBox9 } from './components/borderBox9' 17 | export { default as BorderBox10 } from './components/borderBox10' 18 | export { default as BorderBox11 } from './components/borderBox11' 19 | export { default as BorderBox12 } from './components/borderBox12' 20 | export { default as BorderBox13 } from './components/borderBox13' 21 | 22 | // decoration 23 | export { default as Decoration1 } from './components/decoration1' 24 | export { default as Decoration2 } from './components/decoration2' 25 | export { default as Decoration3 } from './components/decoration3' 26 | export { default as Decoration4 } from './components/decoration4' 27 | export { default as Decoration5 } from './components/decoration5' 28 | export { default as Decoration6 } from './components/decoration6' 29 | export { default as Decoration7 } from './components/decoration7' 30 | export { default as Decoration8 } from './components/decoration8' 31 | export { default as Decoration9 } from './components/decoration9' 32 | export { default as Decoration10 } from './components/decoration10' 33 | export { default as Decoration11 } from './components/decoration11' 34 | export { default as Decoration12 } from './components/decoration12' 35 | 36 | // charts 37 | export { default as Charts } from './components/charts' 38 | 39 | export { default as ActiveRingChart } from './components/activeRingChart' 40 | export { default as CapsuleChart } from './components/capsuleChart' 41 | export { default as WaterLevelPond } from './components/waterLevelPond' 42 | export { default as PercentPond } from './components/percentPond' 43 | export { default as FlylineChart } from './components/flylineChart' 44 | export { default as FlylineChartEnhanced } from './components/flylineChartEnhanced' 45 | export { default as ConicalColumnChart } from './components/conicalColumnChart' 46 | export { default as DigitalFlop } from './components/digitalFlop' 47 | export { default as ScrollBoard } from './components/scrollBoard' 48 | export { default as ScrollRankingBoard } from './components/scrollRankingBoard' 49 | 50 | export { default as useAutoResize } from './use/autoResize' 51 | 52 | export { co } from './util' 53 | -------------------------------------------------------------------------------- /src/test.js: -------------------------------------------------------------------------------- 1 | import ExampleComponent from './' 2 | 3 | describe('ExampleComponent', () => { 4 | it('is truthy', () => { 5 | expect(ExampleComponent).toBeTruthy() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /src/use/autoResize.js: -------------------------------------------------------------------------------- 1 | import { useState, useCallback, useEffect, useRef, useImperativeHandle } from 'react' 2 | import { debounce, observerDomResize } from '../util/index' 3 | 4 | export default function useAutoResize(ref) { 5 | const [state, setState] = useState({ width: 0, height: 0 }) 6 | 7 | const domRef = useRef(null) 8 | 9 | const setWH = useCallback(() => { 10 | const { clientWidth, clientHeight } = domRef.current || { clientWidth: 0, clientHeight: 0 } 11 | 12 | setState({ width: clientWidth, height: clientHeight }) 13 | 14 | if (!domRef.current) { 15 | console.warn('DataV: Failed to get dom node, component rendering may be abnormal!') 16 | } else if (!clientWidth || !clientHeight) { 17 | console.warn('DataV: Component width or height is 0px, rendering abnormality may occur!') 18 | } 19 | }, []) 20 | 21 | useImperativeHandle(ref, () => ({ setWH }), []) 22 | 23 | useEffect(() => { 24 | const debounceSetWHFun = debounce(setWH, 100) 25 | 26 | debounceSetWHFun() 27 | 28 | const domObserver = observerDomResize(domRef.current, debounceSetWHFun) 29 | 30 | window.addEventListener('resize', debounceSetWHFun) 31 | 32 | return () => { 33 | window.removeEventListener('resize', debounceSetWHFun) 34 | 35 | if (!domObserver) { 36 | return 37 | } 38 | 39 | domObserver.disconnect() 40 | domObserver.takeRecords() 41 | } 42 | }, []) 43 | 44 | return { ...state, domRef, setWH } 45 | } 46 | -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | export function randomExtend(minNum, maxNum) { 2 | if (arguments.length === 1) { 3 | return parseInt(Math.random() * minNum + 1, 10) 4 | } else { 5 | return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10) 6 | } 7 | } 8 | 9 | /** 10 | * @description 将函数转成防抖动函数 11 | * @param {Function} 需要转成防抖动函数的函数 12 | * @param {number} 延迟时间(毫秒数) 13 | * @param {boolean} 是否执行第一次 14 | * @return {undefined} 无返回值 15 | */ 16 | export function debounce(fn, delay = 600, runFirstFn = true) { 17 | let timer = null 18 | 19 | return function(...rest) { 20 | // 清除定时器 21 | clearTimeout(timer) 22 | if (runFirstFn) { 23 | fn.apply(this, rest) 24 | runFirstFn = false 25 | return 26 | } 27 | 28 | // 设置定时器 29 | timer = setTimeout(fn.bind(this, ...rest), delay) 30 | } 31 | } 32 | 33 | export function observerDomResize(dom, callback) { 34 | const MutationObserver = 35 | window.MutationObserver || 36 | window.WebKitMutationObserver || 37 | window.MozMutationObserver 38 | 39 | const observer = new MutationObserver(callback) 40 | 41 | observer.observe(dom, { 42 | attributes: true, 43 | attributeFilter: ['style'], 44 | attributeOldValue: true 45 | }) 46 | 47 | return observer 48 | } 49 | 50 | export function getPointDistance(pointOne, pointTwo) { 51 | const minusX = Math.abs(pointOne[0] - pointTwo[0]) 52 | 53 | const minusY = Math.abs(pointOne[1] - pointTwo[1]) 54 | 55 | return Math.sqrt(minusX * minusX + minusY * minusY) 56 | } 57 | 58 | export function co(gen) { 59 | let destroyed = false 60 | 61 | // 处理 return 之后 resume 的问题 62 | let stop = false 63 | 64 | let val = null 65 | 66 | if (typeof gen === 'function') gen = gen() 67 | 68 | if (!gen || typeof gen.next !== 'function') return () => ({}) 69 | 70 | Promise.resolve().then(() => { 71 | destroyed || next(gen.next()) 72 | }) 73 | 74 | return { 75 | end () { 76 | destroyed = true 77 | 78 | Promise.resolve().then(() => { 79 | gen.return() 80 | 81 | gen = null 82 | }) 83 | }, 84 | pause () { 85 | if (!destroyed) { stop = true } 86 | }, 87 | resume () { 88 | const oldVal = val 89 | 90 | if (!destroyed && stop) { 91 | stop = false 92 | 93 | Promise.resolve(val).then(function () { 94 | if (!destroyed && !stop && oldVal === val) { next(gen.next()) } 95 | }) 96 | } 97 | } 98 | } 99 | 100 | function next(ret) { 101 | if (ret.done) return ret.value 102 | 103 | val = ret.value 104 | 105 | return Promise.resolve(ret.value).then(() => { 106 | (!destroyed && !stop) && next(gen.next()) 107 | }) 108 | } 109 | } 110 | 111 | export function uuid (hasHyphen) { 112 | return (hasHyphen ? 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' : 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx').replace(/[xy]/g, function (c) { 113 | const r = Math.random() * 16 | 0 114 | const v = c === 'x' ? r : (r & 0x3 | 0x8) 115 | return v.toString(16) 116 | }) 117 | } 118 | -------------------------------------------------------------------------------- /umdExample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DataV 5 | 9 | 13 | 14 | 15 | 19 | 20 | 21 | 25 | 44 | 45 | 46 |
47 | 48 | 53 | 54 | 55 | --------------------------------------------------------------------------------