Compare commits

...

252 Commits

Author SHA1 Message Date
奔跑的面条
fdc39e18dc Merge branch 'dev' 2023-09-18 11:43:20 +08:00
奔跑的面条
d170d94186 fix: 解决分组在预览下的滤镜变换问题 2023-09-18 11:43:04 +08:00
奔跑的面条
5214c27331 fix: 解决window.opener 错误判断 2023-09-18 11:30:08 +08:00
奔跑的面条
af691af61f build: 升级版本到1.2.9 2023-09-18 11:07:39 +08:00
奔跑的面条
ab7ffcddac Merge branch 'dev' 2023-09-18 10:49:12 +08:00
奔跑的面条
19165c76d5 feat: 抽取PR地图下钻代码 2023-09-16 16:52:55 +08:00
ea179f9897 第三方应用open预览地址的时候,发现window.opener并不是一个window对象会报addEventListener不存在。
第三方应用open预览地址的时候,发现window.opener并不是一个window对象会报addEventListener不存在。

Signed-off-by: 空 <jinj@hxcfsoft.com>
2023-09-16 16:10:49 +08:00
奔跑的面条
65d3ee424a docs: update readme 2023-09-14 10:20:50 +08:00
奔跑的面条
55c84f2e39 fix: 解决保存时候可能数据获取不完整的bug 2023-09-13 10:43:11 +08:00
奔跑的面条
f348038ff7 fix: 解决依赖安装会报错的问题 2023-09-06 16:58:42 +08:00
奔跑的面条
dd71c311e0 feat: 解决分组在预览会失效的问题 2023-09-03 23:09:54 +08:00
奔跑的面条
0ab42027c4 style: 优化 pr_200 代码 2023-09-03 18:02:01 +08:00
奔跑的面条
a492ed2440 !200 性能提升, 未知key时处理逻辑调整
Merge pull request !200 from ly-chn/ly-chn
2023-09-03 09:59:15 +00:00
奔跑的面条
4444645dfd fix: 修改关系图的问题 2023-09-03 17:42:11 +08:00
奔跑的面条
c32a9f7d1b !203 feat: 增加关系图力引导布局逻辑
Merge pull request !203 from QuietlyChan/feat-graph
2023-09-03 09:41:19 +00:00
奔跑的面条
8472efd210 fix: 解决预览不会隐藏超出内容的问题 2023-09-03 16:52:31 +08:00
QuietlyChan
4a409393fb 增加关系图力引导布局逻辑 2023-08-30 15:23:41 +08:00
奔跑的面条
0f9e837508 docs: update 2023-08-25 10:40:23 +08:00
奔跑的面条
66a04660fe docs: update 2023-08-24 11:15:57 +08:00
奔跑的面条
a53a6678b7 docs: update 2023-08-24 11:13:59 +08:00
奔跑的面条
310b27f634 docs: add banner 2023-08-18 16:35:10 +08:00
奔跑的面条
552313df12 Merge branch 'dev' 2023-08-17 09:55:45 +08:00
ly-chn
51ba52ae45 fix: 同步时出现特殊key时, 加载进度始终显示, 且无法继续解析后续内容
perf: 大量使用相同组件时, 提升createComponent性能
2023-08-17 09:38:30 +08:00
奔跑的面条
95b50c7d76 fix: 解决TS打包报错 2023-08-15 09:29:06 +08:00
奔跑的面条
d76ddf1126 !197 新增输入框联动组件
Merge pull request !197 from 阿飞/dev1
2023-08-15 01:11:45 +00:00
luoyp
c5788f79b3 新增输入框组件 2023-08-14 11:01:04 +08:00
奔跑的面条
704a7bd8f8 feat: 新增基础分页表格 2023-08-11 23:56:30 +08:00
奔跑的面条
db73346c71 feat: 处理基础表格图片和文案提示 2023-08-11 23:47:05 +08:00
奔跑的面条
ab5ade9be1 perf: 格式化表格组件代码 2023-08-11 22:35:44 +08:00
奔跑的面条
0d3418259c !192 新增分页表格组件
Merge pull request !192 from 阿飞/dev2
2023-08-11 14:22:14 +00:00
奔跑的面条
541ce8a083 feat: 修改柱状图 & 折线图文件位置和名称,格式化内容 2023-08-11 22:20:32 +08:00
奔跑的面条
6b9e993599 !193 新增组合图
Merge pull request !193 from 阿飞/dev3
2023-08-11 14:08:47 +00:00
奔跑的面条
1ad0658a5f !194 新增分页联动组件
Merge pull request !194 from 阿飞/dev4
2023-08-11 14:03:20 +00:00
奔跑的面条
b89e5d702b !190 feat: 增加全屏按钮组件
Merge pull request !190 from QuietlyChan/feat-fullScreen
2023-08-11 13:55:15 +00:00
奔跑的面条
fed515f844 !191 修复单折线渐变图鼠标移入报错
Merge pull request !191 from 阿飞/dev1
2023-08-11 13:50:54 +00:00
奔跑的面条
9f9df3566f !196 修复naive-ui进度图预览显示bug
Merge pull request !196 from 阿飞/dev6
2023-08-11 13:49:47 +00:00
奔跑的面条
39e735b29c fix: 解决了三维地球不能被截图的bug 2023-08-11 21:43:43 +08:00
奔跑的面条
d2ad32e08e fix: 解决地图point的值展示错误的问题 2023-08-09 09:28:48 +08:00
retire
b75cbea6cc feat: 基础事件增加components参数 2023-08-03 21:05:06 +08:00
luoyp
3c1ea60f21 修复Naive-UI进度图预览显示bug 2023-08-03 15:38:47 +08:00
奔跑的面条
fb8034c915 docs: update 2023-08-03 10:47:59 +08:00
奔跑的面条
39f0a136b7 docs: update 2023-08-03 10:38:37 +08:00
奔跑的面条
f83db8a31d docs: update 2023-08-03 10:37:27 +08:00
奔跑的面条
fbf453b9fa docs: update 2023-08-03 10:36:37 +08:00
奔跑的面条
7fd9d339c4 docs: update readme 2023-08-03 10:33:35 +08:00
luoyp
32c5b216f2 修复组合图不显示 2023-08-01 16:44:30 +08:00
luoyp
a08e27da2d 新增分页联动组件 2023-08-01 09:32:55 +08:00
luoyp
4c13dc3184 新增组合图 2023-08-01 09:16:54 +08:00
luoyp
d91c86f01c 新增分页表格组件 2023-08-01 08:48:59 +08:00
luoyp
5479a26832 修复单折线渐变图鼠标移入报错 2023-08-01 08:44:27 +08:00
奔跑的面条
1250829da6 fix: 处理一开始不会请求的问题 2023-07-31 17:09:20 +08:00
奔跑的面条
ac2fd67688 fix: 修复创建分组排序会错误的bug 2023-07-31 15:45:43 +08:00
QuietlyChan
dbc44bf419 fix: 修复初始化不能拖拽 2023-07-28 14:34:40 +08:00
QuietlyChan
1401a091eb feat: 增加全屏按钮组件 2023-07-28 10:11:34 +08:00
奔跑的面条
5bef16665a docs: update readme 2023-07-24 10:06:31 +08:00
奔跑的面条
f528eb29bc fix: 处理加上链接内容就会消失的bug 2023-07-21 16:43:05 +08:00
奔跑的面条
06921ea3f5 !180 修复旋转组件预览错位问题
Merge pull request !180 from 张江胜/dev_fix
2023-07-21 08:29:05 +00:00
奔跑的面条
f2d9f14ea5 !179 修复右下角白点 通过修改样式修改 不需要元素
Merge pull request !179 from cherubic_c/dev
2023-07-21 08:06:37 +00:00
奔跑的面条
9477bceefc !182 基础事件增加components参数
Merge pull request !182 from Retire/pr
2023-07-21 07:06:42 +00:00
奔跑的面条
d76107e2b0 !183 调整过滤编辑界面大小,方便编写过滤
Merge pull request !183 from Retire/pr0713
2023-07-21 07:01:30 +00:00
奔跑的面条
97e5d985bd !184 fix: 左侧刻度尺错位问题
Merge pull request !184 from daidai/dev
2023-07-21 06:59:15 +00:00
刘嘉威
bb1828b478 fix: 左侧刻度尺错位问题 2023-07-20 14:28:31 +08:00
Ming
91c4cca62e fix: 粘贴坐标 2023-07-17 18:53:33 +08:00
奔跑的面条
c604b41fb2 Merge branch 'dev' 2023-07-15 14:14:19 +08:00
奔跑的面条
c3140d3746 build: 升级 axios lock错误 2023-07-15 14:13:40 +08:00
retire
c19080e75b style: 调整过滤编辑界面大小,方便编写过滤 2023-07-13 17:38:49 +08:00
retire
7519247f93 feat: 基础事件增加components参数 2023-07-13 11:23:51 +08:00
奔跑的面条
34fe89c168 docs: update readme 2023-07-12 18:26:57 +08:00
张江胜
307cdd9e9a fix: 修复单个组件旋转后,进行分组再次旋转预览错位的问题 2023-07-10 11:06:19 +08:00
IMyself
7bc8c16581 修复右下角白点 2023-07-10 08:21:10 +08:00
奔跑的面条
4cba991e9f Merge branch 'dev' 2023-07-09 17:07:14 +08:00
奔跑的面条
8caa588d3f perf: 优化预览拖拽交互 2023-07-09 17:06:35 +08:00
奔跑的面条
9cf023fcc8 Merge branch 'dev' 2023-07-09 15:54:38 +08:00
奔跑的面条
7076c4deb7 feat: 新增预览拖拽 2023-07-09 15:54:01 +08:00
奔跑的面条
28f0585a5c Merge branch 'dev' 2023-07-08 22:00:35 +08:00
奔跑的面条
e979149cfb feat: 不符合接口格式时添加拦截 2023-07-08 21:59:41 +08:00
奔跑的面条
5fc43d1d02 build: 升级版本到1.2.7 2023-07-08 21:52:07 +08:00
奔跑的面条
084441d365 Merge branch 'dev' 2023-07-08 21:48:53 +08:00
奔跑的面条
d0d031d1bb feat: 还原修改成组旋转的问题,优化预览放大的交互 2023-07-08 21:33:50 +08:00
奔跑的面条
9127e6f44c feat: 新增预览放大功能 2023-07-08 21:18:37 +08:00
xlys999
bb610ff7ae update src/views/chart/ContentEdit/components/EditRule/index.vue.
坐标尺刻度错位问题

Signed-off-by: xlys999 <xlys998@163.com>
2023-07-08 18:45:03 +08:00
奔跑的面条
2dc12b1f0b !177 update src/views/chart/ContentEdit/components/EditRule/index.vue.
Merge pull request !177 from xlys999/N/A
2023-07-08 10:42:13 +00:00
奔跑的面条
c575cff727 perf: 优化滤镜预设展示 2023-07-08 18:36:36 +08:00
奔跑的面条
5443c9647b !176 新增预设滤镜功能
Merge pull request !176 from 张江胜/dev_feat
2023-07-08 10:35:31 +00:00
xlys999
ace6b0f0d2 update src/views/chart/ContentEdit/components/EditRule/index.vue.
坐标尺刻度错位问题

