npmapps 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/app/dialogFnJsx/DialogForm.vue +51 -0
- package/app/dialogFnJsx/README.md +98 -0
- package/app/dialogFnJsx/com.vue +74 -0
- package/app/dialogFnJsx/com11.vue +31 -0
- package/app/dialogFnJsx/examples.vue +205 -0
- package/app/dialogFnJsx/index.js +59 -0
- package/app/dialogFnJsx/index.vue +91 -0
- package/package.json +1 -1
- package/app/pei3d.vue +0 -579
package/README.md
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-form ref="form" :model="formData" label-width="80px">
|
|
3
|
+
<el-form-item label="名称" prop="name">
|
|
4
|
+
<el-input
|
|
5
|
+
v-model="formData.name"
|
|
6
|
+
placeholder="请输入名称"
|
|
7
|
+
/>
|
|
8
|
+
</el-form-item>
|
|
9
|
+
<el-form-item label="邮箱" prop="email">
|
|
10
|
+
<el-input
|
|
11
|
+
v-model="formData.email"
|
|
12
|
+
placeholder="请输入邮箱"
|
|
13
|
+
/>
|
|
14
|
+
</el-form-item>
|
|
15
|
+
<el-form-item label="描述" prop="description">
|
|
16
|
+
<el-input
|
|
17
|
+
type="textarea"
|
|
18
|
+
v-model="formData.description"
|
|
19
|
+
placeholder="请输入描述"
|
|
20
|
+
:rows="3"
|
|
21
|
+
/>
|
|
22
|
+
</el-form-item>
|
|
23
|
+
</el-form>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script>
|
|
27
|
+
export default {
|
|
28
|
+
name: 'DialogForm',
|
|
29
|
+
data() {
|
|
30
|
+
return {
|
|
31
|
+
formData: {
|
|
32
|
+
name: '',
|
|
33
|
+
email: '',
|
|
34
|
+
description: ''
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
methods: {
|
|
39
|
+
getFormData() {
|
|
40
|
+
return this.formData
|
|
41
|
+
},
|
|
42
|
+
resetForm() {
|
|
43
|
+
this.formData = {
|
|
44
|
+
name: '',
|
|
45
|
+
email: '',
|
|
46
|
+
description: ''
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# dialogFnJsx 组件文档
|
|
2
|
+
|
|
3
|
+
## 组件介绍
|
|
4
|
+
|
|
5
|
+
`dialogFnJsx` 是一个基于 Element UI 的 Dialog 组件封装的函数式对话框组件,使用 JSX 语法实现。它提供了一种更灵活的方式来创建和管理对话框,支持动态内容渲染和自定义插槽。
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- 函数式调用,无需在模板中声明
|
|
10
|
+
- 支持 JSX 语法
|
|
11
|
+
- 支持多个插槽(默认内容、标题、底部)
|
|
12
|
+
- 自动管理对话框的生命周期
|
|
13
|
+
- 支持所有 Element UI Dialog 的原生属性和事件
|
|
14
|
+
|
|
15
|
+
## 基本用法
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { dialogFn } from './dialogFnJsx';
|
|
19
|
+
|
|
20
|
+
// 基础用法
|
|
21
|
+
const { dialog, close } = dialogFn({
|
|
22
|
+
slots: {
|
|
23
|
+
default: <div>对话框内容</div>,
|
|
24
|
+
title: <h3>标题</h3>,
|
|
25
|
+
footer: (
|
|
26
|
+
<div>
|
|
27
|
+
<el-button onClick={() => close()}>取消</el-button>
|
|
28
|
+
<el-button type="primary" onClick={() => {}}>确定</el-button>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
},
|
|
32
|
+
props: {
|
|
33
|
+
title: '标题',
|
|
34
|
+
width: '500px',
|
|
35
|
+
destroyOnClose: true
|
|
36
|
+
},
|
|
37
|
+
on: {
|
|
38
|
+
close: () => {
|
|
39
|
+
console.log('关闭');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 参数说明
|
|
46
|
+
|
|
47
|
+
### options 配置对象
|
|
48
|
+
|
|
49
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
50
|
+
|------|------|------|------|
|
|
51
|
+
| slots | Object | 否 | 插槽内容配置对象 |
|
|
52
|
+
| props | Object | 否 | Dialog 组件的 props 配置 |
|
|
53
|
+
| on | Object | 否 | Dialog 组件的事件监听配置 |
|
|
54
|
+
|
|
55
|
+
### slots 配置对象
|
|
56
|
+
|
|
57
|
+
| 属性 | 类型 | 说明 |
|
|
58
|
+
|------|------|------|
|
|
59
|
+
| default | JSX.Element | 默认插槽内容 |
|
|
60
|
+
| title | JSX.Element | 标题插槽内容 |
|
|
61
|
+
| footer | JSX.Element | 底部插槽内容 |
|
|
62
|
+
|
|
63
|
+
### props 配置对象
|
|
64
|
+
|
|
65
|
+
支持所有 Element UI Dialog 组件的 props 配置,常用的有:
|
|
66
|
+
|
|
67
|
+
| 属性 | 类型 | 说明 |
|
|
68
|
+
|------|------|------|
|
|
69
|
+
| title | String | 对话框标题 |
|
|
70
|
+
| width | String | 对话框宽度 |
|
|
71
|
+
| top | String | 对话框距离顶部的距离 |
|
|
72
|
+
| destroyOnClose | Boolean | 关闭时是否销毁内容 |
|
|
73
|
+
| beforeClose | Function | 关闭前的回调函数 |
|
|
74
|
+
|
|
75
|
+
### on 配置对象
|
|
76
|
+
|
|
77
|
+
支持所有 Element UI Dialog 组件的事件监听配置,常用的有:
|
|
78
|
+
|
|
79
|
+
| 事件名 | 说明 |
|
|
80
|
+
|--------|------|
|
|
81
|
+
| close | 对话框关闭时的回调函数 |
|
|
82
|
+
| open | 对话框打开时的回调函数 |
|
|
83
|
+
|
|
84
|
+
## 注意事项
|
|
85
|
+
|
|
86
|
+
1. 组件使用 JSX 语法,确保项目已配置好相关的 Babel 插件支持。
|
|
87
|
+
2. 关闭对话框时会自动销毁组件实例,无需手动处理。
|
|
88
|
+
3. 所有的 Element UI Dialog 原生属性都可以通过 props 传入。
|
|
89
|
+
4. 事件监听器通过 on 对象进行配置。
|
|
90
|
+
5. 返回的 close 方法可以用于手动关闭对话框。
|
|
91
|
+
|
|
92
|
+
## 与普通 Vue 组件的区别
|
|
93
|
+
|
|
94
|
+
1. 采用函数式调用而非组件式声明
|
|
95
|
+
2. 使用 JSX 语法替代模板语法
|
|
96
|
+
3. 自动管理组件的挂载和销毁
|
|
97
|
+
4. 更灵活的插槽内容配置
|
|
98
|
+
5. 无需在父组件中注册即可使用
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
{{ nameProps }}
|
|
4
|
+
|
|
5
|
+
<el-button type="primary" v-if="showBtn" @click="show">打开新弹窗</el-button>
|
|
6
|
+
<el-button v-if="showBtn" @click="close">关闭</el-button>
|
|
7
|
+
<el-button v-if="showBtn" @click="obj.a++">{{ obj.a }}</el-button>
|
|
8
|
+
<slot />
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
<script>
|
|
12
|
+
import { dialogFn } from "./index";
|
|
13
|
+
import com11 from "./com11.vue";
|
|
14
|
+
export default {
|
|
15
|
+
props: {
|
|
16
|
+
nameProps: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: "111",
|
|
19
|
+
},
|
|
20
|
+
closeDialog: {
|
|
21
|
+
type: Function,
|
|
22
|
+
default: () => {
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
showBtn: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
obj: {
|
|
30
|
+
type: Object,
|
|
31
|
+
default: () => {
|
|
32
|
+
return {};
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
created() {
|
|
37
|
+
console.log(this.nameProps, "nameProps");
|
|
38
|
+
},
|
|
39
|
+
methods: {
|
|
40
|
+
close() {
|
|
41
|
+
console.log(this.closeDialog, "dialog");
|
|
42
|
+
this.closeDialog();
|
|
43
|
+
},
|
|
44
|
+
beforeClose(d) {
|
|
45
|
+
d();
|
|
46
|
+
},
|
|
47
|
+
show() {
|
|
48
|
+
|
|
49
|
+
const { close } = dialogFn({
|
|
50
|
+
slots: {
|
|
51
|
+
default: (
|
|
52
|
+
<com11
|
|
53
|
+
nameProps="内部defaultSlot"
|
|
54
|
+
closeDialog={() => close()}
|
|
55
|
+
/>
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
props: {
|
|
59
|
+
title: "内部弹窗标题",
|
|
60
|
+
width: "300px",
|
|
61
|
+
top: "100px",
|
|
62
|
+
beforeClose: this.beforeClose,
|
|
63
|
+
appendToBody: true,
|
|
64
|
+
},
|
|
65
|
+
on: {
|
|
66
|
+
close: () => {
|
|
67
|
+
console.log("内部关闭");
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
{{ nameProps }}
|
|
4
|
+
<el-button type="" @click="close">关闭</el-button>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
props: {
|
|
10
|
+
nameProps: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: "111",
|
|
13
|
+
},
|
|
14
|
+
closeDialog: {
|
|
15
|
+
type: Function,
|
|
16
|
+
default: () => {
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
created() {
|
|
21
|
+
console.log(this.nameProps, "nameProps");
|
|
22
|
+
},
|
|
23
|
+
methods: {
|
|
24
|
+
close() {
|
|
25
|
+
console.log(this.closeDialog, "dialog");
|
|
26
|
+
|
|
27
|
+
this.closeDialog();
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="dialog-examples">
|
|
3
|
+
<!-- 基础用法示例 -->
|
|
4
|
+
<el-button @click="showBasicDialog">基础对话框</el-button>
|
|
5
|
+
|
|
6
|
+
<!-- 自定义标题和内容示例 -->
|
|
7
|
+
<el-button @click="showCustomDialog" type="primary">自定义对话框</el-button>
|
|
8
|
+
|
|
9
|
+
<!-- 表单验证示例 -->
|
|
10
|
+
<el-button @click="showFormDialog" type="success">表单对话框</el-button>
|
|
11
|
+
|
|
12
|
+
<!-- 复杂功能示例 -->
|
|
13
|
+
<el-button @click="showComplexDialog" type="warning">复杂对话框</el-button>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
import DialogForm from './DialogForm.vue'
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
components: {
|
|
22
|
+
DialogForm
|
|
23
|
+
},
|
|
24
|
+
name: 'DialogExamples',
|
|
25
|
+
data() {
|
|
26
|
+
return {
|
|
27
|
+
formData: {
|
|
28
|
+
name: '',
|
|
29
|
+
email: '',
|
|
30
|
+
description: ''
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
methods: {
|
|
35
|
+
// 基础对话框示例
|
|
36
|
+
showBasicDialog() {
|
|
37
|
+
this.$dialogFnByJsx({
|
|
38
|
+
props: {
|
|
39
|
+
title: '基础对话框',
|
|
40
|
+
width: '30%'
|
|
41
|
+
},
|
|
42
|
+
slots: {
|
|
43
|
+
default: '这是一个基础的对话框示例,展示最简单的用法。'
|
|
44
|
+
},
|
|
45
|
+
on: {
|
|
46
|
+
open: () => console.log('对话框打开了'),
|
|
47
|
+
close: () => console.log('对话框关闭了')
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// 自定义对话框示例
|
|
53
|
+
showCustomDialog() {
|
|
54
|
+
this.$dialogFnByJsx({
|
|
55
|
+
props: {
|
|
56
|
+
width: '40%',
|
|
57
|
+
'custom-class': 'custom-dialog'
|
|
58
|
+
},
|
|
59
|
+
slots: {
|
|
60
|
+
title: <div style="color: #409EFF">自定义标题样式</div>,
|
|
61
|
+
default: (
|
|
62
|
+
<div class="custom-content">
|
|
63
|
+
<el-alert
|
|
64
|
+
title="自定义内容示例"
|
|
65
|
+
type="success"
|
|
66
|
+
description="这里展示了如何使用JSX语法自定义对话框内容"
|
|
67
|
+
show-icon
|
|
68
|
+
/>
|
|
69
|
+
<div style="margin-top: 20px">
|
|
70
|
+
可以在这里放置任何自定义的内容组件
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
),
|
|
74
|
+
footer: (
|
|
75
|
+
<div class="custom-footer">
|
|
76
|
+
<el-button>取消</el-button>
|
|
77
|
+
<el-button type="primary">确定</el-button>
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
// 表单对话框示例
|
|
85
|
+
showFormDialog() {
|
|
86
|
+
let formRef = null
|
|
87
|
+
const config = {
|
|
88
|
+
props: {
|
|
89
|
+
title: '表单对话框',
|
|
90
|
+
width: '50%'
|
|
91
|
+
},
|
|
92
|
+
slots: {
|
|
93
|
+
default: (
|
|
94
|
+
<DialogForm ref={ref => formRef = ref} />
|
|
95
|
+
),
|
|
96
|
+
footer: (
|
|
97
|
+
<div>
|
|
98
|
+
<el-button onClick={() => close()}>取消</el-button>
|
|
99
|
+
<el-button
|
|
100
|
+
type="primary"
|
|
101
|
+
onClick={() => {
|
|
102
|
+
const formData = formRef.getFormData()
|
|
103
|
+
console.log('表单数据:', formData)
|
|
104
|
+
close()
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
提交
|
|
108
|
+
</el-button>
|
|
109
|
+
</div>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
let { close } = this.$dialogFnByJsx(config)
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// 复杂功能示例
|
|
117
|
+
showComplexDialog() {
|
|
118
|
+
const config={
|
|
119
|
+
props: {
|
|
120
|
+
title: '复杂功能示例',
|
|
121
|
+
width: '60%',
|
|
122
|
+
'close-on-click-modal': false,
|
|
123
|
+
'custom-class': 'complex-dialog'
|
|
124
|
+
},
|
|
125
|
+
slots: {
|
|
126
|
+
default: (
|
|
127
|
+
<div class="complex-content">
|
|
128
|
+
<el-tabs type="border-card">
|
|
129
|
+
<el-tab-pane label="基本信息">
|
|
130
|
+
<el-descriptions title="用户信息" border>
|
|
131
|
+
<el-descriptions-item label="用户名">张三</el-descriptions-item>
|
|
132
|
+
<el-descriptions-item label="手机号">18100000000</el-descriptions-item>
|
|
133
|
+
<el-descriptions-item label="居住地">苏州市</el-descriptions-item>
|
|
134
|
+
<el-descriptions-item label="备注">
|
|
135
|
+
<el-tag size="small">学校</el-tag>
|
|
136
|
+
</el-descriptions-item>
|
|
137
|
+
<el-descriptions-item label="联系地址">
|
|
138
|
+
江苏省苏州市吴中区吴中大道 1188 号
|
|
139
|
+
</el-descriptions-item>
|
|
140
|
+
</el-descriptions>
|
|
141
|
+
</el-tab-pane>
|
|
142
|
+
<el-tab-pane label="操作记录">
|
|
143
|
+
<el-timeline>
|
|
144
|
+
<el-timeline-item
|
|
145
|
+
timestamp="2023/4/12"
|
|
146
|
+
placement="top"
|
|
147
|
+
>
|
|
148
|
+
<el-card>
|
|
149
|
+
<h4>更新 Github 模板</h4>
|
|
150
|
+
<p>王小虎 提交于 2023/4/12 20:46</p>
|
|
151
|
+
</el-card>
|
|
152
|
+
</el-timeline-item>
|
|
153
|
+
<el-timeline-item
|
|
154
|
+
timestamp="2023/4/3"
|
|
155
|
+
placement="top"
|
|
156
|
+
>
|
|
157
|
+
<el-card>
|
|
158
|
+
<h4>更新 Github 模板</h4>
|
|
159
|
+
<p>王小虎 提交于 2023/4/3 20:46</p>
|
|
160
|
+
</el-card>
|
|
161
|
+
</el-timeline-item>
|
|
162
|
+
</el-timeline>
|
|
163
|
+
</el-tab-pane>
|
|
164
|
+
</el-tabs>
|
|
165
|
+
</div>
|
|
166
|
+
),
|
|
167
|
+
footer: (
|
|
168
|
+
<div class="complex-footer">
|
|
169
|
+
<el-button onClick={() => close()}>取消</el-button>
|
|
170
|
+
<el-button type="primary" onClick={() => close()}>确定</el-button>
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
},
|
|
174
|
+
on: {
|
|
175
|
+
open: () => console.log('复杂对话框打开'),
|
|
176
|
+
close: () => console.log('复杂对话框关闭')
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const { close } = this.$dialogFnByJsx(config)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
</script>
|
|
184
|
+
|
|
185
|
+
<style scoped>
|
|
186
|
+
.dialog-examples {
|
|
187
|
+
padding: 20px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.dialog-examples .el-button {
|
|
191
|
+
margin-right: 10px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.custom-content {
|
|
195
|
+
padding: 20px 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.complex-content {
|
|
199
|
+
padding: 20px 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
:global(.complex-dialog) {
|
|
203
|
+
min-height: 400px;
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Dialog } from "element-ui";
|
|
2
|
+
import Vue from "vue";
|
|
3
|
+
|
|
4
|
+
const DialogConstructor = Vue.extend(Dialog);
|
|
5
|
+
|
|
6
|
+
export function dialogFn(options = {}) {
|
|
7
|
+
const {
|
|
8
|
+
slots = {},
|
|
9
|
+
props = {},
|
|
10
|
+
on = {},
|
|
11
|
+
} = options;
|
|
12
|
+
|
|
13
|
+
const dialog = new DialogConstructor({
|
|
14
|
+
el: document.createElement("div"),
|
|
15
|
+
render() {
|
|
16
|
+
const dialogProps = {
|
|
17
|
+
props: {
|
|
18
|
+
visible: true,
|
|
19
|
+
...props,
|
|
20
|
+
},
|
|
21
|
+
on: {
|
|
22
|
+
"update:visible": (val) => {
|
|
23
|
+
dialog.visible = val;
|
|
24
|
+
if (!val) {
|
|
25
|
+
close();
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
...on,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Dialog {...dialogProps}>
|
|
34
|
+
{slots.default && <template slot="default">{slots.default}</template>}
|
|
35
|
+
{slots.title && <template slot="title">{slots.title}</template>}
|
|
36
|
+
{slots.footer && <template slot="footer">{slots.footer}</template>}
|
|
37
|
+
</Dialog>
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const close = () => {
|
|
43
|
+
on.close && on.close();
|
|
44
|
+
if (dialog && dialog.$el && dialog.$el.parentNode) {
|
|
45
|
+
dialog.$el.parentNode.removeChild(dialog.$el);
|
|
46
|
+
dialog.$destroy();
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
Vue.nextTick(() => {
|
|
52
|
+
document.body.appendChild(dialog.$el);
|
|
53
|
+
on.open && on.open();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return { dialog, close };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Vue.prototype.$dialogFnByJsx = dialogFn;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<el-button @click="show">案例1jsx</el-button>
|
|
4
|
+
<el-button @click="show1">案例2jsx</el-button>
|
|
5
|
+
<span>{{ obj.a }}</span>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import com from "./com.vue";
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: "DialogFn",
|
|
14
|
+
components: {
|
|
15
|
+
com,
|
|
16
|
+
},
|
|
17
|
+
data() {
|
|
18
|
+
return {
|
|
19
|
+
obj: {
|
|
20
|
+
a: 1,
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
methods: {
|
|
25
|
+
beforeClose(done) {
|
|
26
|
+
console.log("beforeClose");
|
|
27
|
+
done();
|
|
28
|
+
},
|
|
29
|
+
show() {
|
|
30
|
+
// 确保在打开新对话框前关闭旧的
|
|
31
|
+
const dialogConfig = {
|
|
32
|
+
slots: {
|
|
33
|
+
default: (
|
|
34
|
+
<com
|
|
35
|
+
nameProps="defaultSlot"
|
|
36
|
+
closeDialog={() => close()}
|
|
37
|
+
obj={this.obj}
|
|
38
|
+
showBtn={true}
|
|
39
|
+
> <el-button type='text'>anniu</el-button></com>
|
|
40
|
+
),
|
|
41
|
+
title: <com nameProps="标题titleSlot" />,
|
|
42
|
+
footer: (
|
|
43
|
+
<div>
|
|
44
|
+
<el-button onClick={() => close()}>取消</el-button>
|
|
45
|
+
<el-button type="primary" onClick={() => {}}>
|
|
46
|
+
确定
|
|
47
|
+
</el-button>
|
|
48
|
+
</div>
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
props: {
|
|
53
|
+
title: "标题",
|
|
54
|
+
width: "500px",
|
|
55
|
+
top: "100px",
|
|
56
|
+
beforeClose: this.beforeClose,
|
|
57
|
+
destroyOnClose: true, // 关闭时销毁内容
|
|
58
|
+
},
|
|
59
|
+
on: {
|
|
60
|
+
close: () => {
|
|
61
|
+
console.log("关闭close");
|
|
62
|
+
},
|
|
63
|
+
open: () => {
|
|
64
|
+
console.log("打开opened");
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const { close } = this.$dialogFnByJsx(dialogConfig);
|
|
70
|
+
},
|
|
71
|
+
show1() {
|
|
72
|
+
const dialogConfig = {
|
|
73
|
+
slots: {
|
|
74
|
+
default: (
|
|
75
|
+
<com
|
|
76
|
+
nameProps="简单案例"
|
|
77
|
+
closeDialog={() => close()}
|
|
78
|
+
showBtn={true}
|
|
79
|
+
> </com>
|
|
80
|
+
),
|
|
81
|
+
},
|
|
82
|
+
props: {
|
|
83
|
+
title: "标题",
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
const { close } = this.$dialogFnByJsx(dialogConfig);
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
</script>
|
package/package.json
CHANGED
package/app/pei3d.vue
DELETED
|
@@ -1,579 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<!-- 3D饼图容器组件 -->
|
|
3
|
-
<div class="mff-main" style="position: relative;">
|
|
4
|
-
<div style="display: flex;
|
|
5
|
-
justify-content: center;
|
|
6
|
-
position: absolute;
|
|
7
|
-
z-index: 1;
|
|
8
|
-
left: 50%;
|
|
9
|
-
transform: translateX(-50%);
|
|
10
|
-
" v-if="isShowBtn">
|
|
11
|
-
<el-button
|
|
12
|
-
type="text"
|
|
13
|
-
size="small"
|
|
14
|
-
@click="toggleEqualHeight">{{ isEqualHeight ? "不等高" : "等高" }}</el-button>
|
|
15
|
-
<el-button
|
|
16
|
-
type="text"
|
|
17
|
-
size="small"
|
|
18
|
-
@click="toggleRotate">{{ isRotate ? '停止旋转' : '开始旋转' }}</el-button>
|
|
19
|
-
</div>
|
|
20
|
-
<!-- echarts图表容器 -->
|
|
21
|
-
<div class="mff-charts" :id="`mff-charts-${id}`"></div>
|
|
22
|
-
</div>
|
|
23
|
-
</template>
|
|
24
|
-
<script>
|
|
25
|
-
// 引入echarts核心库
|
|
26
|
-
import * as echarts from "echarts";
|
|
27
|
-
// 引入echarts-gl插件以支持3D图表
|
|
28
|
-
import "echarts-gl";
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @description 3D饼图组件
|
|
32
|
-
* 该组件基于echarts-gl实现了一个可交互的3D饼图
|
|
33
|
-
* 支持鼠标悬停高亮、点击选中等交互效果
|
|
34
|
-
*/
|
|
35
|
-
export default {
|
|
36
|
-
name: "MffCharts",
|
|
37
|
-
props: {
|
|
38
|
-
// 饼图数据
|
|
39
|
-
optionData: {
|
|
40
|
-
type: Array,
|
|
41
|
-
default: () => [],
|
|
42
|
-
},
|
|
43
|
-
id: {
|
|
44
|
-
type: String,
|
|
45
|
-
default: "",
|
|
46
|
-
required: true,
|
|
47
|
-
},
|
|
48
|
-
isShowBtn: {
|
|
49
|
-
type: Boolean,
|
|
50
|
-
default: true,
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
data() {
|
|
54
|
-
return {
|
|
55
|
-
// 控制所有扇区是否等高,true表示所有扇区高度相同
|
|
56
|
-
isEqualHeight: false,
|
|
57
|
-
// 是否旋转
|
|
58
|
-
isRotate: false,
|
|
59
|
-
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
mounted() {
|
|
63
|
-
// 组件挂载后初始化3D饼图
|
|
64
|
-
this.init();
|
|
65
|
-
},
|
|
66
|
-
methods: {
|
|
67
|
-
|
|
68
|
-
// 切换所有扇区是否等高
|
|
69
|
-
toggleEqualHeight() {
|
|
70
|
-
this.isEqualHeight = !this.isEqualHeight;
|
|
71
|
-
this.init(false);
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
// 切换是否旋转
|
|
75
|
-
toggleRotate() {
|
|
76
|
-
this.isRotate =!this.isRotate;
|
|
77
|
-
this.init(true);
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @description 初始化3D饼图
|
|
82
|
-
* 创建echarts实例,生成3D饼图配置,添加标签引导线
|
|
83
|
-
*/
|
|
84
|
-
init(isInit = false) {
|
|
85
|
-
console.log(1111);
|
|
86
|
-
|
|
87
|
-
// 初始化echarts实例
|
|
88
|
-
let myChart = echarts.init(
|
|
89
|
-
document.getElementById(`mff-charts-${this.id}`)
|
|
90
|
-
);
|
|
91
|
-
// 生成3D饼图配置,0.8为内部空心比例
|
|
92
|
-
this.option = this.getPie3D(this.optionData, 0.8);
|
|
93
|
-
// myChart.setOption(this.option,isInit);
|
|
94
|
-
// 添加透明2D饼图用于显示标签引导线
|
|
95
|
-
// 通过调整起始角度和方向使引导线与3D饼图对齐
|
|
96
|
-
const data = this.optionData.map((item) => {
|
|
97
|
-
return {
|
|
98
|
-
value: item.value,
|
|
99
|
-
name: item.name,
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
this.option.series.push({
|
|
103
|
-
name: "pie2d",
|
|
104
|
-
type: "pie",
|
|
105
|
-
itemStyle: {
|
|
106
|
-
// opacity: 0,
|
|
107
|
-
color: 'rgba(0,0,0,0)',
|
|
108
|
-
},
|
|
109
|
-
labelLine: {
|
|
110
|
-
show: !this.isRotate,
|
|
111
|
-
length: 20,
|
|
112
|
-
length2: 10,
|
|
113
|
-
},
|
|
114
|
-
label: {
|
|
115
|
-
show: true,
|
|
116
|
-
color: "#fff",
|
|
117
|
-
fontSize: 12,
|
|
118
|
-
formatter: function (params) {
|
|
119
|
-
return `${params.name}\n${params.value}\n${params.percent}%`;
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
startAngle: -40, //起始角度,支持范围[0, 360]。
|
|
123
|
-
clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
|
|
124
|
-
radius: ["20%", "50%"],
|
|
125
|
-
center: ["50%", "50%"],
|
|
126
|
-
data,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
130
|
-
myChart.setOption(this.option, isInit);
|
|
131
|
-
this.bindListen(myChart);
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* @description 生成3D饼图的配置项
|
|
136
|
-
* @param {Array} pieData 饼图数据数组
|
|
137
|
-
* @param {number} internalDiameterRatio 内部空心占比(0-1)
|
|
138
|
-
* @returns {Object} echarts配置项
|
|
139
|
-
*/
|
|
140
|
-
getPie3D(pieData, internalDiameterRatio) {
|
|
141
|
-
//internalDiameterRatio:透明的空心占比
|
|
142
|
-
let that = this;
|
|
143
|
-
let series = [];
|
|
144
|
-
let sumValue = 0;
|
|
145
|
-
let startValue = 0;
|
|
146
|
-
let endValue = 0;
|
|
147
|
-
let legendData = [];
|
|
148
|
-
let legendBfb = [];
|
|
149
|
-
let k = 1 - internalDiameterRatio;
|
|
150
|
-
pieData.sort((a, b) => {
|
|
151
|
-
return b.value - a.value;
|
|
152
|
-
});
|
|
153
|
-
// 为每一个饼图数据,生成一个 series-surface 配置
|
|
154
|
-
for (let i = 0; i < pieData.length; i++) {
|
|
155
|
-
sumValue += pieData[i].value;
|
|
156
|
-
let seriesItem = {
|
|
157
|
-
name:
|
|
158
|
-
typeof pieData[i].name === "undefined"
|
|
159
|
-
? `series${i}`
|
|
160
|
-
: pieData[i].name,
|
|
161
|
-
type: "surface",
|
|
162
|
-
parametric: true,
|
|
163
|
-
wireframe: {
|
|
164
|
-
show: false,
|
|
165
|
-
},
|
|
166
|
-
pieData: pieData[i],
|
|
167
|
-
pieStatus: {
|
|
168
|
-
selected: false,
|
|
169
|
-
hovered: false,
|
|
170
|
-
k: k,
|
|
171
|
-
},
|
|
172
|
-
center: ["10%", "50%"],
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
if (typeof pieData[i].itemStyle != "undefined") {
|
|
176
|
-
let itemStyle = {};
|
|
177
|
-
typeof pieData[i].itemStyle.color != "undefined"
|
|
178
|
-
? (itemStyle.color = pieData[i].itemStyle.color)
|
|
179
|
-
: null;
|
|
180
|
-
typeof pieData[i].itemStyle.opacity != "undefined"
|
|
181
|
-
? (itemStyle.opacity = pieData[i].itemStyle.opacity)
|
|
182
|
-
: null;
|
|
183
|
-
seriesItem.itemStyle = itemStyle;
|
|
184
|
-
}
|
|
185
|
-
series.push(seriesItem);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
|
|
189
|
-
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
|
|
190
|
-
legendData = [];
|
|
191
|
-
legendBfb = [];
|
|
192
|
-
for (let i = 0; i < series.length; i++) {
|
|
193
|
-
endValue = startValue + series[i].pieData.value;
|
|
194
|
-
series[i].pieData.startRatio = startValue / sumValue;
|
|
195
|
-
series[i].pieData.endRatio = endValue / sumValue;
|
|
196
|
-
series[i].parametricEquation = this.getParametricEquation(
|
|
197
|
-
series[i].pieData.startRatio,
|
|
198
|
-
series[i].pieData.endRatio,
|
|
199
|
-
false,
|
|
200
|
-
false,
|
|
201
|
-
k,
|
|
202
|
-
series[i].pieData.value
|
|
203
|
-
);
|
|
204
|
-
startValue = endValue;
|
|
205
|
-
let bfb = that.fomatFloat(series[i].pieData.value / sumValue, 4);
|
|
206
|
-
legendData.push({
|
|
207
|
-
name: series[i].name,
|
|
208
|
-
value: bfb,
|
|
209
|
-
});
|
|
210
|
-
legendBfb.push({
|
|
211
|
-
name: series[i].name,
|
|
212
|
-
value: bfb,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
let boxHeight = this.getHeight3D(series, 26);
|
|
216
|
-
//通过传参设定3d饼/环的高度,26代表26px
|
|
217
|
-
// 准备待返回的配置项,把准备好的 legendData、series 传入。
|
|
218
|
-
let option = {
|
|
219
|
-
legend: {
|
|
220
|
-
show: false,
|
|
221
|
-
},
|
|
222
|
-
labelLine: {
|
|
223
|
-
show: false,
|
|
224
|
-
},
|
|
225
|
-
|
|
226
|
-
tooltip: {
|
|
227
|
-
formatter: (params) => {
|
|
228
|
-
if (
|
|
229
|
-
params.seriesName !== "mouseoutSeries" &&
|
|
230
|
-
params.seriesName !== "pie2d"
|
|
231
|
-
) {
|
|
232
|
-
let bfb = (
|
|
233
|
-
(option.series[params.seriesIndex].pieData.endRatio -
|
|
234
|
-
option.series[params.seriesIndex].pieData.startRatio) *
|
|
235
|
-
100
|
|
236
|
-
).toFixed(2);
|
|
237
|
-
return (
|
|
238
|
-
`${params.seriesName}<br/>` +
|
|
239
|
-
`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
|
|
240
|
-
this.formatNumberWithCommas(option.series[params.seriesIndex].pieData.value)
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
xAxis3D: {
|
|
246
|
-
min: -1,
|
|
247
|
-
max: 1,
|
|
248
|
-
},
|
|
249
|
-
yAxis3D: {
|
|
250
|
-
min: -1,
|
|
251
|
-
max: 1,
|
|
252
|
-
},
|
|
253
|
-
zAxis3D: {
|
|
254
|
-
min: -1,
|
|
255
|
-
max: 2,
|
|
256
|
-
},
|
|
257
|
-
grid3D: {
|
|
258
|
-
show: false,
|
|
259
|
-
boxHeight: boxHeight, //圆环的高度
|
|
260
|
-
viewControl: {
|
|
261
|
-
//3d效果可以放大、旋转等,请自己去查看官方配置
|
|
262
|
-
alpha: 44, //角度
|
|
263
|
-
distance: 280, //调整视角到主体的距离,类似调整zoom
|
|
264
|
-
rotateSensitivity: 0, //设置为0无法旋转
|
|
265
|
-
zoomSensitivity: 0, //设置为0无法缩放
|
|
266
|
-
panSensitivity: 0, //设置为0无法平移
|
|
267
|
-
autoRotate: this.isRotate, //自动旋转
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
series: series,
|
|
271
|
-
};
|
|
272
|
-
return option;
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
//获取3d丙图的最高扇区的高度
|
|
276
|
-
/**
|
|
277
|
-
* @description 计算3D饼图的高度
|
|
278
|
-
* @param {Array} series 系列数据
|
|
279
|
-
* @param {number} height 基础高度
|
|
280
|
-
* @returns {number} 计算后的高度
|
|
281
|
-
*/
|
|
282
|
-
getHeight3D(series, height) {
|
|
283
|
-
// if(this.isEqualHeight) return height * 3;
|
|
284
|
-
series.sort((a, b) => {
|
|
285
|
-
return b.pieData.value - a.pieData.value;
|
|
286
|
-
});
|
|
287
|
-
return (height * 25) / series[0].pieData.value;
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
// 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
|
|
291
|
-
/**
|
|
292
|
-
* @description 生成3D扇形的参数方程
|
|
293
|
-
* @param {number} startRatio 起始比例
|
|
294
|
-
* @param {number} endRatio 结束比例
|
|
295
|
-
* @param {boolean} isSelected 是否被选中
|
|
296
|
-
* @param {boolean} isHovered 是否被悬停
|
|
297
|
-
* @param {number} k 内外径比例
|
|
298
|
-
* @param {number} h 高度
|
|
299
|
-
* @returns {Object} 参数方程对象
|
|
300
|
-
*/
|
|
301
|
-
getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
|
|
302
|
-
if (this.isEqualHeight) {
|
|
303
|
-
if(this.id === "1") {
|
|
304
|
-
h = 20000;
|
|
305
|
-
}
|
|
306
|
-
if(this.id === "2") {
|
|
307
|
-
h = 1500;
|
|
308
|
-
}
|
|
309
|
-
// // 添加缩放因子,使大数值的柱子间距更合理
|
|
310
|
-
}
|
|
311
|
-
k = k * 1.3;
|
|
312
|
-
|
|
313
|
-
// 计算
|
|
314
|
-
let midRatio = (startRatio + endRatio) / 2;
|
|
315
|
-
let startRadian = startRatio * Math.PI * 2;
|
|
316
|
-
let endRadian = endRatio * Math.PI * 2;
|
|
317
|
-
let midRadian = midRatio * Math.PI * 2;
|
|
318
|
-
// 如果只有一个扇形,则不实现选中效果。
|
|
319
|
-
if (startRatio === 0 && endRatio === 1) {
|
|
320
|
-
isSelected = false;
|
|
321
|
-
}
|
|
322
|
-
// 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
|
|
323
|
-
k = typeof k !== "undefined" ? k : 1 / 3;
|
|
324
|
-
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
|
|
325
|
-
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
|
|
326
|
-
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
|
|
327
|
-
// 计算高亮效果的放大比例(未高亮,则比例为 1)
|
|
328
|
-
let hoverRate = isHovered ? 1.05 : 1;
|
|
329
|
-
// 返回曲面参数方程
|
|
330
|
-
return {
|
|
331
|
-
u: {
|
|
332
|
-
min: -Math.PI,
|
|
333
|
-
max: Math.PI * 3,
|
|
334
|
-
step: Math.PI / 32,
|
|
335
|
-
},
|
|
336
|
-
v: {
|
|
337
|
-
min: 0,
|
|
338
|
-
max: Math.PI * 2,
|
|
339
|
-
step: Math.PI / 20,
|
|
340
|
-
},
|
|
341
|
-
x: function (u, v) {
|
|
342
|
-
if (u < startRadian) {
|
|
343
|
-
return (
|
|
344
|
-
offsetX +
|
|
345
|
-
Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
if (u > endRadian) {
|
|
349
|
-
return (
|
|
350
|
-
offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
|
|
354
|
-
},
|
|
355
|
-
y: function (u, v) {
|
|
356
|
-
if (u < startRadian) {
|
|
357
|
-
return (
|
|
358
|
-
offsetY +
|
|
359
|
-
Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
if (u > endRadian) {
|
|
363
|
-
return (
|
|
364
|
-
offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
|
|
368
|
-
},
|
|
369
|
-
z: function (u, v) {
|
|
370
|
-
if (u < -Math.PI * 0.5) {
|
|
371
|
-
return Math.sin(u);
|
|
372
|
-
}
|
|
373
|
-
if (u > Math.PI * 2.5) {
|
|
374
|
-
return Math.sin(u) * h * 0.1;
|
|
375
|
-
}
|
|
376
|
-
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
},
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @description 格式化浮点数
|
|
383
|
-
* @param {number} num 需要格式化的数字
|
|
384
|
-
* @param {number} n 保留小数位数
|
|
385
|
-
* @returns {string} 格式化后的字符串
|
|
386
|
-
*/
|
|
387
|
-
fomatFloat(num, n) {
|
|
388
|
-
var f = parseFloat(num);
|
|
389
|
-
if (isNaN(f)) {
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂
|
|
393
|
-
var s = f.toString();
|
|
394
|
-
var rs = s.indexOf(".");
|
|
395
|
-
//判定如果是整数,增加小数点再补0
|
|
396
|
-
if (rs < 0) {
|
|
397
|
-
rs = s.length;
|
|
398
|
-
s += ".";
|
|
399
|
-
}
|
|
400
|
-
while (s.length <= rs + n) {
|
|
401
|
-
s += "0";
|
|
402
|
-
}
|
|
403
|
-
return s;
|
|
404
|
-
},
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* @description 绑定图表交互事件
|
|
408
|
-
* @param {Object} myChart echarts实例
|
|
409
|
-
* 实现饼图的选中效果(单选)和高亮(放大)效果
|
|
410
|
-
*/
|
|
411
|
-
bindListen(myChart) {
|
|
412
|
-
// // 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
|
|
413
|
-
// let that = this;
|
|
414
|
-
// let selectedIndex = "";
|
|
415
|
-
// let hoveredIndex = "";
|
|
416
|
-
// 监听点击事件,实现选中效果(单选)
|
|
417
|
-
myChart.on("click", function (params) {
|
|
418
|
-
console.log('click');
|
|
419
|
-
|
|
420
|
-
return
|
|
421
|
-
// 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
|
|
422
|
-
let isSelected =
|
|
423
|
-
!that.option.series[params.seriesIndex].pieStatus.selected;
|
|
424
|
-
let isHovered =
|
|
425
|
-
that.option.series[params.seriesIndex].pieStatus.hovered;
|
|
426
|
-
let k = that.option.series[params.seriesIndex].pieStatus.k;
|
|
427
|
-
let startRatio =
|
|
428
|
-
that.option.series[params.seriesIndex].pieData.startRatio;
|
|
429
|
-
let endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
|
|
430
|
-
// 如果之前选中过其他扇形,将其取消选中(对 option 更新)
|
|
431
|
-
if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) {
|
|
432
|
-
that.option.series[selectedIndex].parametricEquation =
|
|
433
|
-
that.getParametricEquation(
|
|
434
|
-
that.option.series[selectedIndex].pieData.startRatio,
|
|
435
|
-
that.option.series[selectedIndex].pieData.endRatio,
|
|
436
|
-
false,
|
|
437
|
-
false,
|
|
438
|
-
k,
|
|
439
|
-
that.option.series[selectedIndex].pieData.value
|
|
440
|
-
);
|
|
441
|
-
that.option.series[selectedIndex].pieStatus.selected = false;
|
|
442
|
-
}
|
|
443
|
-
// 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
|
|
444
|
-
that.option.series[params.seriesIndex].parametricEquation =
|
|
445
|
-
that.getParametricEquation(
|
|
446
|
-
startRatio,
|
|
447
|
-
endRatio,
|
|
448
|
-
isSelected,
|
|
449
|
-
isHovered,
|
|
450
|
-
k,
|
|
451
|
-
that.option.series[params.seriesIndex].pieData.value
|
|
452
|
-
);
|
|
453
|
-
that.option.series[params.seriesIndex].pieStatus.selected = isSelected;
|
|
454
|
-
// 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
|
|
455
|
-
isSelected ? (selectedIndex = params.seriesIndex) : null;
|
|
456
|
-
// 使用更新后的 option,渲染图表
|
|
457
|
-
myChart.setOption(that.option);
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
return
|
|
461
|
-
// 监听 mouseover,近似实现高亮(放大)效果
|
|
462
|
-
myChart.on("mouseover", function (params) {
|
|
463
|
-
// 准备重新渲染扇形所需的参数
|
|
464
|
-
let isSelected;
|
|
465
|
-
let isHovered;
|
|
466
|
-
let startRatio;
|
|
467
|
-
let endRatio;
|
|
468
|
-
let k;
|
|
469
|
-
// 如果触发 mouseover 的扇形当前已高亮,则不做操作
|
|
470
|
-
if (hoveredIndex === params.seriesIndex) {
|
|
471
|
-
return;
|
|
472
|
-
// 否则进行高亮及必要的取消高亮操作
|
|
473
|
-
} else {
|
|
474
|
-
// 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
|
|
475
|
-
if (hoveredIndex !== "") {
|
|
476
|
-
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
|
|
477
|
-
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
|
|
478
|
-
isHovered = false;
|
|
479
|
-
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
|
|
480
|
-
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
|
|
481
|
-
k = that.option.series[hoveredIndex].pieStatus.k;
|
|
482
|
-
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
|
|
483
|
-
that.option.series[hoveredIndex].parametricEquation =
|
|
484
|
-
that.getParametricEquation(
|
|
485
|
-
startRatio,
|
|
486
|
-
endRatio,
|
|
487
|
-
isSelected,
|
|
488
|
-
isHovered,
|
|
489
|
-
k,
|
|
490
|
-
that.option.series[hoveredIndex].pieData.value
|
|
491
|
-
);
|
|
492
|
-
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
|
|
493
|
-
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
|
|
494
|
-
hoveredIndex = "";
|
|
495
|
-
}
|
|
496
|
-
// 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
|
|
497
|
-
if (
|
|
498
|
-
params.seriesName !== "mouseoutSeries" &&
|
|
499
|
-
params.seriesName !== "pie2d"
|
|
500
|
-
) {
|
|
501
|
-
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
|
|
502
|
-
isSelected =
|
|
503
|
-
that.option.series[params.seriesIndex].pieStatus.selected;
|
|
504
|
-
isHovered = true;
|
|
505
|
-
startRatio =
|
|
506
|
-
that.option.series[params.seriesIndex].pieData.startRatio;
|
|
507
|
-
endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
|
|
508
|
-
k = that.option.series[params.seriesIndex].pieStatus.k;
|
|
509
|
-
// 对当前点击的扇形,执行高亮操作(对 option 更新)
|
|
510
|
-
that.option.series[params.seriesIndex].parametricEquation =
|
|
511
|
-
that.getParametricEquation(
|
|
512
|
-
startRatio,
|
|
513
|
-
endRatio,
|
|
514
|
-
isSelected,
|
|
515
|
-
isHovered,
|
|
516
|
-
k,
|
|
517
|
-
that.option.series[params.seriesIndex].pieData.value + 5
|
|
518
|
-
);
|
|
519
|
-
that.option.series[params.seriesIndex].pieStatus.hovered =
|
|
520
|
-
isHovered;
|
|
521
|
-
// 记录上次高亮的扇形对应的系列号 seriesIndex
|
|
522
|
-
hoveredIndex = params.seriesIndex;
|
|
523
|
-
}
|
|
524
|
-
// 使用更新后的 option,渲染图表
|
|
525
|
-
myChart.setOption(that.option);
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
// 修正取消高亮失败的 bug
|
|
529
|
-
myChart.on("globalout", function () {
|
|
530
|
-
// 准备重新渲染扇形所需的参数
|
|
531
|
-
let isSelected;
|
|
532
|
-
let isHovered;
|
|
533
|
-
let startRatio;
|
|
534
|
-
let endRatio;
|
|
535
|
-
let k;
|
|
536
|
-
if (hoveredIndex !== "") {
|
|
537
|
-
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
|
|
538
|
-
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
|
|
539
|
-
isHovered = false;
|
|
540
|
-
k = that.option.series[hoveredIndex].pieStatus.k;
|
|
541
|
-
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
|
|
542
|
-
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
|
|
543
|
-
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
|
|
544
|
-
that.option.series[hoveredIndex].parametricEquation =
|
|
545
|
-
that.getParametricEquation(
|
|
546
|
-
startRatio,
|
|
547
|
-
endRatio,
|
|
548
|
-
isSelected,
|
|
549
|
-
isHovered,
|
|
550
|
-
k,
|
|
551
|
-
that.option.series[hoveredIndex].pieData.value
|
|
552
|
-
);
|
|
553
|
-
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
|
|
554
|
-
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
|
|
555
|
-
hoveredIndex = "";
|
|
556
|
-
}
|
|
557
|
-
// 使用更新后的 option,渲染图表
|
|
558
|
-
myChart.setOption(that.option);
|
|
559
|
-
});
|
|
560
|
-
},
|
|
561
|
-
|
|
562
|
-
formatNumberWithCommas(num) {
|
|
563
|
-
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
564
|
-
}
|
|
565
|
-
},
|
|
566
|
-
};
|
|
567
|
-
</script>
|
|
568
|
-
|
|
569
|
-
<style scoped>
|
|
570
|
-
.mff-main {
|
|
571
|
-
width: 100%;
|
|
572
|
-
height: 100%;
|
|
573
|
-
background-color: #000a3b;
|
|
574
|
-
}
|
|
575
|
-
.mff-charts {
|
|
576
|
-
width: 100%;
|
|
577
|
-
height: 100%;
|
|
578
|
-
}
|
|
579
|
-
</style>
|