Signed-off-by: xlys999 <xlys998@163.com>
2023-07-03 14:10:00 +00:00
张江胜
271a02ff12 feat: 增加预设滤镜功能
1.滤镜变换:新增了快捷预设滤镜
2023-06-29 18:45:59 +08:00
张江胜
f747fd3506 fix: 解决单个组件旋转后,再组合分组渲染预览会错位的问题
1.解决单个组件旋转后,和其他组件组合分组后再次旋转,进行预览后该分组会错位的问题
2.解决TS类型报错
2023-06-29 17:39:17 +08:00
奔跑的面条
b59c28b8ae fix: 解决 TS 类型错误问题 2023-06-27 18:11:37 +08:00
奔跑的面条
b1a0e7b5e2 fix: 修改 axios 类型错误 2023-06-27 17:54:17 +08:00
奔跑的面条
0d762f7d30 style: 优化 pr_173 的问题 2023-06-27 17:48:08 +08:00
奔跑的面条
cc156a0a6b !173 1.时间选择器增加默认值类型选项
Merge pull request !173 from dingxs/dingxs
2023-06-27 09:47:39 +00:00
奔跑的面条
a77f4d6bf4 !174 feat: 为 naive-ui 组件配置感知、属性提示、自动完成功能
Merge pull request !174 from dodu/dev-commet
2023-06-25 01:32:43 +00:00
tnt group
9e5676e5ed feat: 为 naive-ui 组件提供感知能力 2023-06-23 11:54:52 +08:00
dingxs
bc79e2f01f fix:用in判断对象是否具有某个特定的key,而不是value,解决当value为null时永远得不到修改 2023-06-19 14:39:00 +08:00
dingxs
80f06afa02 feat:时间选择器增加默认值类型选项 2023-06-19 14:35:17 +08:00
奔跑的面条
58ab3dee6d !172 环形饼图增加轨道宽度设置,并优化数字显示(如无小数位,则不强制显示小数位)
Merge pull request !172 from dodu/dev-commet
2023-06-15 11:52:47 +00:00
奔跑的面条
d7a3bb7ba0 !169 feat:标签选择器增加默认值选项
Merge pull request !169 from h5coder/dev-h5coder
2023-06-15 19:50:27 +08:00
奔跑的面条
5387a7ad90 !171 fix: 修复旧版本没有legend配置导致报settting color错误
Merge pull request !171 from h5coder/h5coder-fix
2023-06-15 19:46:13 +08:00
tnt group
fe37435f79 chore: 设置选择框size 2023-06-14 07:54:36 +08:00
tnt group
1ef6d9797a feat: 环形饼图增加轨道宽度设置,并优化数字显示 2023-06-13 10:27:08 +08:00
奔跑的面条
c70d54c622 style: 删除冗余代码 2023-06-08 16:39:18 +08:00
Ming
d74645d7b0 feat: 组件交互对公共api支持配置页 2023-06-07 15:13:48 +08:00
Ming
86910de3b2 fix: 数据初始化 2023-06-07 15:08:52 +08:00
Ming
47636ee680 feat: 支持对公共api进行交互 2023-06-07 15:06:51 +08:00
Ming
9485931f5d feat: 更新公共api对组件动态绑定交互 2023-06-07 15:03:59 +08:00
Ming
20fa9e4afe fix: declare module '@iconify/vue' 2023-06-07 15:00:28 +08:00
Ming
cbd629d7f8 feat: 更新交互组件更新方式 2023-06-07 15:00:06 +08:00
Ming
1551aa9ded fix: 语言转换为英文后,创建按钮的英文拼写错误 2023-05-29 10:29:44 +08:00
奔跑的面条
471610963b build: 升级版本到1.2.6 2023-05-28 17:29:19 +08:00
奔跑的面条
f6424245fd Merge branch 'dev' 2023-05-28 17:28:34 +08:00
奔跑的面条
d9834482f3 !166 fix: 调整组件列表下图片的展现方式,保持图片不被变形
Merge pull request !166 from dodu/dev-commet
2023-05-28 09:27:17 +00:00
tnt group
6fe20c4655 fix: 调整组件列表下图片的展现方式,保持图片不被变形 2023-05-28 17:23:59 +08:00
奔跑的面条
6afbe59828 Merge branch 'dev' 2023-05-28 17:20:36 +08:00
奔跑的面条
52389fa6fc !162 ecahrts全局公共图例新增详细配置参数
Merge pull request !162 from tanhao/feat-echarts-legend
2023-05-28 09:09:26 +00:00
奔跑的面条
bcb2ca1cb5 !159 地图组件新增卫星地图主题
Merge pull request !159 from tanhao/feat-map-theme
2023-05-28 16:15:58 +08:00
奔跑的面条
346c8d439a !164 feat: 增加管道组件
Merge pull request !164 from wsc/dev
2023-05-28 07:50:00 +00:00
奔跑的面条
c7f7c6a731 !163 fix: 修复原来动态导入的问题,保留 redirectComponent 配置的灵活性
Merge pull request !163 from dodu/dev-commet
2023-05-27 07:00:44 +00:00
tnt group
6063408d94 fix: 上次遗漏的修复 #e463b2cd 2023-05-27 13:21:17 +08:00
tnt group
ff4140cbfb chore: 使用模板字符串方式表示 redirectComponent 规则,更为精准,避免手误 2023-05-27 12:06:43 +08:00
tnt group
d8bcb4ab4f fix: 修复图标组件持久化(或导出再导入)时保存的分类不正确导致无法载入的问题 2023-05-27 00:02:40 +08:00
Wang sc
3d4e05b514 feat: 增加管道组件 2023-05-26 18:07:35 +08:00
tnt group
bb48745484 fix: 修复动态导入的问题,保留 redirectComponent 配置的灵活性 2023-05-26 16:51:05 +08:00
tanhao
f9adeac742 feat: echarts公共图例新增详细配置信息 2023-05-25 11:52:10 +08:00
奔跑的面条
8867a489a2 fix: 处理编译之后无法生成新数据的bug 2023-05-24 22:49:25 +08:00
奔跑的面条
adfd8c63e2 !159 地图组件新增卫星地图主题
Merge pull request !159 from tanhao/feat-map-theme
2023-05-24 12:58:20 +00:00
奔跑的面条
d8c55b6325 perf: 优化提示文案 2023-05-24 20:53:26 +08:00
奔跑的面条
44ace74ca9 fix: 新增删除功能 2023-05-24 17:59:27 +08:00
奔跑的面条
2e84b3d196 feat: 修改代码结构,新增删除按钮 2023-05-24 16:56:39 +08:00
奔跑的面条
8f82c1fa59 !157 fix:修复[时间选择器无法获取实际所选时间范围]Bug并且设置默认值
Merge pull request !157 from dingxs/dev-fix
2023-05-24 07:54:08 +00:00
奔跑的面条
7098e2e5e7 !158 chore: 图标和图片虚拟组件设置成static静态资源
Merge pull request !158 from dodu/dev-commet
2023-05-24 07:40:14 +00:00
tanhao
11af941590 feat: 在地图组件基础上新增卫星地图主题 2023-05-24 14:44:46 +08:00
tnt group
051ddcc2d4 chore: 图标和图片动态组件设置成static静态资源 2023-05-24 11:49:24 +08:00
奔跑的面条
773ae65085 perf: 处理提示词 2023-05-23 21:13:54 +08:00
奔跑的面条
e4db7cb8ff feat: 新增图片和图标 2023-05-23 20:55:24 +08:00
dingxs
8bb0f5e3a5 fix:修复[时间选择器无法获取实际所选时间范围]Bug并且设置默认值 2023-05-23 11:50:47 +08:00
Ming
93ed31f093 feat: 防止前端编译工具安全警告报错 2023-05-22 11:43:54 +08:00
Ming
76e511daa0 feat: 动态日期,初始化日期 2023-05-22 11:38:38 +08:00
Ming
a2184b19b3 feat: 动态日期config面板 2023-05-22 11:36:43 +08:00
Ming
ec9210d7e7 feat: 动态日期config 2023-05-22 11:34:59 +08:00
奔跑的面条
e0fe8f673c !155 增加图片、图标侧边栏功能
Merge pull request !155 from dodu/dev-commet
2023-05-22 03:06:22 +00:00
tnt group
95466aa076 feat: 添加天气分组图标 2023-05-20 13:53:15 +08:00
tnt group
6e8e38e737 fix: 修复搜索列表不显示图标的问题 2023-05-19 17:19:34 +08:00
tnt group
3008073829 fix: 修复图标无法拖拽的问题 2023-05-19 17:15:24 +08:00
tnt group
0e0794338a fix: 修复合并丢掉的虚拟组件配置,导致photos my 下的虚拟组件异常 2023-05-18 20:20:58 +08:00
tnt group
5059c9ea65 chore: 移除 pnpm-lock,避免冲突 2023-05-18 19:59:25 +08:00
tnt group
50a8342c49 Merge branch 'dev-photos' into dev-commet 2023-05-18 19:56:31 +08:00
tnt group
afad8e49b1 feat: 增加图标边栏选项卡 2023-05-18 19:44:27 +08:00
tnt group
a3d97e56ab feat: 增加两种图标类别及虚拟组件 2023-05-18 19:43:36 +08:00
tnt group
816c11a877 feat: 扩展 ConfigType,以支持虚拟图标组件 2023-05-18 19:41:30 +08:00
tnt group
6fee63600b feat: 创建通用图标组件 2023-05-18 19:39:21 +08:00
tnt group
1dd055294c feat: 添加 iconify 库及图标素材 2023-05-18 19:36:58 +08:00
tnt group
4aa41bbe36 chore: 忽略vite警告 2023-05-18 12:00:31 +08:00
tnt group
9585bd07a3 feat: 扩展 ConfigType 添加 clickHandle 属性,为上传图片组件增加点击事件,完善点击上传(暂时不走网络,读取其base64) 2023-05-18 09:46:18 +08:00
tnt group
aecba9c95e feat: 扩展 ConfigType,添加禁用属性,并添加一个上传按钮组件,在拖拽、双击、搜索模式让配置了禁用项的组件不可用 2023-05-18 09:45:41 +08:00
奔跑的面条
57ad9a2c7a build: 升级依赖 2023-05-18 09:21:54 +08:00
奔跑的面条
e71fb22b22 build: 升级依赖 2023-05-18 09:19:02 +08:00
tnt group
d177ebc900 feat: 侧边栏中加入图片类型选项卡 2023-05-17 20:30:50 +08:00
tnt group
e18cf847cd feat: 组件 Image 支持延迟加载 2023-05-17 20:23:55 +08:00
tnt group
31ed863d53 feat: 在通过拖拽、双击、搜索不同方式动态创建组件时,支持创建虚拟组件,并根据预设值和预设标题,初始化组件 2023-05-17 20:23:05 +08:00
tnt group
c7b2daa0b8 feat: 创建Photos虚拟组件(设置 virtualComponent 组件路径),预设我的|共享类别 2023-05-17 20:16:36 +08:00
tnt group
3a6990f124 feat: 扩展 ConfigType 组件配置类型,支持虚拟组件路径和预设组件 dataset 值 2023-05-17 20:12:48 +08:00
tnt group
9f41ad1811 feat: 列表组件的image渲染支持url模式 2023-05-17 20:09:03 +08:00
奔跑的面条
0ec0a12b0f feat: 升级 vite 版本到4.3.6 2023-05-16 19:48:23 +08:00
奔跑的面条
c18bc019d3 feat: 新增饼图轮播功能 2023-05-16 19:48:06 +08:00
奔跑的面条
6bbe489162 !154 修复数字翻牌因未等待ui更新导致显示错误的异常,并能实时响应更新
Merge pull request !154 from dodu/dev-commet
2023-05-14 09:09:48 +00:00
tnt group
54cdada560 style: 加重翻牌动画效果 2023-05-14 13:03:25 +08:00
tnt group
048f3426fe fix: 修复因变化快无法显示反动动画效果 2023-05-14 12:34:21 +08:00
tnt group
c508aaa400 feat: 翻牌数字增加内阴影边框属性及配置,默认为 0 2023-05-14 12:12:59 +08:00
tnt group
606cb753c4 fix: 修复因翻牌值变化太快,导致显示错误的异常 2023-05-14 12:09:38 +08:00
奔跑的面条
66e376a87d docs: update 2023-05-13 14:21:49 +08:00
奔跑的面条
318821680a docs: update 2023-05-13 14:19:52 +08:00
奔跑的面条
114fe5626a update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-05-13 05:55:38 +00:00
奔跑的面条
afb364b362 docs: add sponsors 2023-05-13 13:52:52 +08:00
tnt group
01be79ee9a Merge branch 'dev' into dev-commet 2023-05-10 11:33:48 +08:00
Ming
3137109c6d fix: 支持分组 2023-05-09 10:13:48 +08:00
Ming
1d876418fe feat: 交互绑定组件,可以绑定分组内组件 2023-05-09 10:09:26 +08:00
Ming
fd37ce6ede fix: 补充枚举字段 2023-05-09 10:08:47 +08:00
Ming
9693c0dedf docs: md 2023-05-09 09:50:13 +08:00
Ming
dc8d7c86d7 perf: 优化颜色 2023-05-09 09:46:00 +08:00
Ming
8499d574dc fix: 小组件外层盒子宽度不一致 2023-05-09 09:44:14 +08:00
奔跑的面条
5c1af11788 build: 升级版本到 1.2.5 2023-05-08 20:42:22 +08:00
奔跑的面条
c953ccd238 Merge branch 'dev' 2023-05-08 20:37:17 +08:00
奔跑的面条
697542f804 perf: 优化发布的提示文案 2023-05-08 20:27:53 +08:00
奔跑的面条
0bb83c4131 perf: 去除多余无用功能 2023-05-08 20:21:23 +08:00
Ming
38d542ce77 feat: 加载完毕 清除历史记录 2023-05-04 17:17:45 +08:00
Ming
663cc94ae1 feat: 文本组件可进自定义换行 2023-05-04 17:13:51 +08:00
Ming
0370bc5c6c feat: 拖拽中无需计算hover 2023-05-04 17:07:35 +08:00
Ming
4dc8725b3e feat: 先获取数据后触发画布 2023-05-04 17:04:08 +08:00
奔跑的面条
7b9da32215 Merge branch 'dev' 2023-04-23 21:14:43 +08:00
奔跑的面条
9ce042cc8a perf: 优化切换图表导致画布缩放的交互 2023-04-23 21:14:28 +08:00
奔跑的面条
9b8cf36135 Merge branch 'dev' 2023-04-23 21:09:21 +08:00
奔跑的面条
a400526108 fix: 修改不返回 code 导致的问题 2023-04-23 21:05:52 +08:00
奔跑的面条
2a8d0717f8 fix: 处理编辑和预览不一致的问题 2023-04-23 20:33:46 +08:00
奔跑的面条
a6194b8fa9 style: 优化写法 2023-04-23 20:05:49 +08:00
tntgroup
09a21f44c5 Merge branch 'dev' into dev-commet 2023-04-22 08:05:21 +08:00
奔跑的面条
de681dbcd4 fix: 修复密码无限制的漏洞 2023-04-16 19:59:04 +08:00
奔跑的面条
465fbf713c fix: update readme 2023-04-11 09:23:33 +08:00
奔跑的面条
3b41bf480c Merge branch 'dev' 2023-04-05 16:39:25 +08:00
奔跑的面条
59b9ca0569 !152 fix: 柱状图传入错误数据后展示问题
Merge pull request !152 from szy/fix/barcommon
2023-04-05 08:27:11 +00:00
headmasterZhao
c930e3433f fix: 柱状图传入错误数据后展示问题 2023-04-04 09:35:28 +08:00
headmasterZhao
8e1731354c fix: 柱状图传入错误数据后展示问题 2023-04-04 09:34:47 +08:00
headmasterZhao
93f398d5a7 fix: 柱状图传入错误数据后展示问题 2023-04-04 08:46:56 +08:00
headmasterZhao
0f61ee728b fix: 柱状图传入错误数据后展示问题 2023-04-04 08:41:26 +08:00
奔跑的面条
234755cd34 Merge branch 'dev' 2023-04-03 20:11:09 +08:00
奔跑的面条
8ef4ab8175 fix: 处理过滤器会让柱状图重复的bug 2023-04-03 20:10:43 +08:00
奔跑的面条
c289252546 style: 去除多余代码 2023-04-02 18:16:27 +08:00
奔跑的面条
5207a98ce4 build: 升级版本号到 1.2.4 2023-04-02 18:15:12 +08:00
奔跑的面条
e411cb9b09 style: 去除多余代码 2023-04-02 18:14:22 +08:00
奔跑的面条
a2f32b0289 Merge branch 'dev' 2023-04-02 18:00:55 +08:00
奔跑的面条
db7a4801d8 feat: 还原实时同步到预览页面的功能 2023-04-01 22:00:26 +08:00
奔跑的面条
47d1dcbc04 build: 升级 vite 到4.x版本, 修改不兼容的代码 2023-04-01 21:33:01 +08:00
奔跑的面条
9fd408e8ef !151 fix: 柱状图组件动态数据发送请求后,配置会被覆盖成默认配置问题
Merge pull request !151 from szy/fix/bar
2023-04-01 12:00:02 +00:00
headmasterZhao
77a5f47e82 fix: 补充 2023-04-01 19:28:39 +08:00
headmasterZhao
4915f9e077 fix: 柱状图组件配置会被覆盖成默认配置问题 2023-04-01 19:18:15 +08:00
奔跑的面条
ce46f609ec !147 feat: 增加表盘组件,后续完善
Merge pull request !147 from szy/dev
2023-04-01 08:10:39 +00:00
headmasterZhao
ba425d44cc feat: 增加仪表盘组件,解决冲突 2023-04-01 15:48:33 +08:00
奔跑的面条
e6338f89dd !148 feat: 增加桑基图组件,桑基图mock接口
Merge pull request !148 from szy/feat-sankey
2023-04-01 06:41:15 +00:00
headmasterZhao
24361e63c2 feat: 增加桑基图,解决冲突 2023-04-01 13:02:22 +08:00
奔跑的面条
5effb94b1d !149 feat: 增加关系图组件,关系图mock接口
Merge pull request !149 from szy/feat/graph
2023-03-31 11:54:29 +00:00
奔跑的面条
f68aee1f3a !150 fix: 修复导入json数据后,修改其中一个图表的功能,所有图表都会修改的问题
Merge pull request !150 from szy/fix/bar
2023-03-31 11:48:16 +00:00
headmasterZhao
233f3210c6 fix: 横向柱状图导入json数据后,修改其中一个图表的功能,所有图表都会修改,和柱状图相同的问题 2023-03-30 19:40:00 +08:00
headmasterZhao
ab52fcaaf9 fix: 柱状图导入json数据后,修改其中一个图表的功能,所有图表都会修改 2023-03-30 19:37:18 +08:00
headmasterZhao
99eadd96af feat: 增加关系图,关系图mock接口 2023-03-30 16:40:30 +08:00
headmasterZhao
480e328306 feat: 增加mock桑基图数据 2023-03-30 13:37:07 +08:00
headmasterZhao
bd52c4454c feat: 增加桑基图组件 2023-03-30 13:28:39 +08:00
“zxzsxf”
6b87618622 feat: 增加表盘组件 2023-03-28 23:01:16 +08:00
奔跑的面条
4e9f96505a fix: 修改聚焦按钮函数错误 2023-03-28 16:10:14 +08:00
奔跑的面条
dde03274c2 !146 fix: 页面布局按钮激活状态不能准确切换问题
Merge pull request !146 from szy/dev
2023-03-28 08:08:52 +00:00
“zxzsxf”
41444026f9 fix: 页面布局按钮激活状态不能准确切换问题 2023-03-27 14:09:20 +08:00
“zxzsxf”
8b76f6e219 fix: 页面布局按钮激活状态不能准确切换问题 2023-03-27 14:07:56 +08:00
“zxzsxf”
5ed3e4e8b1 fix: 页面布局按钮激活状态不能准确切换问题 2023-03-27 13:51:52 +08:00
奔跑的面条
55221ff756 perf: 处理 alive 2023-03-27 10:32:52 +08:00
奔跑的面条
b534619649 !144 修复keep-alive组件复用
Merge pull request !144 from NuroDante/dev
2023-03-27 02:21:45 +00:00
奔跑的面条
421ea3dc84 !145 fix: dock模式工具栏会遮挡滚动条问题,工具栏选择隐藏时,鼠标悬停在下方工具栏闪烁问题
Merge pull request !145 from headmasterZhao/dev
2023-03-27 01:50:56 +00:00
“zxzsxf”
4bb3c34bc2 fix: dock模式工具栏会遮挡滚动条问题,工具栏选择隐藏时,鼠标悬停在下方工具栏闪烁问题 2023-03-26 16:09:55 +08:00
Nuro
2cbb851948 fix: 修复组件缓存问题 2023-03-21 20:18:41 +08:00
tnt group
98b38640d1 Merge branch 'dev' into dev-commet 2023-01-09 23:24:58 +08:00
tntgroup
89194848de Merge branch 'dev' into dev-commet 2022-12-19 13:25:57 +08:00
tnt group
7c1bcd0605 Merge branch 'dev' into dev-commet 2022-12-12 07:55:10 +08:00
tnt group
c1d98b03a9 Merge branch 'dev' into dev-commet 2022-11-29 17:03:05 +08:00
tnt group
66f4768285 Merge branch 'dev' into dev-commet 2022-11-24 11:04:20 +08:00
tnt group
ec6d8dedec Merge branch 'dev' into dev-commet 2022-11-18 13:21:38 +08:00
tnt group
99d20d99f9 Merge branch 'dev' into dev-commet 2022-11-13 16:21:11 +08:00
tnt group
0106d43467 Merge branch 'dev' into dev-commet 2022-11-07 08:25:07 +08:00
tnt group
231fb9dd29 Merge branch 'dev' into dev-commet 2022-11-03 11:06:18 +08:00
tnt group
f2ae08e62a Merge branch 'dev' into dev-commet 2022-11-01 08:28:43 +08:00
tnt group
e930ca1587 Merge branch 'dev' into dev-commet 2022-10-15 18:37:12 +08:00
tnt group
ddb125656a Merge branch 'dev' into dev-commet 2022-10-14 14:18:18 +08:00
tnt group
35cda43d95 Merge branch 'dev' into dev-commet 2022-10-13 22:19:28 +08:00
tnt group
e3faaad5e0 fix: 修复 eslint 报错(移除多余eslint注释) 2022-10-13 18:41:00 +08:00
tnt group
24ef446fd6 Merge branch 'dev' into dev-commet 2022-10-13 18:09:55 +08:00
tnt group
53b9e03e69 fix: 修复编辑动态请求modal,esc关闭后无法再次打开的问题,并增加取消关闭 2022-10-13 16:33:51 +08:00
196 changed files with 10467 additions and 3867 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ dist
dist-ssr
*.local
.vscode
.idea

View File

@@ -1,4 +1,16 @@
#### 总览
<p align="center">
<a
href="https://www.goviewlink.com?channel=mayun"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
">
<img src="readme/GoViewPro.png" alt="go-view" />
</a>
</p>
<p align="center">
<img src="readme/logo-t-y.png" alt="go-view" />
</p>
@@ -6,6 +18,7 @@
<h4 align="center">开源、精美、便捷的「数据可视化」低代码开发平台</h4>
#### 长期赞助商
<div>
<div align="center" style="column-gap: 20px;">
<a
@@ -20,6 +33,19 @@
<img src="readme/sponsors/ccflow-banner.png" alt="go-view" style="width: 250px;" width="250px" />
</a>
<span> &nbsp;</span>
<a
href="https://fastbee.cn/"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/fb-banner.gif" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<br/>
<br/>
<a
href="https://www.qeasy.cloud/"
target="_blank"
@@ -31,6 +57,42 @@
">
<img src="readme/sponsors/qyy-banner.png" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<span> &nbsp;</span>
<a
href="http://doc.zyplayer.com/#/integrate/zyplayer-doc?utm=goview"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/zyplayer-banner.png" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<br/>
<br/>
<a
href="https://gitee.com/dandiankeji/icampus"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/dandian-banner.png" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<a
href="https://www.mingdao.com?s=utm_88&utm_source=Goview&utm_medium=banner&utm_campaign=gitee&utm_content=IT%E8%B5%8B%E8%83%BD%E4%B8%9A%E5%8A%A1"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/mdy-banner.png" alt="go-view" style="width: 270px;" width="270px"/>
</a>
</div>
</div>
@@ -48,13 +110,13 @@ Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](http
#### 🤯 后端项目看这里!
后端项目 gitee 地址:[https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve)
后端地址(社区实现,仅供参考):
接口说明地址:[https://docs.apipost.cn/...](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3#3e053622-1e76-43f9-a039-756aee822dbb)
其它后端方案地址:
- 【.NET】[https://gitee.com/sun_xiang_yu/go-view-dotnet](https://gitee.com/sun_xiang_yu/go-view-dotnet)
- `JAVA` [https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve) (当前使用)
- `.NET` [https://gitee.com/sun_xiang_yu/go-view-dotnet](https://gitee.com/sun_xiang_yu/go-view-dotnet)
- `NODE` [https://gitee.com/qwdingyu/led](https://gitee.com/qwdingyu/led)
- `Docker 镜像` [https://gitee.com/AHEAD4/go-view-docker](https://gitee.com/AHEAD4/go-view-docker)
- `接口文档`[https://docs.apipost.cn](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3) (不是最新, 以前端代码为准)
#### 整体介绍
@@ -102,7 +164,7 @@ Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](http
| 名称 | 版本 | 名称 | 版本 |
| ------------------- | ----- | ----------- | ------ |
| Vue | 3.2.x | TypeScript4 | 4.6.x |
| Vite | 2.9.x | NaiveUI | 2.27.x |
| Vite | 4.2.x | NaiveUI | 2.34.x |
| ECharts | 5.3.x | Pinia | 2.0.x |
| 详见 `package.json` | 😁 | 🥰 | 🤗 |
@@ -110,7 +172,7 @@ Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](http
| 名称 | 版本 | 名称 | 版本 |
| ---- | ------- | ------- | ----- |
| node | 16.14.x | npm | 8.5.x |
| node | 16.16.x | npm | 8.5.x |
| pnpm | 7.1.x | windows | 11 |
已完成图表:
@@ -151,7 +213,12 @@ Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](http
## 交流群
QQ 群:663629294
<img width="260px" src="readme/go-view-qq.png" alt="QQ群" style="border-radius: 20px" />
QQ 群:881415392
<img width="260px" src="readme/go-view-qq.jpg" alt="QQ群" style="border-radius: 20px" />
## Pro 部分功能展示
体验地址: <a href="https://ai.goviewlink.com/" target="_blank">https://ai.goviewlink.com/</a>
![渲染海报](readme/logo-poster.png)

View File

@@ -1,6 +1,6 @@
{
"name": "go-view",
"version": "1.2.3",
"version": "1.2.9",
"engines": {
"node": ">=12.0"
},
@@ -21,7 +21,7 @@
"@types/keymaster": "^1.6.30",
"@types/lodash": "^4.14.184",
"animate.css": "^4.1.1",
"axios": "^0.27.2",
"axios": "^1.4.0",
"color": "^4.2.3",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
@@ -33,6 +33,7 @@
"highlight.js": "^11.5.0",
"html2canvas": "^1.4.1",
"keymaster": "^1.6.2",
"mitt": "^3.0.0",
"monaco-editor": "^0.33.0",
"naive-ui": "2.34.3",
"pinia": "^2.0.13",
@@ -40,7 +41,7 @@
"three": "^0.145.0",
"vue": "^3.2.31",
"vue-demi": "^0.13.1",
"vue-i18n": "^9.2.2",
"vue-i18n": "9.2.2",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
"vue3-sketch-ruler": "^1.3.3",
@@ -49,14 +50,16 @@
"devDependencies": {
"@commitlint/cli": "^17.0.2",
"@commitlint/config-conventional": "^17.0.2",
"@iconify/types": "^2.0.0",
"@iconify/vue": "^4.1.1",
"@types/node": "^16.11.26",
"@types/three": "^0.144.0",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^1.10.2",
"@vitejs/plugin-vue-jsx": "^1.3.9",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/compiler-sfc": "^3.2.31",
"@vueuse/core": "^7.7.1",
"commitlint": "^17.0.2",
@@ -75,7 +78,7 @@
"sass": "^1.49.11",
"sass-loader": "^12.6.0",
"typescript": "4.6.3",
"vite": "2.9.9",
"vite": "4.3.6",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6",

3230
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

BIN
readme/GoViewPro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

BIN
readme/go-view-qq.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,4 +1,4 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import axios, { AxiosResponse, InternalAxiosRequestConfig, AxiosError } from 'axios'
import { ResultEnum } from "@/enums/httpEnum"
import { ErrorPageNameMap } from "@/enums/pageEnum"
import { redirectErrorPage } from '@/utils'
@@ -9,10 +9,10 @@ const axiosInstance = axios.create({
})
axiosInstance.interceptors.request.use(
(config: AxiosRequestConfig) => {
(config: InternalAxiosRequestConfig) => {
return config
},
(error: AxiosRequestConfig) => {
(error: AxiosError) => {
Promise.reject(error)
}
)
@@ -21,7 +21,7 @@ axiosInstance.interceptors.request.use(
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
const { code } = res.data as { code: number }
if (code === undefined || code === null) return Promise.resolve(res)
if (code === undefined || code === null) return Promise.resolve(res.data)
if (code === ResultEnum.DATA_SUCCESS) return Promise.resolve(res.data)
// 重定向
if (ErrorPageNameMap.get(code)) redirectErrorPage(code)

View File

@@ -163,7 +163,6 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
params = translateStr(params)
// form 类型处理
let formData: FormData = new FormData()
formData.set('default', 'defaultData')
// 类型处理
switch (requestParamsBodyType) {

100
src/api/mock/graph.json Normal file
View File

@@ -0,0 +1,100 @@
{
"nodes": [
{
"id": "0",
"name": "Myriel",
"symbolSize": "@integer(0, 50)",
"x": -266.82776,
"y": 299.6904,
"value": "@integer(0, 50)",
"category": 3
},
{
"id": "1",
"name": "Napoleon",
"symbolSize": "@integer(0, 50)",
"x": -418.08344,
"y": 446.8853,
"value": "@integer(0, 50)",
"category": 5
},
{
"id": "2",
"name": "MlleBaptistine",
"symbolSize": "@integer(0, 50)",
"x": -212.76357,
"y": 245.29176,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "3",
"name": "MmeMagloire",
"symbolSize": "@integer(0, 50)",
"x": -242.82404,
"y": 235.26283,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "4",
"name": "CountessDeLo",
"symbolSize": "@integer(0, 50)",
"x": -379.30386,
"y": 429.06424,
"value": "@integer(0, 50)",
"category": 0
}
],
"links": [
{
"source": "1",
"target": "@integer(2, 4)"
},
{
"source": "2",
"target": "@integer(3, 4)"
},
{
"source": "3",
"target": "@integer(0, 2)"
},
{
"source": "3",
"target": "@integer(0, 1)"
},
{
"source": "4",
"target": "@integer(0, 3)"
}
],
"categories": [
{
"name": "A"
},
{
"name": "B"
},
{
"name": "C"
},
{
"name": "D"
},
{
"name": "E"
},
{
"name": "F"
},
{
"name": "G"
},
{
"name": "H"
},
{
"name": "I"
}
]
}

View File

@@ -19,6 +19,8 @@ export const capsuleUrl = '/mock/capsule'
export const wordCloudUrl = '/mock/wordCloud'
export const treemapUrl = '/mock/treemap'
export const threeEarth01Url = '/mock/threeEarth01Data'
export const sankeyUrl = '/mock/sankey'
export const graphUrl = '/mock/graphData'
const mockObject: MockMethod[] = [
{
@@ -103,6 +105,16 @@ const mockObject: MockMethod[] = [
method: RequestHttpEnum.GET,
response: () => test.threeEarth01Data
},
{
url: sankeyUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchSankey
},
{
url: graphUrl,
method: RequestHttpEnum.GET,
response: () => test.graphData
},
]
export default mockObject

86
src/api/mock/sankey.json Normal file
View File

@@ -0,0 +1,86 @@
{
"label": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "a1"
},
{
"name": "a2"
},
{
"name": "b1"
},
{
"name": "b2"
}
],
"links": [
{
"source": "a",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "a2",
"value": "@integer(0, 10)"
},
{
"source": "b",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "b2",
"value": "@integer(0, 10)"
}
],
"levels": [
{
"depth": 0,
"itemStyle": {
"color": "#decbe4"
},
"lineStyle": {
"color": "source",
"opacity": 0.9
}
},
{
"depth": 1,
"itemStyle": {
"color": "#b3cde3"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
},
{
"depth": 2,
"itemStyle": {
"color": "#ccebc5"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
}
]
}

View File

@@ -2,6 +2,8 @@ import heatmapJson from './heatMapData.json'
import scatterJson from './scatter.json'
import mapJson from './map.json'
import tTreemapJson from './treemap.json'
import sankeyJson from './sankey.json'
import graphDataJson from './graph.json'
export default {
// 单图表
@@ -219,5 +221,19 @@ export default {
'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
}
]
}
},
// 桑基图
fetchSankey: {
code: 0,
status: 200,
msg: '请求成功',
data: sankeyJson
},
// 关系图
graphData: {
code: 0,
status: 200,
msg: '请求成功',
data: graphDataJson
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -257,9 +257,36 @@
<n-switch v-model:value="legend.show" size="small"></n-switch>
</template>
<setting-item-box name="图例文字">
<setting-item>
<setting-item name="颜色">
<n-color-picker size="small" v-model:value="legend.textStyle.color"></n-color-picker>
</setting-item>
<setting-item name="大小">
<n-input-number v-model:value="legend.textStyle.fontSize" :min="1" size="small"></n-input-number>
</setting-item>
</setting-item-box>
<setting-item-box name="图例位置">
<setting-item name="x轴">
<n-select v-model:value="legend.x" size="small" :options="legendConfig.lengendX" />
</setting-item>
<setting-item name="y轴">
<n-select v-model:value="legend.y" size="small" :options="legendConfig.lengendY" />
</setting-item>
</setting-item-box>
<setting-item-box name="图例信息">
<setting-item name="方向">
<n-select v-model:value="legend.orient" size="small" :options="legendConfig.orient" />
</setting-item>
<setting-item name="形状">
<n-select v-model:value="legend.icon" size="small" :options="legendConfig.shape" />
</setting-item>
</setting-item-box>
<setting-item-box name="图例大小">
<setting-item name="宽">
<n-input-number v-model:value="legend.itemWidth" :min="1" size="small"></n-input-number>
</setting-item>
<setting-item name="高">
<n-input-number v-model:value="legend.itemHeight" :min="1" size="small"></n-input-number>
</setting-item>
</setting-item-box>
</collapse-item>
@@ -309,9 +336,9 @@
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { PropType, computed, watch } from 'vue'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import { axisConfig } from '@/packages/chartConfiguration/echarts/index'
import { axisConfig, legendConfig } from '@/packages/chartConfiguration/echarts/index'
import { CollapseItem, SettingItemBox, SettingItem, GlobalSettingPosition } from '@/components/Pages/ChartItemSetting'
import { icon } from '@/plugins'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -360,4 +387,18 @@ const grid = computed(() => {
const visualMap = computed(() => {
return props.optionData.visualMap
})
// 监听legend color颜色改变type = scroll的颜色
watch(() => legend.value && legend.value.textStyle.color, (newVal) => {
if (legend.value && newVal) {
if (!legend.value.pageTextStyle) {
legend.value.pageTextStyle = { color: newVal }
} else {
legend.value.pageTextStyle.color = newVal
}
}
}, {
immediate: true,
deep: true,
})
</script>

View File

@@ -69,6 +69,22 @@
</setting-item>
</setting-item-box>
<!-- 预设滤镜 -->
<div v-if="presetImageList.length" class="preset-filter">
<n-image
class="preset-img"
width="46"
preview-disabled
object-fit="scale-down"
v-for="(item, index) in presetImageList"
:key="index"
:class="{ 'active-preset': item.hueRotate === chartStyles.hueRotate }"
:style="{ filter: `hue-rotate(${item.hueRotate}deg)` }"
:src="item.src"
@click="() => (chartStyles.hueRotate = item.hueRotate)"
></n-image>
</div>
<!-- 混合模式 -->
<setting-item-box v-if="!isCanvas" :alone="true">
<template #name>
@@ -149,10 +165,12 @@
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { ref, PropType } from 'vue'
import { PickCreateComponentType, BlendModeEnumList } from '@/packages/index.d'
import { SettingItemBox, SettingItem, CollapseItem } from '@/components/Pages/ChartItemSetting'
import { icon } from '@/plugins'
import logoImg from '@/assets/logo.png'
import { useDesignStore } from '@/store/modules/designStore/designStore'
const props = defineProps({
isGroup: {
@@ -175,10 +193,48 @@ const { HelpOutlineIcon } = icon.ionicons5
const sliderFormatTooltip = (v: string) => {
return `${(parseFloat(v) * 100).toFixed(0)}%`
}
// 角度格式化
const degFormatTooltip = (v: string) => {
return `${v}deg`
}
// 预设滤镜
interface presetImageData {
index: number
src: string
hueRotate: number
}
const presetImageList = ref([] as presetImageData[])
for (let i = 1; i <= 12; i++) {
presetImageList.value.push({
index: i,
src: logoImg,
hueRotate: i * 30
})
}
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
// 预设滤镜
.preset-filter {
margin: 20px 0 10px 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.preset-img {
margin-bottom: 10px;
padding: 2px;
border-radius: 6px;
transition: 0.2s all;
cursor: pointer;
&:hover {
box-shadow: 0 0 0 2px #66a9c9;
}
}
.active-preset {
box-shadow: 0 0 0 2px #66a9c9;
}
}
</style>

View File

@@ -1,13 +1,13 @@
<template>
<div class="go-Flipper" :class="[flipType, { go: isFlipping }]">
<div class="go-flipper" :class="[flipType, { go: isFlipping }]">
<div class="digital front" :data-front="frontTextFromData"></div>
<div class="digital back" :data-back="backTextFromData"></div>
</div>
</template>
<script lang="ts" setup>
import { ref, PropType, watch } from 'vue'
import { FlipType } from './index'
import { ref, PropType, watch, nextTick } from 'vue'
import { FlipType } from './index'
const props = defineProps({
flipType: {
@@ -43,6 +43,10 @@ const props = defineProps({
backColor: {
type: String,
default: '#000000'
},
borderWidth: {
type: Number,
default: 2
}
})
@@ -50,19 +54,27 @@ const isFlipping = ref(false)
const frontTextFromData = ref(props.count || 0)
const backTextFromData = ref(props.count || 0)
let timeoutID: any = 0
// 翻牌
const flip = (front: string | number, back: string | number) => {
const flip = async (front: string | number, back: string | number) => {
// 如果处于翻转中,则不执行
if (isFlipping.value) return
if (isFlipping.value) {
isFlipping.value = false // 立即结束此次动画
clearTimeout(timeoutID) // 清除上一个计时器任务
await nextTick()
await flip(front, back) // 开始最后一次翻牌任务
return
}
// 设置翻盘前后数据
backTextFromData.value = back
frontTextFromData.value = front
// 设置翻转状态为true
isFlipping.value = true
// 翻牌结束的行为
setTimeout(() => {
timeoutID = setTimeout(() => {
isFlipping.value = false // 设置翻转状态为false
frontTextFromData.value = back
}, props.duration)
@@ -86,6 +98,7 @@ $radius: v-bind('`${props.radius}px`');
$width: v-bind('`${props.width}px`');
$height: v-bind('`${props.height}px`');
$perspective: v-bind('`${props.height * 2}px`');
$borderWidth: v-bind('`${props.borderWidth * 2}px`');
$speed: v-bind('`${props.duration / 1000}s`');
$shadowColor: #000000;
$lineColor: #4a9ef8;
@@ -125,13 +138,12 @@ $lineColor: #4a9ef8;
}
// #endregion
.go-Flipper {
.go-flipper {
display: inline-block;
position: relative;
width: $width;
height: $height;
line-height: $height;
border: solid 1px $backColor;
border-radius: $radius;
background: $frontColor;
font-size: $width;
@@ -139,6 +151,17 @@ $lineColor: #4a9ef8;
box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); // 阴影部分
text-align: center;
// font-family: 'Helvetica Neue';
&::after {
content: '';
position: absolute;
z-index: 10;
left: 0;
top: 0;
right: 0;
bottom: 0;
box-shadow: inset 0 0 $borderWidth 0 $frontColor; // 内测阴影部分
border-radius: $radius;
}
.digital:before,
.digital:after {
@@ -186,11 +209,13 @@ $lineColor: #4a9ef8;
&.down.go .front:before {
transform-origin: 50% 100%;
animation: frontFlipDown $speed ease-in-out both;
box-shadow: 0 -2px 6px rgba($color: $lineColor, $alpha: 0.3);
box-shadow: 0 -2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
&.down.go .back:after {
animation: backFlipDown $speed ease-in-out both;
box-shadow: 0 2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
/*向上翻*/
&.up .front:after {
@@ -208,11 +233,13 @@ $lineColor: #4a9ef8;
&.up.go .front:after {
transform-origin: 50% 0;
animation: frontFlipUp $speed ease-in-out both;
box-shadow: 0 2px 6px rgba($color: $lineColor, $alpha: 0.3);
box-shadow: 0 2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
&.up.go .back:before {
animation: backFlipUp $speed ease-in-out both;
box-shadow: 0 -2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
}
</style>

View File

@@ -12,6 +12,7 @@ export enum DragKeyEnum {
// 不同页面保存操作
export enum SavePageEnum {
CHART = 'SaveChart',
CHART_TO_PREVIEW = 'ChartToPreview',
JSON = 'SaveJSON',
CLOSE = 'close'
}

View File

@@ -12,5 +12,7 @@ export enum StorageEnum {
// 工作台布局配置
GO_CHART_LAYOUT_STORE = 'GO_CHART_LAYOUT',
// 工作台需要保存的数据
GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST'
GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST',
// 用户存储的图片媒体
GO_USER_MEDIA_PHOTOS = 'GO_USER_MEDIA_PHOTOS'
}

View File

@@ -1,122 +1,128 @@
import { ref, toRefs, toRaw, watch } from 'vue'
import type VChart from 'vue-echarts'
import { customizeHttp } from '@/api/http'
import { useChartDataPondFetch } from '@/hooks/'
import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
import { setOption } from '@/packages/public/chart'
// 获取类型
type ChartEditStoreType = typeof useChartEditStore
/**
* setdata 数据监听与更改
* @param targetComponent
* @param useChartEditStore 若直接引会报错,只能动态传递
* @param updateCallback 自定义更新函数
*/
export const useChartDataFetch = (
targetComponent: CreateComponentType,
useChartEditStore: ChartEditStoreType,
updateCallback?: (...args: any) => any
) => {
const vChartRef = ref<typeof VChart | null>(null)
let fetchInterval: any = 0
// 数据池
const { addGlobalDataInterface } = useChartDataPondFetch()
// 组件类型
const { chartFrame } = targetComponent.chartConfig
// eCharts 组件配合 vChart 库更新方式
const echartsUpdateHandle = (dataset: any) => {
if (chartFrame === ChartFrameEnum.ECHARTS) {
if (vChartRef.value) {
setOption(vChartRef.value, { dataset: dataset })
}
}
}
const requestIntervalFn = () => {
const chartEditStore = useChartEditStore()
// 全局数据
const {
requestOriginUrl,
requestIntervalUnit: globalUnit,
requestInterval: globalRequestInterval
} = toRefs(chartEditStore.getRequestGlobalConfig)
// 目标组件
const {
requestDataType,
requestUrl,
requestIntervalUnit: targetUnit,
requestInterval: targetInterval
} = toRefs(targetComponent.request)
// 非请求类型
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
try {
// 处理地址
// @ts-ignore
if (requestUrl?.value) {
// requestOriginUrl 允许为空
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
clearInterval(fetchInterval)
const fetchFn = async () => {
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
if (res) {
try {
const filter = targetComponent.filter
echartsUpdateHandle(newFunctionHandle(res?.data, res, filter))
// 更新回调函数
if (updateCallback) {
updateCallback(newFunctionHandle(res?.data, res, filter))
}
} catch (error) {
console.error(error)
}
}
}
// 普通初始化与组件交互处理监听
watch(
() => targetComponent.request,
() => {
fetchFn()
},
{
immediate: true,
deep: true
}
)
// 定时时间
const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
// 单位
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
// 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
}
// eslint-disable-next-line no-empty
} catch (error) {
console.log(error)
}
}
if (isPreview()) {
// 判断是否是数据池类型
targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
: requestIntervalFn()
}
return { vChartRef }
}
import { ref, toRefs, toRaw, watch } from 'vue'
import type VChart from 'vue-echarts'
import { customizeHttp } from '@/api/http'
import { useChartDataPondFetch } from '@/hooks/'
import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
import { setOption } from '@/packages/public/chart'
// 获取类型
type ChartEditStoreType = typeof useChartEditStore
/**
* setdata 数据监听与更改
* @param targetComponent
* @param useChartEditStore 若直接引会报错,只能动态传递
* @param updateCallback 自定义更新函数
*/
export const useChartDataFetch = (
targetComponent: CreateComponentType,
useChartEditStore: ChartEditStoreType,
updateCallback?: (...args: any) => any
) => {
const vChartRef = ref<typeof VChart | null>(null)
let fetchInterval: any = 0
// 数据池
const { addGlobalDataInterface } = useChartDataPondFetch()
// 组件类型
const { chartFrame } = targetComponent.chartConfig
// eCharts 组件配合 vChart 库更新方式
const echartsUpdateHandle = (dataset: any) => {
if (chartFrame === ChartFrameEnum.ECHARTS) {
if (vChartRef.value) {
setOption(vChartRef.value, { dataset: dataset })
}
}
}
const requestIntervalFn = () => {
const chartEditStore = useChartEditStore()
// 全局数据
const {
requestOriginUrl,
requestIntervalUnit: globalUnit,
requestInterval: globalRequestInterval
} = toRefs(chartEditStore.getRequestGlobalConfig)
// 目标组件
const {
requestDataType,
requestUrl,
requestIntervalUnit: targetUnit,
requestInterval: targetInterval
} = toRefs(targetComponent.request)
// 非请求类型
if (requestDataType.value !== RequestDataTypeEnum.AJAX) return
try {
// 处理地址
// @ts-ignore
if (requestUrl?.value) {
// requestOriginUrl 允许为空
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
clearInterval(fetchInterval)
const fetchFn = async () => {
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
if (res) {
try {
const filter = targetComponent.filter
const { data } = res
echartsUpdateHandle(newFunctionHandle(data, res, filter))
// 更新回调函数
if (updateCallback) {
updateCallback(newFunctionHandle(data, res, filter))
}
} catch (error) {
console.error(error)
}
}
}
// 普通初始化与组件交互处理监听
watch(
() => targetComponent.request.requestParams,
() => {
fetchFn()
},
{
immediate: true,
deep: true
}
)
// 定时时间
const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
// 单位
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
// 开启轮询
if (time) {
fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
} else {
fetchFn()
}
}
// eslint-disable-next-line no-empty
} catch (error) {
console.log(error)
}
}
if (isPreview()) {
targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
: requestIntervalFn()
} else {
requestIntervalFn()
}
return { vChartRef }
}

View File

@@ -1,4 +1,4 @@
import { toRaw } from 'vue'
import { toRaw, watch, computed, ComputedRef } from 'vue'
import { customizeHttp } from '@/api/http'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -20,7 +20,7 @@ const mittDataPondMap = new Map<string, DataPondMapType[]>()
// 创建单个数据项轮询接口
const newPondItemInterval = (
requestGlobalConfig: RequestGlobalConfigType,
requestDataPondItem: RequestDataPondItemType,
requestDataPondItem: ComputedRef<RequestDataPondItemType>,
dataPondMapItem?: DataPondMapType[]
) => {
if (!dataPondMapItem) return
@@ -31,8 +31,7 @@ const newPondItemInterval = (
// 请求
const fetchFn = async () => {
try {
const res = await customizeHttp(toRaw(requestDataPondItem.dataPondRequestConfig), toRaw(requestGlobalConfig))
const res = await customizeHttp(toRaw(requestDataPondItem.value.dataPondRequestConfig), toRaw(requestGlobalConfig))
if (res) {
try {
// 遍历更新回调函数
@@ -49,19 +48,32 @@ const newPondItemInterval = (
}
}
watch(
() => requestDataPondItem.value.dataPondRequestConfig.requestParams.Params,
() => {
fetchFn()
},
{
immediate: false,
deep: true
}
)
// 立即调用
fetchFn()
const targetInterval = requestDataPondItem.dataPondRequestConfig.requestInterval
const targetUnit = requestDataPondItem.dataPondRequestConfig.requestIntervalUnit
const targetInterval = requestDataPondItem.value.dataPondRequestConfig.requestInterval
const targetUnit = requestDataPondItem.value.dataPondRequestConfig.requestIntervalUnit
const globalRequestInterval = requestGlobalConfig.requestInterval
const globalUnit = requestGlobalConfig.requestIntervalUnit
// 定时时间
const time = targetInterval ? targetInterval : globalRequestInterval
const time = targetInterval ? targetInterval : globalRequestInterval
// 单位
const unit = targetInterval ? targetUnit : globalUnit
const unit = targetInterval ? targetUnit : globalUnit
// 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
}
@@ -96,13 +108,16 @@ export const useChartDataPondFetch = () => {
}
// 初始化数据池
const initDataPond = (requestGlobalConfig: RequestGlobalConfigType) => {
const { requestDataPond } = requestGlobalConfig
const initDataPond = (useChartEditStore: ChartEditStoreType) => {
const { requestGlobalConfig } = useChartEditStore()
const chartEditStore = useChartEditStore()
// 根据 mapId 查找对应的数据池配置
for (let pondKey of mittDataPondMap.keys()) {
const requestDataPondItem = requestDataPond.find(item => item.dataPondId === pondKey)
const requestDataPondItem = computed(() => {
return requestGlobalConfig.requestDataPond.find(item => item.dataPondId === pondKey)
}) as ComputedRef<RequestDataPondItemType>
if (requestDataPondItem) {
newPondItemInterval(requestGlobalConfig, requestDataPondItem, mittDataPondMap.get(pondKey))
newPondItemInterval(chartEditStore.requestGlobalConfig, requestDataPondItem, mittDataPondMap.get(pondKey))
}
}
}

View File

@@ -1,4 +1,5 @@
import { toRefs } from 'vue'
import { isPreview } from '@/utils'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -12,6 +13,7 @@ export const useChartInteract = (
param: { [T: string]: any },
interactEventOn: string
) => {
if (!isPreview()) return
const chartEditStore = useChartEditStore()
const { interactEvents } = chartConfig.events
const fnOnEvent = interactEvents.filter(item => {
@@ -20,20 +22,37 @@ export const useChartInteract = (
if (fnOnEvent.length === 0) return
fnOnEvent.forEach(item => {
const index = chartEditStore.fetchTargetIndex(item.interactComponentId)
if (index === -1) return
const { Params, Header } = toRefs(chartEditStore.componentList[index].request.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (Params.value[key]) {
Params.value[key] = param[item.interactFn[key]]
}
if (Header.value[key]) {
Header.value[key] = param[item.interactFn[key]]
}
})
const globalConfigPindAprndex = chartEditStore.requestGlobalConfig.requestDataPond.findIndex(cItem =>
cItem.dataPondId === item.interactComponentId
)
if (globalConfigPindAprndex !== -1) {
const { Params, Header } = toRefs(chartEditStore.requestGlobalConfig.requestDataPond[globalConfigPindAprndex].dataPondRequestConfig.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (key in Params.value) {
Params.value[key] = param[item.interactFn[key]]
}
if (key in Header.value) {
Header.value[key] = param[item.interactFn[key]]
}
})
} else {
const index = chartEditStore.fetchTargetIndex(item.interactComponentId)
if (index === -1) return
const { Params, Header } = toRefs(chartEditStore.componentList[index].request.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (key in Params.value) {
Params.value[key] = param[item.interactFn[key]]
}
if (key in Header.value) {
Header.value[key] = param[item.interactFn[key]]
}
})
}
})
}
// 联动事件触发的 type 变更时,清除当前绑定内容
export const clearInteractEvent = (chartConfig: CreateComponentType) => {

View File

@@ -48,10 +48,10 @@ export const useLifeHandler = (chartConfig: CreateComponentType | CreateComponen
try {
return new Function(`
return (
async function(mouseEvent){
async function(components,mouseEvent){
${fnStr}
}
)`)()
)`)().bind(undefined,components)
} catch (error) {
console.error(error)
}

View File

@@ -1,218 +1,218 @@
import throttle from 'lodash/throttle'
// 拆出来是为了更好的分离单独复用
// * 屏幕缩放适配(两边留白)
export const usePreviewFitScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
// 当前屏幕宽高比
const currentRate = parseFloat(
(window.innerWidth / window.innerHeight).toFixed(5)
)
if (scaleDom) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
} else {
// 表示更高
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
}
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * X轴撑满Y轴滚动条
export const usePreviewScrollYScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * Y轴撑满X轴滚动条
export const usePreviewScrollXScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
height: 1,
width: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * 变形内容,宽高铺满
export const usePreviewFullScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat((window.innerWidth / width).toFixed(5))
scale.height = parseFloat((window.innerHeight / height).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
import throttle from 'lodash/throttle'
// 拆出来是为了更好的分离单独复用
// * 屏幕缩放适配(两边留白)
export const usePreviewFitScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
// 当前屏幕宽高比
const currentRate = parseFloat(
(window.innerWidth / window.innerHeight).toFixed(5)
)
if (scaleDom) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
} else {
// 表示更高
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
}
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * X轴撑满Y轴滚动条
export const usePreviewScrollYScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * Y轴撑满X轴滚动条
export const usePreviewScrollXScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
height: 1,
width: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * 变形内容,宽高铺满
export const usePreviewFullScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat((window.innerWidth / width).toFixed(5))
scale.height = parseFloat((window.innerHeight / height).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}

View File

@@ -1,5 +1,5 @@
export default {
create_btn: 'Creat',
create_btn: 'Create',
create_tip: 'Please select a content for development',
project: 'Project',
my: 'My',

View File

@@ -1,13 +1,9 @@
<template>
<router-view>
<template #default="{ Component, route }">
<component
v-if="route.noKeepAlive"
:is="Component"
:key="route.fullPath"
></component>
<component v-if="route.meta.noKeepAlive" :is="Component"></component>
<keep-alive v-else>
<component :is="Component" :key="route.fullPath"></component>
<component :is="Component"></component>
</keep-alive>
</template>
</router-view>

View File

@@ -1,14 +1,14 @@
<template>
<router-view #default="{ Component, route }">
<transition name="fade" mode="out-in" appear>
<component
v-if="route.noKeepAlive"
:is="Component"
:key="route.fullPath"
></component>
<keep-alive v-else>
<component :is="Component" :key="route.fullPath"></component>
</keep-alive>
</transition>
</router-view>
</template>
<template>
<router-view #default="{ Component, route }">
<transition name="fade" mode="out-in" appear>
<component
v-if="route.meta.noKeepAlive"
:is="Component"
:key="route.fullPath"
></component>
<keep-alive v-else>
<component :is="Component" :key="route.fullPath"></component>
</keep-alive>
</transition>
</router-view>
</template>

View File

@@ -1,3 +1,4 @@
export * from './axis'
export * from './line'
export * from './label'
export * from './label'
export * from './legend'

View File

@@ -0,0 +1,70 @@
export const legendConfig = {
// X轴位置
lengendX: [
{
label: '靠左',
value: 'left'
},
{
label: '居中',
value: 'center'
},
{
label: '靠右',
value: 'right'
}
],
// y轴位置
lengendY: [
{
label: '靠上',
value: 'top'
},
{
label: '居中',
value: 'center'
},
{
label: '靠下',
value: 'bottom'
}
],
// 排列方向
orient: [
{
label: '水平',
value: 'horizontal'
},
{
label: '垂直',
value: 'vertical'
}
],
// 形状
shape: [
{
label: '圆形',
value: 'circle'
},
{
label: '方形',
value: 'rect'
},
{
label: '圆角方形',
value: 'roundRect'
},
{
label: '三角形',
value: 'triangle'
},
{
label: '钢笔形',
value: 'pin'
},
{
label: '箭头形',
value: 'arrow'
}
]
}

View File

@@ -1,15 +1,8 @@
<template>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()"
:update-options="{
replaceMerge: replaceMergeArr
}"
autoresize
></v-chart>
}" autoresize></v-chart>
</template>
<script setup lang="ts">
@@ -27,6 +20,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import isObject from 'lodash/isObject'
import cloneDeep from 'lodash/cloneDeep'
const props = defineProps({
themeSetting: {
@@ -61,11 +55,23 @@ watch(
if (!isObject(newData) || !('dimensions' in newData)) return
if (Array.isArray(newData?.dimensions)) {
const seriesArr = []
for (let i = 0; i < newData.dimensions.length - 1; i++) {
seriesArr.push(seriesItem)
// 对oldData进行判断防止传入错误数据之后对旧维度判断产生干扰
// 此处计算的是dimensions的Y轴维度若是dimensions.length为0或1则默认为1排除X轴维度干扰
const oldDimensions = Array.isArray(oldData?.dimensions)&&oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1;
const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1;
const dimensionsGap = newDimensions - oldDimensions;
if (dimensionsGap < 0) {
props.chartConfig.option.series.splice(newDimensions - 1)
} else if (dimensionsGap > 0) {
if(!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length ) {
props.chartConfig.option.series=[]
}
for (let i = 0; i < dimensionsGap; i++) {
seriesArr.push(cloneDeep(seriesItem))
}
props.chartConfig.option.series.push(...seriesArr)
}
replaceMergeArr.value = ['series']
props.chartConfig.option.series = seriesArr
nextTick(() => {
replaceMergeArr.value = []
})

View File

@@ -26,6 +26,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import isObject from 'lodash/isObject'
import cloneDeep from 'lodash/cloneDeep'
const props = defineProps({
themeSetting: {
@@ -61,7 +62,7 @@ watch(
if (Array.isArray(newData?.dimensions)) {
const seriesArr = []
for (let i = 0; i < newData.dimensions.length - 1; i++) {
seriesArr.push(seriesItem)
seriesArr.push(cloneDeep(seriesItem))
}
replaceMergeArr.value = ['series']
props.chartConfig.option.series = seriesArr

View File

@@ -0,0 +1,75 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { BarLineConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
// 柱状折线组合图 分别定义series
// 写死name可以定义legend显示的名称
export const barSeriesItem = {
type: 'bar',
barWidth: 15,
label: {
show: true,
position: 'top',
color: '#fff',
fontSize: 12
},
itemStyle: {
color: null,
borderRadius: 2
}
}
export const lineSeriesItem = {
type: 'line',
symbol: 'circle',
label: {
show: true,
position: 'top',
color: '#fff',
fontSize: 12
},
symbolSize: 5, //设定实心点的大小
itemStyle: {
color: '#FFE47A',
borderWidth: 1
},
lineStyle: {
type: 'solid',
width: 3,
color: null
}
}
export const option = {
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
show: true,
type: 'shadow'
}
},
legend: {
data: null
},
xAxis: {
show: true,
type: 'category'
},
yAxis: {
show: true,
type: 'value'
},
dataset: { ...dataJson },
series: [barSeriesItem, lineSeriesItem]
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = BarLineConfig.key
public chartConfig = cloneDeep(BarLineConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@@ -0,0 +1,93 @@
<template>
<!-- Echarts 全局设置 -->
<global-setting :optionData="optionData"></global-setting>
<CollapseItem
v-for="(item, index) in seriesList"
:key="index"
:name="`${item.type == 'bar' ? '柱状图' : '折线图'}`"
:expanded="true"
>
<SettingItemBox name="图形" v-if="item.type == 'bar'">
<SettingItem name="宽度">
<n-input-number
v-model:value="item.barWidth"
:min="1"
:max="100"
size="small"
placeholder="自动计算"
></n-input-number>
</SettingItem>
<SettingItem name="圆角">
<n-input-number v-model:value="item.itemStyle.borderRadius" :min="0" size="small"></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="线条" v-if="item.type == 'line'">
<SettingItem name="宽度">
<n-input-number
v-model:value="item.lineStyle.width"
:min="1"
:max="100"
size="small"
placeholder="自动计算"
></n-input-number>
</SettingItem>
<SettingItem name="类型">
<n-select v-model:value="item.lineStyle.type" size="small" :options="lineConf.lineStyle.type"></n-select>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="实心点" v-if="item.type == 'line'">
<SettingItem name="大小">
<n-input-number
v-model:value="item.symbolSize"
:min="1"
:max="100"
size="small"
placeholder="自动计算"
></n-input-number>
</SettingItem>
</SettingItemBox>
<setting-item-box name="标签">
<setting-item>
<n-space>
<n-switch v-model:value="item.label.show" size="small" />
<n-text>展示标签</n-text>
</n-space>
</setting-item>
<setting-item name="大小">
<n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number>
</setting-item>
<setting-item name="tip颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker>
</setting-item>
<setting-item name="位置">
<n-select
v-model:value="item.label.position"
:options="[
{ label: 'top', value: 'top' },
{ label: 'left', value: 'left' },
{ label: 'right', value: 'right' },
{ label: 'bottom', value: 'bottom' }
]"
/>
</setting-item>
</setting-item-box>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { lineConf } from '@/packages/chartConfiguration/echarts'
import { GlobalThemeJsonType } from '@/settings/chartThemes'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const seriesList = computed(() => {
return props.optionData.series
})
</script>

View File

@@ -0,0 +1,40 @@
{
"dimensions": ["product", "data1", "data2"],
"source": [
{
"product": "1月",
"data1": 104,
"data2": 30
},
{
"product": "2月",
"data1": 56,
"data2": 56
},
{
"product": "3月",
"data1": 136,
"data2": 36
},
{
"product": "4月",
"data1": 86,
"data2": 6
},
{
"product": "5月",
"data1": 98,
"data2": 10
},
{
"product": "6月",
"data1": 86,
"data2": 70
},
{
"product": "7月",
"data1": 77,
"data2": 57
}
]
}

View File

@@ -0,0 +1,16 @@
// 公共类型声明
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
// 当前[信息模块]分类声明
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
export const BarLineConfig: ConfigType = {
key: 'BarLine',
chartKey: 'VBarLine',
conKey: 'VCBarLine',
title: '柱状图 & 折线图',
category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.ECHARTS,
image: 'bar_line.png'
}

View File

@@ -0,0 +1,73 @@
<template>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
autoresize
></v-chart>
</template>
<script setup lang="ts">
import { ref, computed, watch, PropType, nextTick } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
//引入柱状图 折线图
import { BarChart, LineChart } from 'echarts/charts'
import config, { includes, barSeriesItem, lineSeriesItem } from './config'
import { mergeTheme } from '@/packages/public/chart'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, BarChart, LineChart, GridComponent, TooltipComponent, LegendComponent])
const replaceMergeArr = ref<string[]>()
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
watch(
() => props.chartConfig.option.dataset,
(newData, oldData) => {
if (newData.dimensions.length !== oldData.dimensions.length) {
const seriesArr = []
for (let i = 0; i < newData.dimensions.length - 1; i++) {
seriesArr.push(barSeriesItem, lineSeriesItem)
}
replaceMergeArr.value = ['series']
props.chartConfig.option.series = seriesArr
nextTick(() => {
replaceMergeArr.value = []
})
}
},
{
deep: false
}
)
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore)
</script>

View File

@@ -1,5 +1,6 @@
import { BarCommonConfig } from './BarCommon/index'
import { BarCrossrangeConfig } from './BarCrossrange/index'
import { CapsuleChartConfig } from './CapsuleChart/index'
export default [BarCommonConfig, BarCrossrangeConfig, CapsuleChartConfig]
import { BarCommonConfig } from './BarCommon/index'
import { BarCrossrangeConfig } from './BarCrossrange/index'
import { CapsuleChartConfig } from './CapsuleChart/index'
import { BarLineConfig } from './BarLine/index'
export default [BarCommonConfig, BarCrossrangeConfig, BarLineConfig, CapsuleChartConfig]

View File

@@ -33,6 +33,10 @@ export const option = {
width: 3,
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,

View File

@@ -16,7 +16,8 @@ export enum ThemeEnum {
MACARON = 'macaron',
BLUE = 'blue',
DARKBLUE = 'darkblue',
WINE = 'wine'
WINE = 'wine',
WEIXIN = 'tileLayer'
}
export enum LangEnum {

View File

@@ -134,6 +134,10 @@ const themeOptions = [
{
value: ThemeEnum.WINE,
label: '酱籽'
},
{
value: ThemeEnum.WEIXIN,
label: '卫星'
}
]

View File

@@ -8,7 +8,7 @@ import AMapLoader from '@amap/amap-jsapi-loader'
import { CreateComponentType } from '@/packages/index.d'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { MarkerEnum } from './config'
import { MarkerEnum, ThemeEnum } from './config'
import { isArray } from '@/utils'
const props = defineProps({
@@ -51,7 +51,6 @@ const initMap = (newData: any) => {
resizeEnable: true,
zoom: amapZindex.value, // 地图显示的缩放级别
center: [amapLon.value, amapLat.value],
mapStyle: `amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}`, //自定义地图的显示样式
lang: lang.value,
features: features.value,
pitch: pitch.value, // 地图俯仰角度,有效范围 0 度- 83 度
@@ -60,6 +59,14 @@ const initMap = (newData: any) => {
willReadFrequently: true
})
dataHandle(props.chartConfig.option.dataset)
let satellite = new AMap.TileLayer.Satellite()
let roadNet = new AMap.TileLayer.RoadNet()
if (newData.amapStyleKey === ThemeEnum.WEIXIN) {
mapIns.add([satellite, roadNet])
} else {
mapIns.remove([satellite, roadNet])
mapIns.setMapStyle(`amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}`)
}
})
.catch(e => {})
}

View File

@@ -11,7 +11,10 @@ export const option = {
dataset: dataJson,
mapRegion: {
adcode: 'china',
showHainanIsLands: true
showHainanIsLands: true,
enter: false,
backSize: 20,
backColor: '#ffffff'
},
tooltip: {
show: true,
@@ -84,7 +87,10 @@ export const option = {
shadowColor: '#E1FFFF',
shadowBlur: 10
},
data: []
data: [],
encode: {
value: 2
}
},
{
name: '区域',
@@ -100,19 +106,19 @@ export const option = {
borderColor: 'rgba(147, 235, 248, 0.8)',
textStyle: {
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
}
},
label: {
show: false,
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
},
emphasis: {
disabled: false,
label: {
color: '#FFFFFF',
fontSize: 12,
fontSize: 12
},
itemStyle: {
areaColor: '#389BB7',
@@ -145,6 +151,26 @@ export const option = {
shadowOffsetY: 2,
shadowBlur: 10
}
},
{
type: 'lines',
zlevel: 2,
effect: {
show: true,
period: 4, //箭头指向速度,值越小速度越快
trailLength: 0.4, //特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'arrow', //箭头图标
symbolSize: 7 //图标大小
},
lineStyle: {
normal: {
color: '#4fb6d2',
width: 1, //线条宽度
opacity: 0.1, //尾迹线条透明度
curveness: 0.3 //尾迹线条曲直度
}
},
data: []
}
]
}

View File

@@ -69,11 +69,7 @@
</n-space>
</SettingItem>
<SettingItem name="字体颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="seriesList[1].label.color"
></n-color-picker>
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[1].label.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
@@ -129,7 +125,7 @@
></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="悬浮弹窗">
<SettingItem name="显示">
<n-space>
@@ -180,6 +176,22 @@
<SettingItem>
<n-checkbox v-model:checked="mapRegion.showHainanIsLands" size="small">显示南海群岛</n-checkbox>
</SettingItem>
<SettingItem v-if="seriesList[2]">
<n-checkbox v-model:checked="mapRegion.enter" size="small">点击进入下级</n-checkbox>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="返回图标" v-if="mapRegion.enter">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="mapRegion.backColor"></n-color-picker>
</SettingItem>
<SettingItem name="大小">
<n-input-number
v-model:value="mapRegion.backSize"
:min="1"
size="small"
placeholder="请输入字体大小"
></n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
<CollapseItem name="标记" :expanded="true">
@@ -191,7 +203,7 @@
<n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="文本">
<SettingItem name="显示">
<n-space>
@@ -223,6 +235,47 @@
</SettingItem>
</SettingItemBox>
</CollapseItem>
<CollapseItem v-if="seriesList[2]" name="飞线" :expanded="true">
<SettingItemBox name="箭头">
<SettingItem name="速度">
<n-tooltip trigger="hover">
<template #trigger>
<n-input-number v-model:value="seriesList[2].effect.period" size="small" :min="0"></n-input-number>
</template>
值越小速度越快
</n-tooltip>
</SettingItem>
<SettingItem name="尾迹">
<n-tooltip trigger="hover">
<template #trigger>
<n-input-number
v-model:value="seriesList[2].effect.trailLength"
size="small"
:min="0"
:max="1"
></n-input-number>
</template>
特效尾迹长度[0,1]值越大尾迹越长重
</n-tooltip>
</SettingItem>
<SettingItem name="大小">
<n-input-number v-model:value="seriesList[2].effect.symbolSize" size="small" :min="0"></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="配置">
<SettingItem name="颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="seriesList[2].lineStyle.normal.color"
></n-color-picker>
</SettingItem>
<SettingItem name="宽度">
<n-input-number v-model:value="seriesList[2].lineStyle.normal.width" size="small" :min="1"></n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">

View File

@@ -21,6 +21,32 @@
"value": [126.642464, 45.756967, 101]
}
],
"line": [
{
"coords": [
[113.665412, 34.757975],
[116.405285, 39.904989]
]
},
{
"coords": [
[101.778916, 36.623178],
[116.405285, 39.904989]
]
},
{
"coords": [
[106.278179, 38.46637],
[116.405285, 39.904989]
]
},
{
"coords": [
[126.642464, 45.756967],
[116.405285, 39.904989]
]
}
],
"map": [
{
"name": "北京市",

View File

@@ -1,156 +1,256 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option.value" :manual-update="isPreview()" autoresize>
</v-chart>
</template>
<script setup lang="ts">
import { PropType, reactive, watch, ref, nextTick } from 'vue'
import config, { includes } from './config'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use, registerMap } from 'echarts/core'
import { EffectScatterChart, MapChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import { useChartDataFetch } from '@/hooks'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([
MapChart,
DatasetComponent,
CanvasRenderer,
GridComponent,
TooltipComponent,
GeoComponent,
EffectScatterChart,
VisualMapComponent
])
const option = reactive({
value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const vChartRef = ref<typeof VChart>()
//动态获取json注册地图
const getGeojson = (regionId: string) => {
return new Promise<boolean>(resolve => {
import(`./mapGeojson/${regionId}.json`).then(data => {
registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} })
resolve(true)
})
})
}
//异步时先注册空的 保证初始化不报错
registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
// 进行更换初始化地图 如果为china 单独处理
const registerMapInitAsync = async () => {
await nextTick()
const adCode = `${props.chartConfig.option.mapRegion.adcode}`;
if (adCode !== 'china') {
await getGeojson(adCode)
} else {
await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
}
vEchartsSetOption()
}
registerMapInitAsync()
// 手动触发渲染
const vEchartsSetOption = () => {
option.value = props.chartConfig.option
setOption(vChartRef.value, props.chartConfig.option)
}
// 更新数据处理
const dataSetHandle = async (dataset: any) => {
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'effectScatter' && dataset.point) item.data = dataset.point
else if (item.type === 'map' && dataset.map) item.data = dataset.map
})
if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces
isPreview() && vEchartsSetOption()
}
// 处理海南群岛
const hainanLandsHandle = async (newData: boolean) => {
if (newData) {
await getGeojson('china')
} else {
registerMap('china', { geoJSON: mapJsonWithoutHainanIsLands as any, specialAreas: {} })
}
}
//监听 dataset 数据发生变化
watch(
() => props.chartConfig.option.dataset,
newData => {
dataSetHandle(newData)
},
{
immediate: true,
deep: false
}
)
//监听是否显示南海群岛
watch(
() => props.chartConfig.option.mapRegion.showHainanIsLands,
async newData => {
try {
await hainanLandsHandle(newData)
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
//监听地图展示区域发生变化
watch(
() => `${props.chartConfig.option.mapRegion.adcode}`,
async newData => {
try {
await getGeojson(newData)
props.chartConfig.option.geo.map = newData
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'map') item.map = newData
})
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
// 预览
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
dataSetHandle(newData)
})
</script>
<template>
<div>
<div class="back-icon" v-if="(enter && levelHistory.length !== 0) || (enter && !isPreview())" @click="backLevel">
<n-icon :color="backColor" :size="backSize * 1.1">
<ArrowBackIcon />
</n-icon>
<span
:style="{
'font-weight': 200,
color: backColor,
'font-size': `${backSize}px`
}"
>
返回上级
</span>
</div>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option.value"
:manual-update="isPreview()"
autoresize
@click="chartPEvents"
>
</v-chart>
</div>
</template>
<script setup lang="ts">
import { PropType, reactive, watch, ref, nextTick, toRefs } from 'vue'
import config, { includes } from './config'
import VChart from 'vue-echarts'
import { icon } from '@/plugins'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use, registerMap } from 'echarts/core'
import { EffectScatterChart, MapChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import { useChartDataFetch } from '@/hooks'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
import mapChinaJson from './mapGeojson/china.json'
import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const { ArrowBackIcon } = icon.ionicons5
let levelHistory: any = ref([])
const { backColor, backSize, enter } = toRefs(props.chartConfig.option.mapRegion)
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([
MapChart,
DatasetComponent,
CanvasRenderer,
GridComponent,
TooltipComponent,
GeoComponent,
EffectScatterChart,
VisualMapComponent
])
const option = reactive({
value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const vChartRef = ref<typeof VChart>()
//动态获取json注册地图
const getGeojson = (regionId: string) => {
return new Promise<boolean>(resolve => {
import(`./mapGeojson/${regionId}.json`).then(data => {
registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} })
resolve(true)
})
})
}
//异步时先注册空的 保证初始化不报错
registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
// 进行更换初始化地图 如果为china 单独处理
const registerMapInitAsync = async () => {
await nextTick()
const adCode = `${props.chartConfig.option.mapRegion.adcode}`
if (adCode !== 'china') {
await getGeojson(adCode)
} else {
await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
}
vEchartsSetOption()
}
registerMapInitAsync()
// 手动触发渲染
const vEchartsSetOption = () => {
option.value = props.chartConfig.option
setOption(vChartRef.value, props.chartConfig.option)
}
// 更新数据处理
const dataSetHandle = async (dataset: any) => {
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'effectScatter' && dataset.point) item.data = dataset.point
else if (item.type === 'lines' && dataset.line) {
item.data = dataset.line.map((it: any) => {
return {
...it,
lineStyle: {
color: props.chartConfig.option.series[2].lineStyle.normal.color
}
}
})
} else if (item.type === 'map' && dataset.map) item.data = dataset.map
})
if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces
isPreview() && vEchartsSetOption()
}
// 处理海南群岛
const hainanLandsHandle = async (newData: boolean) => {
if (newData) {
await getGeojson('china')
} else {
registerMap('china', { geoJSON: mapJsonWithoutHainanIsLands as any, specialAreas: {} })
}
}
// 点击区域
const chartPEvents = (e: any) => {
if (e.seriesType !== 'map') return
if (!props.chartConfig.option.mapRegion.enter) {
return
}
mapChinaJson.features.forEach(item => {
var pattern = new RegExp(e.name)
if (pattern.test(item.properties.name)) {
let code = String(item.properties.adcode)
levelHistory.value.push(code)
checkOrMap(code)
}
})
}
// 返回上一级
const backLevel = () => {
levelHistory.value = []
if (levelHistory.value.length > 1) {
levelHistory.value.pop()
const code = levelHistory[levelHistory.value.length - 1]
checkOrMap(code)
} else {
checkOrMap('china')
}
}
// 切换地图
const checkOrMap = async (newData: string) => {
await getGeojson(newData)
props.chartConfig.option.geo.map = newData
props.chartConfig.option.series.forEach((item: any) => {
if (item.type === 'map') item.map = newData
})
vEchartsSetOption()
}
//监听 dataset 数据发生变化
watch(
() => props.chartConfig.option.dataset,
newData => {
dataSetHandle(newData)
},
{
immediate: true,
deep: false
}
)
// 监听线的颜色
if (props.chartConfig.option.series[2] && !isPreview()) {
watch(
() => props.chartConfig.option.series[2].lineStyle.normal.color,
() => {
dataSetHandle(props.chartConfig.option.dataset)
},
{
deep: false
}
)
}
//监听是否显示南海群岛
if (!isPreview()) {
watch(
() => props.chartConfig.option.mapRegion.showHainanIsLands,
async newData => {
try {
await hainanLandsHandle(newData)
vEchartsSetOption()
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
}
//监听地图展示区域发生变化
watch(
() => `${props.chartConfig.option.mapRegion.adcode}`,
newData => {
try {
checkOrMap(newData)
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
// 预览
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
dataSetHandle(newData)
})
</script>
<style scope lang="scss">
.back-icon {
z-index: 50;
cursor: pointer;
position: absolute;
display: flex;
align-items: center;
top: 0;
left: 0;
gap: 2px;
}
</style>

View File

@@ -0,0 +1,91 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { DialConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
export const includes = []
const option = {
backgroundColor: '#0E1327',
dataset:70,
series: [{
type: "gauge",
data: [{
value: 70,
itemStyle: { // 指针样式
color: '#2AF4FF'
}
}],
min: 0, //最小刻度
max: 100, //最大刻度
splitNumber: 10, //刻度数量
center: ['50%', '55%'],
radius: '80%',
axisLine: {
lineStyle: {
color: [
[0, 'rgba(0,212,230,0.5)'],
[1, 'rgba(28,128,245,0)']
],
width: 170
}
},
axisLabel: { // 文字样式
color: '#eee',
fontSize: 14,
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
detail: {
show: false,
},
pointer: {
length: '80%',
width: 4
},
animationDuration: 2000,
},
{
name: '外部刻度',
type: 'gauge',
center: ['50%', '55%'],
radius: '90%',
axisLine: {
show: true,
lineStyle: {
width: 25,
color: [ // 表盘外部颜色
[0, '#1369E380'],
[1, '#1369E380']
],
}
},
axisLabel: {
show:false,
},
axisTick: {
splitNumber: 5,
lineStyle: { //刻度颜色
color: '#42E5FB',
width: 2,
},
},
splitLine: {
length: 15,
lineStyle: {
color: '#42E5FB',
}
},
},
]
};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key: string = DialConfig.key
public chartConfig = cloneDeep(DialConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@@ -0,0 +1,84 @@
<template>
<!-- 遍历 seriesList -->
<CollapseItem :name="`圆环`" :expanded="true">
<SettingItemBox name="数据">
<SettingItem name="数值">
<n-input-number v-model:value="config.dataset" :min="dialConfig.min" :max="dialConfig.max" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- Echarts 全局设置 -->
<!-- 表盘刻度字体 -->
<SettingItemBox name="字体">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.axisLabel.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="dialConfig.axisLabel.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 表盘 -->
<SettingItemBox name="表盘外部">
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisLine.lineStyle.color[1][1]"></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- 指针 -->
<SettingItemBox name="指针">
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.data[0].itemStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="宽度">
<n-input-number v-model:value="dialConfig.pointer.width" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="刻度">
<SettingItem name="最小值">
<n-input-number v-model:value="dialConfig.min" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
<SettingItem name="最大值">
<n-input-number v-model:value="dialConfig.max" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisTick.lineStyle.color" @update:value="updateClick"></n-color-picker>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { GlobalThemeJsonType } from '@/settings/chartThemes'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const config = computed(() => {
return props.optionData
})
const dialConfig = computed(() => {
return props.optionData.series[0]
})
const updateClick = (val: any) => {
props.optionData.series[1].splitLine.lineStyle.color=val
}
</script>

View File

@@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const DialConfig: ConfigType = {
key: 'Dial',
chartKey: 'VDial',
conKey: 'VCDial',
title: '表盘',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image:'dial.png'
}

View File

@@ -0,0 +1,69 @@
<template>
<v-chart :theme="themeColor" :init-options="initOptions" :option="option.value" autoresize> </v-chart>
</template>
<script setup lang="ts">
import { PropType, reactive, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes } from './config'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, TitleComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent, TitleComponent])
const option = reactive({
value: {}
})
const dataHandle = (newData: any) => {
let config = props.chartConfig.option
config.series[0].data[0].value = newData
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
option.value = props.chartConfig.option
}
// 配置时
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataHandle(newData)
} catch (error) {
console.log(error)
}
},
{
immediate: true,
deep: false
}
)
// 预览时
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
// @ts-ignore
option.value.series[0].data[0].value = resData
})
</script>

View File

@@ -0,0 +1,85 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { GraphConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = []
// 关系图布局
export const GraphLayout = [
{ label: '无', value: 'none' },
{ label: '环形', value: 'circular' },
{ label: '力引导', value: 'force' }
]
// 标签开关
export const LabelSwitch = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
// 标签位置
export const LabelPosition = [
{ label: '左侧', value: 'left' },
{ label: '右侧', value: 'right' },
{ label: '顶部', value: 'top' },
{ label: '底部', value: 'bottom' },
{ label: '内部', value: 'inside' }
]
// 图-迭代动画
export const LayoutAnimation = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
export const option = {
dataset: { ...dataJson },
tooltip: {},
legend: {
show: true,
textStyle: {
color: '#eee',
fontSize: 14
},
data: dataJson.categories.map(function (a) {
return a.name
})
},
series: [
{
type: 'graph',
layout: 'none', // none circular环形布局
data: dataJson.nodes,
links: dataJson.links,
categories: dataJson.categories,
label: {
show: 1,
position: 'right',
formatter: '{b}'
},
labelLayout: {
hideOverlap: true
},
lineStyle: {
color: 'source', // 线条颜色
curveness: 0.2 // 线条卷曲程度
},
force: {
repulsion: 100,
gravity: 0.1,
edgeLength: 30,
layoutAnimation: 1,
friction: 0.6
}
}
]
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = GraphConfig.key
public chartConfig = cloneDeep(GraphConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@@ -0,0 +1,113 @@
<template>
<div>
<CollapseItem name="关系图" :expanded="true">
<SettingItemBox name="样式">
<setting-item name="布局">
<n-select v-model:value="graphConfig.layout" :options="GraphLayout" size="small" />
</setting-item>
</SettingItemBox>
<SettingItemBox name="标签">
<setting-item name="展示">
<n-select v-model:value="graphConfig.label.show" :options="LabelSwitch" size="small" />
</setting-item>
<setting-item name="位置">
<n-select v-model:value="graphConfig.label.position" :options="LabelPosition" size="small" />
</setting-item>
</SettingItemBox>
<SettingItemBox name="线条">
<SettingItem name="弧线">
<!-- 需要输入两位的小数才会变化 -->
<n-input-number
v-model:value="optionData.series[0].lineStyle.curveness"
:min="0"
:step="0.01"
placeholder="弯曲程度"
size="small"
></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="图例">
<SettingItem name="颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.legend.textStyle.color"
></n-color-picker>
</SettingItem>
<SettingItem name="文本">
<n-input-number
v-model:value="optionData.legend.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="文字大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="力引导" v-if="optionData.series[0].force && graphConfig.layout == 'force'">
<SettingItem name="斥力因子" v-if="optionData.series[0].force.repulsion">
<n-input-number
v-model:value="optionData.series[0].force.repulsion"
:min="0"
:step="1"
size="small"
placeholder="斥力因子大小"
>
</n-input-number>
</SettingItem>
<SettingItem name="引力因子" v-if="optionData.series[0].force.gravity">
<n-input-number
v-model:value="optionData.series[0].force.gravity"
:min="0"
:step="0.1"
size="small"
placeholder="引力因子"
>
</n-input-number>
</SettingItem>
<SettingItem name="节点距离">
<n-input-number
v-model:value="optionData.series[0].force.edgeLength"
:min="0"
:step="1"
size="small"
placeholder="节点距离"
>
</n-input-number>
</SettingItem>
<SettingItem name="迭代动画">
<n-select v-model:value="graphConfig.force.layoutAnimation" :options="LayoutAnimation" size="small" />
</SettingItem>
<SettingItem name="节点速度">
<n-input-number
v-model:value="optionData.series[0].force.friction"
:min="0"
:step="0.1"
size="small"
placeholder="节点速度"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</div>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option, GraphLayout, LabelSwitch, LabelPosition, LayoutAnimation } from './config'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option & GlobalThemeJsonType>,
required: true
}
})
const graphConfig = computed<(typeof option.series)[0]>(() => {
return props.optionData.series[0]
})
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const GraphConfig: ConfigType = {
key: 'Graph',
chartKey: 'VGraph',
conKey: 'VCGraph',
title: '关系图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'graph.png'
}

View File

@@ -0,0 +1,87 @@
<template>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
autoresize
></v-chart>
</template>
<script setup lang="ts">
import { ref, computed, PropType, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import dataJson from './data.json'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { RadarChart } from 'echarts/charts'
import { includes } from './config'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
const vChartRef = ref<typeof VChart>()
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const dataSetHandle = (dataset: typeof dataJson) => {
if (dataset.nodes) {
props.chartConfig.option.series[0].data = dataset.nodes
}
if (dataset.links) {
props.chartConfig.option.series[0].links = dataset.links
}
if (dataset.categories) {
props.chartConfig.option.series[0].categories = dataset.categories
// @ts-ignore
props.chartConfig.option.legend.data = dataset.categories.map((i: { name: string }) => i.name)
}
if (vChartRef.value && isPreview()) {
setOption(vChartRef.value, props.chartConfig.option)
}
}
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataSetHandle(newData)
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
dataSetHandle(newData)
})
</script>

View File

@@ -3,7 +3,7 @@
:type="type"
:height="h"
:processing="processing"
:percentage="option.dataset"
:percentage="dataset"
:indicator-placement="indicatorPlacement"
:color="color"
:rail-color="railColor"
@@ -15,7 +15,7 @@
fontSize: `${indicatorTextSize}px`
}"
>
{{ option.dataset }} {{ unit }}
{{ dataset }} {{ unit }}
</n-text>
</n-progress>
</template>

View File

@@ -0,0 +1,43 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { SankeyConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = ['legend']
// 图表方向
export const orientList = [
{ label: '水平', value: 'horizontal' },
{ label: '垂直', value: 'vertical' }
]
// 标签展示
export const toolTipSwitch = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
export const option = {
dataset: { ...dataJson },
tooltip: {
show: 1,
trigger: 'item',
triggerOn: 'mousemove'
},
series: {
type: 'sankey',
layout: 'none',
orient:'horizontal',
data: dataJson.label,
links: dataJson.links,
levels: dataJson.levels
}
};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = SankeyConfig.key
public chartConfig = cloneDeep(SankeyConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@@ -0,0 +1,43 @@
<template>
<div>
<CollapseItem name="桑基图" :expanded="true">
<SettingItemBox name="样式">
<SettingItem name="方向">
<n-select
v-model:value="sankeyConfig.orient"
size="small"
:options="orientList"
placeholder="选择方向"
/>
</SettingItem>
<SettingItem name="提示标签">
<n-select
v-model:value="optionData.tooltip.show"
size="small"
:options="toolTipSwitch"
placeholder="是否开启"
/>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</div>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option, orientList, toolTipSwitch } from './config'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option & GlobalThemeJsonType>,
required: true
}
})
const sankeyConfig = computed<typeof option.series>(() => {
return props.optionData.series
})
</script>

View File

@@ -0,0 +1,86 @@
{
"label": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "a1"
},
{
"name": "a2"
},
{
"name": "b1"
},
{
"name": "b2"
}
],
"links": [
{
"source": "a",
"target": "a1",
"value": 5
},
{
"source": "a",
"target": "a2",
"value": 3
},
{
"source": "b",
"target": "b1",
"value": 8
},
{
"source": "a",
"target": "b1",
"value": 3
},
{
"source": "b1",
"target": "a1",
"value": 1
},
{
"source": "b1",
"target": "b2",
"value": 2
}
],
"levels": [
{
"depth": 0,
"itemStyle": {
"color": "#decbe4"
},
"lineStyle": {
"color": "source",
"opacity": 0.9
}
},
{
"depth": 1,
"itemStyle": {
"color": "#b3cde3"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
},
{
"depth": 2,
"itemStyle": {
"color": "#ccebc5"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
}
]
}

View File

@@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const SankeyConfig: ConfigType = {
key: 'Sankey',
chartKey: 'VSankey',
conKey: 'VCSankey',
title: '桑基图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'sankey.png'
}

View File

@@ -0,0 +1,78 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
</template>
<script setup lang="ts">
import { ref, computed, PropType, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import dataJson from './data.json'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { RadarChart } from 'echarts/charts'
import { includes } from './config'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
const vChartRef = ref<typeof VChart>()
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const dataHandle = (dataset: typeof dataJson) => {
if (dataset.label) {
props.chartConfig.option.series.data = dataset.label
}
if (dataset.links) {
props.chartConfig.option.series.links = dataset.links
}
if (dataset.levels) {
props.chartConfig.option.series.levels = dataset.levels
}
if (vChartRef.value && isPreview()) {
setOption(vChartRef.value, props.chartConfig.option)
}
}
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataHandle(newData)
} catch (error) {
console.log(error)
}
},
{
deep: true
}
)
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
dataHandle(newData)
})
</script>

View File

@@ -4,5 +4,18 @@ import { FunnelConfig } from './Funnel/index'
import { HeatmapConfig } from './Heatmap/index'
import { WaterPoloConfig } from './WaterPolo/index'
import { TreeMapConfig } from './TreeMap/index'
import { DialConfig } from './Dial/index'
import { SankeyConfig } from './Sankey/index'
import { GraphConfig } from './Graph/index'
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig]
export default [
ProcessConfig,
RadarConfig,
FunnelConfig,
HeatmapConfig,
WaterPoloConfig,
TreeMapConfig,
GraphConfig,
SankeyConfig,
DialConfig
]

View File

@@ -7,6 +7,22 @@
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 中心标题 -->
<SettingItemBox v-if="config.title" name="标题">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="config.title.textStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="config.title.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- Echarts 全局设置 -->
<SettingItemBox name="进度条">
<SettingItem name="颜色">
@@ -31,24 +47,8 @@
></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- 中心标题 -->
<SettingItemBox v-if="config.title" name="标题">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="config.title.textStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="config.title.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 其他样式 -->
<SettingItemBox name="轨道样式">
<SettingItemBox name="轨道">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="item.data[1].itemStyle.color"></n-color-picker>
</SettingItem>
@@ -69,6 +69,18 @@
v-model:value="item.data[1].itemStyle.shadowColor"
></n-color-picker>
</SettingItem>
<SettingItem name="轨道宽度">
<n-select
v-model:value="item.radius[0]"
size="small"
:options="[
{ label: '窄', value: '75%' },
{ label: '中', value: '60%' },
{ label: '宽', value: '45%' },
{ label: '更宽', value: '30%' }
]"
/>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>

View File

@@ -41,7 +41,7 @@ const option = reactive({
const dataHandle = (newData: any) => {
const d = parseFloat(`${newData}`) * 100
let config = props.chartConfig.option
config.title.text = d.toFixed(2) + '%'
config.title.text = `${+d.toFixed(2)}%`
config.series[0].data[0].value[0] = d
config.series[0].data[1].value[0] = 100 - d
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
@@ -68,7 +68,7 @@ watch(
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
let d = parseFloat(`${resData}`) * 100
// @ts-ignore
option.value.title.text = d.toFixed(2) + '%'
option.value.title.text = `${+d.toFixed(2)}%`
// @ts-ignore
option.value.series[0].data[0].value[0] = d
// @ts-ignore

View File

@@ -18,7 +18,14 @@ export const PieTypeObject = {
[PieTypeEnum.ROSE]: 'rose'
}
// 其它配置
const otherConfig = {
// 轮播动画
isCarousel: false,
}
const option = {
...otherConfig,
type: 'ring',
tooltip: {
show: true,

View File

@@ -1,88 +1,99 @@
<template>
<!-- Echarts 全局设置 -->
<global-setting :optionData="optionData"></global-setting>
<CollapseItem name="饼图配置" :expanded="true">
<SettingItemBox name="类型">
<SettingItem>
<n-select v-model:value="optionData.type" size="small" :options="fontWeightOptions" />
</SettingItem>
</SettingItemBox>
<SettingItemBox name="标签">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.series[0].label.show" size="small"></n-switch>
<n-text>展示标签</n-text>
</n-space>
</SettingItem>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.series[0].labelLine.show" size="small"></n-switch>
<n-text>引导线</n-text>
</n-space>
</setting-item>
<SettingItem name="位置">
<n-select v-model:value="optionData.series[0].label.position" size="small" :options="labelConfig.position" />
</SettingItem>
<setting-item name="展示类型">
<n-select v-model:value="optionData.series[0].label.formatter" size="small" :options="labelFormatterOptions" />
</setting-item>
</SettingItemBox>
<setting-item-box name="圆角">
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderRadius"
size="small"
:min="0"
></n-input-number>
<n-text>圆角大小</n-text>
</n-space>
</setting-item>
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderWidth"
size="small"
:min="0"
></n-input-number>
<n-text>线条宽度</n-text>
</n-space>
</setting-item>
</setting-item-box>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, watch } from 'vue'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { PieTypeObject, PieTypeEnum } from './config'
import { labelConfig } from '@/packages/chartConfiguration/echarts'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const fontWeightOptions = [
{
label: PieTypeEnum.NORMAL,
value: PieTypeObject[PieTypeEnum.NORMAL]
},
{
label: PieTypeEnum.RING,
value: PieTypeObject[PieTypeEnum.RING]
},
{
label: PieTypeEnum.ROSE,
value: PieTypeObject[PieTypeEnum.ROSE]
}
]
const labelFormatterOptions = [
{ label: '数据名', value: '{b}' },
{ label: '百分比', value: '{d}' },
{ label: '列名:百分比', value: '{b}:{d}%' }
]
</script>
<template>
<!-- Echarts 全局设置 -->
<global-setting :optionData="optionData"></global-setting>
<CollapseItem name="饼图配置" :expanded="true">
<SettingItemBox name="类型">
<SettingItem>
<n-select v-model:value="optionData.type" size="small" :options="fontWeightOptions" />
</SettingItem>
</SettingItemBox>
<SettingItemBox name="动画" :alone="true">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
<n-text>开启<n-text :depth="3">将自动隐藏图例</n-text></n-text>
</n-space>
</SettingItem>
<SettingItem>
<n-text :depth="3">无鼠标点击图例场景时可强行打开图例</n-text>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="标签">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.series[0].label.show" size="small"></n-switch>
<n-text>展示标签</n-text>
</n-space>
</SettingItem>
<setting-item>
<n-space>
<n-switch v-model:value="optionData.series[0].labelLine.show" size="small"></n-switch>
<n-text>引导线</n-text>
</n-space>
</setting-item>
<SettingItem name="位置">
<n-select v-model:value="optionData.series[0].label.position" size="small" :options="labelConfig.position" />
</SettingItem>
<setting-item name="展示类型">
<n-select v-model:value="optionData.series[0].label.formatter" size="small" :options="labelFormatterOptions" />
</setting-item>
</SettingItemBox>
<setting-item-box name="圆角">
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderRadius"
size="small"
:min="0"
></n-input-number>
<n-text>圆角大小</n-text>
</n-space>
</setting-item>
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderWidth"
size="small"
:min="0"
></n-input-number>
<n-text>线条宽度</n-text>
</n-space>
</setting-item>
</setting-item-box>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, watch } from 'vue'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { PieTypeObject, PieTypeEnum } from './config'
import { labelConfig } from '@/packages/chartConfiguration/echarts'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const fontWeightOptions = [
{
label: PieTypeEnum.NORMAL,
value: PieTypeObject[PieTypeEnum.NORMAL]
},
{
label: PieTypeEnum.RING,
value: PieTypeObject[PieTypeEnum.RING]
},
{
label: PieTypeEnum.ROSE,
value: PieTypeObject[PieTypeEnum.ROSE]
}
]
const labelFormatterOptions = [
{ label: '数据名', value: '{b}' },
{ label: '百分比', value: '{d}' },
{ label: '列名:百分比', value: '{b}:{d}%' }
]
</script>

View File

@@ -1,64 +1,146 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
</template>
<script setup lang="ts">
import { computed, PropType, reactive, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes } from './config'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent])
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
watch(
() => props.chartConfig.option.type,
newData => {
try {
if (newData === 'nomal') {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = false
} else if (newData === 'ring') {
props.chartConfig.option.series[0].radius = ['40%', '65%']
props.chartConfig.option.series[0].roseType = false
} else {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = true
}
} catch (error) {
console.log(error)
}
},
{ deep: false, immediate: true }
)
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore)
</script>
<template>
<v-chart
ref="vChartRef"
autoresize
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
@mouseover="handleHighlight"
@mouseout="handleDownplay"
></v-chart>
</template>
<script setup lang="ts">
import { computed, PropType, onMounted, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes } from './config'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import dataJson from './data.json'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
let seriesDataNum = -1
let seriesDataMaxLength = 0
let intervalInstance: any = null
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent])
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
// 会重新选择需要选中和展示的数据
const handleSeriesData = () => {
if (seriesDataNum > -1) {
vChartRef.value?.dispatchAction({
type: 'downplay',
dataIndex: seriesDataNum
})
}
seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
vChartRef.value?.dispatchAction({
type: 'highlight',
dataIndex: seriesDataNum
})
}
// 新增轮播
const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
if (!skipPre && !Array.isArray(newData?.source)) return
if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
clearInterval(intervalInstance)
intervalInstance = setInterval(() => {
handleSeriesData()
}, 1000)
}
// 取消轮播
const clearPieInterval = () => {
vChartRef.value?.dispatchAction({
type: 'downplay',
dataIndex: seriesDataNum
})
clearInterval(intervalInstance)
intervalInstance = null
}
// 处理鼠标聚焦高亮内容
const handleHighlight = () => {
clearPieInterval()
}
// 处理鼠标取消悬浮
const handleDownplay = () => {
if (props.chartConfig.option.isCarousel && !intervalInstance) {
// 恢复轮播
addPieInterval(undefined, true)
}
}
watch(
() => props.chartConfig.option.type,
newData => {
try {
if (newData === 'nomal') {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = false
} else if (newData === 'ring') {
props.chartConfig.option.series[0].radius = ['40%', '65%']
props.chartConfig.option.series[0].roseType = false
} else {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = true
}
} catch (error) {
console.log(error)
}
},
{ deep: false, immediate: true }
)
watch(
() => props.chartConfig.option.isCarousel,
newData => {
if (newData) {
addPieInterval(undefined, true)
props.chartConfig.option.legend.show = false
} else {
props.chartConfig.option.legend.show = true
clearPieInterval()
}
}
)
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
addPieInterval(newData)
})
onMounted(() => {
seriesDataMaxLength = dataJson.source.length
if (props.chartConfig.option.isCarousel) {
addPieInterval(undefined, true)
}
})
</script>

View File

@@ -14,5 +14,6 @@ export enum ChatCategoryEnumName {
LINE = '折线图',
SCATTER = '散点图',
MAP = '地图',
COMBINATION = '组合图',
MORE = '更多'
}

View File

@@ -16,6 +16,7 @@ export interface OptionType {
flipperGap: number
flipperType: FlipType
flipperSpeed: number
flipperBorderWidth: number
}
export const option: OptionType = {
@@ -28,7 +29,8 @@ export const option: OptionType = {
flipperRadius: 5,
flipperGap: 10,
flipperType: 'down',
flipperSpeed: 450
flipperSpeed: 450,
flipperBorderWidth: 0,
}
export default class Config extends PublicConfigClass implements CreateComponentType {

View File

@@ -16,12 +16,16 @@
<setting-item name="高度">
<n-input-number v-model:value="optionData.flipperHeight" size="small" :min="1"></n-input-number>
</setting-item>
<setting-item name="间隔">
<n-input-number v-model:value="optionData.flipperGap" size="small" :min="0"></n-input-number>
<setting-item name="边框">
<n-input-number v-model:value="optionData.flipperBorderWidth" size="small" :min="0" :max="10"></n-input-number>
</setting-item>
<setting-item name="圆角">
<n-input-number v-model:value="optionData.flipperRadius" size="small" :min="0"></n-input-number>
</setting-item>
<setting-item name="翻牌间隔">
<n-input-number v-model:value="optionData.flipperGap" size="small" :min="0"></n-input-number>
</setting-item>
<setting-item />
<setting-item name="背景色">
<n-color-picker
size="small"

View File

@@ -9,6 +9,7 @@
:radius="flipperRadius"
:flip-type="flipperType"
:duration="flipperSpeed"
:border-width="flipperBorderWidth"
v-for="(item, index) in flipperData"
:key="index"
class="go-d-block"
@@ -42,7 +43,8 @@ const {
flipperRadius,
flipperGap,
flipperType,
flipperSpeed
flipperSpeed,
flipperBorderWidth
} = toRefs(props.chartConfig.option as OptionType)
const flipperData = ref<string[] | number[]>([])
@@ -61,7 +63,7 @@ watch(
() => props.chartConfig.option,
newVal => {
try {
updateDatasetHandler((newVal as OptionType).dataset)
updateDatasetHandler((newVal as any as OptionType).dataset)
} catch (error) {
console.log(error)
}

View File

@@ -0,0 +1,18 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { chartInitConfig } from '@/settings/designSetting'
import { FullScreenConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
border: 6,
bgColor: '#84a5e9',
borderColor: '#84a5e9'
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = FullScreenConfig.key
public attr = { ...chartInitConfig, w: 150, h: 150, zIndex: -1 }
public chartConfig = cloneDeep(FullScreenConfig)
public option = cloneDeep(option)
}

View File

@@ -0,0 +1,28 @@
<template>
<CollapseItem name="全屏按钮" expanded>
<SettingItemBox name="按钮">
<SettingItem name="背景色">
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.bgColor"></n-color-picker>
</SettingItem>
<SettingItem name="边框色">
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.borderColor"></n-color-picker>
</SettingItem>
<SettingItem name="边框大小">
<n-input-number v-model:value="optionData.border" size="small" :step="0.5" :min="0"></n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option } from './config'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true
}
})
</script>

View File

@@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const FullScreenConfig: ConfigType = {
key: 'FullScreen',
chartKey: 'VFullScreen',
conKey: 'VCFullScreen',
title: '全屏按钮',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.DECORATES,
chartFrame: ChartFrameEnum.STATIC,
image: 'fullScreen.png'
}

View File

@@ -0,0 +1,111 @@
<template>
<svg @click="toggleFullscreen" v-if="!isFullscreen" viewBox="0 0 1024 1024">
<path
d="M665.6 1017.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h268.8l6.4-268.8c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v294.4c0 32-25.6 51.2-51.2 51.2h-300.8zM51.2 396.8c-19.2 0-38.4-19.2-38.4-38.4V64C12.8 32 38.4 12.8 64 12.8h294.4c19.2 0 38.4 19.2 38.4 38.4s-19.2 38.4-38.4 38.4H89.6v268.8c0 19.2-19.2 38.4-38.4 38.4zM64 1017.6c-32 0-51.2-25.6-51.2-51.2v-294.4c0-19.2 19.2-38.4 38.4-38.4s38.4 19.2 38.4 38.4v217.6l198.4-198.4c6.4-6.4 19.2-12.8 25.6-12.8s19.2 6.4 25.6 12.8c6.4 6.4 12.8 19.2 12.8 25.6 0 12.8-6.4 19.2-12.8 25.6l-198.4 198.4h217.6c19.2 0 38.4 19.2 38.4 38.4s-19.2 38.4-38.4 38.4H64z m915.2-620.8c-19.2 0-38.4-19.2-38.4-38.4V140.8l-198.4 198.4c-6.4 6.4-19.2 12.8-25.6 12.8-12.8 0-19.2-6.4-25.6-12.8-12.8-12.8-12.8-38.4 0-51.2l198.4-198.4h-217.6c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h294.4c32 0 51.2 25.6 51.2 51.2v294.4c0 19.2-19.2 38.4-38.4 38.4z"
class="fullScreen-border"
></path>
</svg>
<svg @click="toggleFullscreen" v-else viewBox="0 0 1024 1024">
<path
d="M379.336 697.237L153.362 921.55c-14.11 14.007-36.905 13.922-50.912-0.188-14.007-14.11-13.922-36.905 0.188-50.912l227.6-225.927H138.645c-18.99 0-34.385-15.446-34.385-34.5 0-19.053 15.395-34.5 34.385-34.5H413.72c18.99 0 34.384 15.447 34.384 34.5v276c0 9.15-3.622 17.926-10.07 24.396a34.326 34.326 0 0 1-24.314 10.104 34.326 34.326 0 0 1-24.314-10.104 34.559 34.559 0 0 1-10.071-24.396V697.237z m263.395-366.88l227.813-227.813c14.059-14.059 36.853-14.059 50.912 0 14.059 14.059 14.059 36.853 0 50.912l-225.18 225.18h187.147c18.99 0 34.385 15.445 34.385 34.5 0 19.053-15.395 34.5-34.385 34.5H608.346c-18.99 0-34.384-15.447-34.384-34.5v-276c0-9.15 3.622-17.926 10.07-24.396a34.326 34.326 0 0 1 24.314-10.105c9.12 0 17.865 3.635 24.314 10.105a34.559 34.559 0 0 1 10.07 24.395v193.223zM99.385 410a34.326 34.326 0 0 1-24.314-10.105A34.559 34.559 0 0 1 65 375.5v-276C65 80.446 80.395 65 99.385 65h275.077c18.99 0 34.384 15.446 34.384 34.5 0 19.054-15.394 34.5-34.384 34.5H133.769v241.5c0 9.15-3.622 17.925-10.07 24.395A34.326 34.326 0 0 1 99.384 410z m825.23 552H649.538c-18.99 0-34.384-15.446-34.384-34.5 0-19.054 15.394-34.5 34.384-34.5h240.693V651.5c0-19.054 15.394-34.5 34.384-34.5 18.99 0 34.385 15.446 34.385 34.5v276c0 19.054-15.395 34.5-34.385 34.5z"
class="fullScreen-border"
></path>
</svg>
</template>
<script setup lang="ts">
import { PropType, toRefs, ref, onMounted, onUnmounted } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { option } from './config'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType & typeof option>,
required: true
}
})
let { border, bgColor, borderColor } = toRefs(props.chartConfig.option)
const isFullscreen = ref(false)
const checkFullscreen = () => {
isFullscreen.value = !!(
document.fullscreenElement ||
(document as any).webkitFullscreenElement ||
(document as any).mozFullScreenElement ||
(document as any).msFullscreenElement
)
}
checkFullscreen()
const requestFullscreen = (element: Element) => {
if (element.requestFullscreen) {
element.requestFullscreen()
} else if ((document as any).mozRequestFullScreen) {
/* Firefox */
(document as any).mozRequestFullScreen()
} else if ((document as any).webkitRequestFullscreen) {
/* Chrome, Safari and Opera */
(document as any).webkitRequestFullscreen()
} else if ((document as any).msRequestFullscreen) {
/* IE/Edge */
(document as any).msRequestFullscreen()
}
}
const exitFullscreen = () => {
if (document.fullscreenElement && document.exitFullscreen) {
document.exitFullscreen()
} else if ((document as any).mozFullScreenElement && (document as any).mozCancelFullScreen) {
/* Firefox */
(document as any).mozCancelFullScreen()
} else if ((document as any).webkitFullscreenElement && (document as any).webkitExitFullscreen) {
/* Chrome, Safari and Opera */
(document as any).webkitExitFullscreen()
} else if ((document as any).msFullscreenElement && (document as any).msExitFullscreen) {
/* IE/Edge */
(document as any).msExitFullscreen()
}
}
const toggleFullscreen = () => {
if (!isFullscreen.value) {
requestFullscreen(document.documentElement)
} else {
exitFullscreen()
}
isFullscreen.value = !isFullscreen.value
// 由于全屏状态的改变不会立即生效,所以需要延迟一段时间再去获取全屏状态
setTimeout(() => {
checkFullscreen()
}, 1000)
}
// 监听全屏状态的改变,保证多个全屏组件的状态一致
onMounted(() => {
document.addEventListener('fullscreenchange', checkFullscreen)
document.addEventListener('webkitfullscreenchange', checkFullscreen)
document.addEventListener('mozfullscreenchange', checkFullscreen)
document.addEventListener('MSFullscreenChange', checkFullscreen)
})
onUnmounted(() => {
document.removeEventListener('fullscreenchange', checkFullscreen)
document.removeEventListener('webkitfullscreenchange', checkFullscreen)
document.removeEventListener('mozfullscreenchange', checkFullscreen)
document.removeEventListener('MSFullscreenChange', checkFullscreen)
})
</script>
<style lang="scss" scoped>
svg {
display: block;
width: 100%;
height: 100%;
cursor: pointer;
}
.fullScreen-border {
stroke: v-bind('borderColor');
stroke-width: v-bind('border+"px"');
fill: v-bind('bgColor');
}
</style>

View File

@@ -0,0 +1,19 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { chartInitConfig } from '@/settings/designSetting'
import { PipelineHConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
color_type: 1,
o_color: '#0a7ae2',
i_color: '#119bfa',
line_class: 'svg_ani_flow'
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = PipelineHConfig.key
public attr = { ...chartInitConfig, w: 500, h: 15, zIndex: -1 }
public chartConfig = cloneDeep(PipelineHConfig)
public option = cloneDeep(option)
}

View File

@@ -0,0 +1,77 @@
<template>
<CollapseItem name="管道" :expanded="true">
<SettingItemBox name="默认颜色">
<SettingItem>
<n-select v-model:value="optionData.color_type" :options="colorOptions" @update:value="handleColorChange" />
</SettingItem>
</SettingItemBox>
<SettingItemBox name="管道颜色">
<SettingItem>
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.o_color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="水流颜色">
<SettingItem>
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.i_color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="流向">
<SettingItem>
<n-select v-model:value="optionData.line_class" :options="options" />
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, ref } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option } from './config'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true
}
})
const options = ref([
{
value: 'svg_ani_flow',
label: '正向'
},
{
value: 'svg_ani_flow_back',
label: '反向'
},
{
value: 'svg_ani_flow_stop',
label: '停止'
}
])
const colorOptions = ref([
{
value: 1,
label: '蓝'
},
{
value: 2,
label: '黄'
}
])
// 默认颜色
const handleColorChange = (e: number) => {
switch (e) {
case 1:
props.optionData.o_color = '#0a7ae2'
props.optionData.i_color = '#119bfa'
break
case 2:
props.optionData.o_color = '#ff9d00'
props.optionData.i_color = '#f7ea37'
break
}
}
</script>

View File

@@ -0,0 +1,13 @@
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const PipelineHConfig: ConfigType = {
key: 'PipelineH',
chartKey: 'VPipelineH',
conKey: 'VCPipelineH',
title: '管道-横向',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.DECORATES,
image: 'Pipeline_H.png'
}

View File

@@ -0,0 +1,141 @@
<template>
<div class="go-decorates-line">
<svg :width="w" :height="h">
<line :x1="0" :y1="h / 2" :x2="w" :y2="h / 2" :stroke="o_color" :stroke-width="h"></line>
<line :x1="0" :y1="h / 2" :x2="w" :y2="h / 2" :stroke="i_color" :stroke-width="h / 2" :class="line_class"></line>
</svg>
</div>
</template>
<script setup lang="ts">
import { PropType, toRefs } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const { w, h } = toRefs(props.chartConfig.attr)
const { o_color, i_color, line_class } = toRefs(props.chartConfig.option)
</script>
<style lang="scss" scoped>
.go-decorates-line {
font-size: 0;
}
/* 正向流动效果 */
.svg_ani_flow {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 13, 5;
}
}
@-webkit-keyframes ani_flow {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 13, 5;
}
}
/* 停止流动效果 */
.svg_ani_flow_stop {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow_stop 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow_stop 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
@-webkit-keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
/* 反向流动效果 */
.svg_ani_flow_back {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow_back 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow_back 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow_back {
from {
stroke-dasharray: 13, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
@-webkit-keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
/* 以最大40高度填充 */
.svg_ani_fill_h40 {
animation: ani_fill_h40 5s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_fill_h40 5s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_fill_h40 {
from {
height: 0px;
}
to {
height: 40px;
}
}
@-webkit-keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
</style>

View File

@@ -0,0 +1,19 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { chartInitConfig } from '@/settings/designSetting'
import { PipelineVConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
color_type: 1,
o_color: '#0a7ae2',
i_color: '#119bfa',
line_class: 'svg_ani_flow'
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = PipelineVConfig.key
public attr = { ...chartInitConfig, w: 15, h: 500, zIndex: -1 }
public chartConfig = cloneDeep(PipelineVConfig)
public option = cloneDeep(option)
}

View File

@@ -0,0 +1,77 @@
<template>
<CollapseItem name="管道" :expanded="true">
<SettingItemBox name="默认颜色">
<SettingItem>
<n-select v-model:value="optionData.color_type" :options="colorOptions" @update:value="handleColorChange" />
</SettingItem>
</SettingItemBox>
<SettingItemBox name="管道颜色">
<SettingItem>
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.o_color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="水流颜色">
<SettingItem>
<n-color-picker size="small" :modes="['hex']" v-model:value="optionData.i_color"></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="流向">
<SettingItem>
<n-select v-model:value="optionData.line_class" :options="options" />
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, ref } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option } from './config'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true
}
})
const options = ref([
{
value: 'svg_ani_flow',
label: '正向'
},
{
value: 'svg_ani_flow_back',
label: '反向'
},
{
value: 'svg_ani_flow_stop',
label: '停止'
}
])
const colorOptions = ref([
{
value: 1,
label: '蓝'
},
{
value: 2,
label: '黄'
}
])
// 默认颜色
const handleColorChange = (e: number) => {
switch (e) {
case 1:
props.optionData.o_color = '#0a7ae2'
props.optionData.i_color = '#119bfa'
break
case 2:
props.optionData.o_color = '#ff9d00'
props.optionData.i_color = '#f7ea37'
break
}
}
</script>

View File

@@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const PipelineVConfig: ConfigType = {
key: 'PipelineV',
chartKey: 'VPipelineV',
conKey: 'VCPipelineV',
title: '管道-纵向',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.DECORATES,
image: 'Pipeline_V.png'
}

View File

@@ -0,0 +1,115 @@
<template>
<div class="go-decorates-line">
<svg :width="w" :height="h">
<line :x1="w / 2" :y1="0" :x2="w / 2" :y2="h" :stroke="o_color" :stroke-width="w"></line>
<line :x1="w / 2" :y1="0" :x2="w / 2" :y2="h" :stroke="i_color" :stroke-width="w / 2" :class="line_class"></line>
</svg>
</div>
</template>
<script setup lang="ts">
import { PropType, toRefs } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const { w, h } = toRefs(props.chartConfig.attr)
const { o_color, i_color, line_class } = toRefs(props.chartConfig.option)
</script>
<style lang="scss" scoped>
.go-decorates-line {
font-size: 0;
}
/* 正向流动效果 */
.svg_ani_flow {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 13, 5;
}
}
@-webkit-keyframes ani_flow {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 13, 5;
}
}
/* 停止流动效果 */
.svg_ani_flow_stop {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow_stop 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow_stop 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
@-webkit-keyframes ani_flow_stop {
from {
stroke-dasharray: 10, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
/* 反向流动效果 */
.svg_ani_flow_back {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: ani_flow_back 10s linear infinite;
animation-fill-mode: forwards;
-webkit-animation: ani_flow_back 10s linear infinite;
-webkit-animation-fill-mode: forwards;
}
@keyframes ani_flow_back {
from {
stroke-dasharray: 13, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
@-webkit-keyframes ani_flow_back {
from {
stroke-dasharray: 13, 5;
}
to {
stroke-dasharray: 10, 5;
}
}
</style>

View File

@@ -1,7 +1,19 @@
import { NumberConfig } from './Number/index'
import { TimeCommonConfig } from './TimeCommon/index'
import { ClockConfig } from './Clock/index'
import { FullScreenConfig } from './FullScreen/index'
import { CountDownConfig } from './CountDown/index'
import { FlipperNumberConfig } from './FlipperNumber'
import { PipelineHConfig } from './PipelineH/index'
import { PipelineVConfig } from './PipelineV/index'
export default [NumberConfig, FlipperNumberConfig, TimeCommonConfig, CountDownConfig, ClockConfig]
export default [
NumberConfig,
FlipperNumberConfig,
TimeCommonConfig,
CountDownConfig,
ClockConfig,
FullScreenConfig,
PipelineHConfig,
PipelineVConfig
]

View File

@@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import {
ArcCurve,

View File

@@ -1,34 +1,34 @@
/**
* 资源文件
* 把模型和图片分开进行加载
*/
interface ITextures {
name: string
url: string
}
export interface IResources {
textures?: ITextures[]
}
const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
const textures: ITextures[] = []
const modules = import.meta.globEager("../../images/earth/*");
for(let item in modules) {
const n = item.split('/').pop()
if(n) {
textures.push({
name: n.split('.')[0],
url: modules[item].default
})
}
}
const resources: IResources = {
textures
}
export { resources }
/**
* 资源文件
* 把模型和图片分开进行加载
*/
interface ITextures {
name: string
url: string
}
export interface IResources {
textures?: ITextures[]
}
const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
const textures: ITextures[] = []
const modules: Record<string, { default: string }> = import.meta.glob("../../images/earth/*", { eager: true })
for(let item in modules) {
const n = item.split('/').pop()
if(n) {
textures.push({
name: n.split('.')[0],
url: modules[item].default
})
}
}
const resources: IResources = {
textures
}
export { resources }

Some files were not shown because too many files have changed in this diff Show More