1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <script src="./echarts.js"></script>
6 </head>
7 <body>
8 <div id="myChart" style="width: 800px; height: 600px;"></div>
9
10 <script type="text/javascript">
11 var chart = echarts.init(document.getElementById('myChart'));
12
13 var originData = [
14 {value: 335, name: '直接访问'},
15 {value: 310, name: '邮件营销'},
16 {value: 234, name: '联盟广告'},
17 {value: 135, name: '视频广告'},
18 {value: 1548, name: '搜索引擎'},
19 ];
20
21 var color = ['#4a6dbf', '#15b3bc', '#f37a18', '#83c775', ' #fcb552'];
22
23 originData.forEach(function(list, i) {
24 list.itemStyle = {
25 color: color[i],
26 };
27 });
28
29 var data = [].slice.call(originData)
30
31 var option = {
32 tooltip: {
33 },
34 toolbox: {
35 feature: {
36 myRestore: {
37 show: true,
38 title: '还原',
39 icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',
40 onclick: refreshChart,
41 },
42 },
43 },
44 legend: { // 图例
45 icon: 'rect',
46 data: [],
47 itemWidth: 12,
48 itemHeight: 12,
49 bottom: 'bottom',
50 },
51 grid: {
52 top: '5%',
53 left: '5%',
54 right: '5%',
55 bottom: '40',
56 containLabel: true,
57 },
58 xAxis: {
59 type: 'category',
60 boundaryGap: true,
61 splitLine: { // grid上每一条竖轴线
62 show: true,
63 interval: 'auto',
64 lineStyle: {
65 color: '#e8e8e8',
66 },
67 },
68 axisLine: { // x刻度上方的横轴线
69 lineStyle: {
70 color: '#e8e8e8',
71 },
72 },
73 axisLabel: { // x轴的刻度
74 textStyle: {
75 color: '#999',
76 },
77 },
78 data: [],
79 },
80 yAxis: {
81 type: 'value',
82 boundaryGap: false,
83 axisLine: { // y刻度上方的横轴线
84 lineStyle: {
85 color: '#e8e8e8',
86 },
87 },
88 splitLine: { // grid上每一条竖轴线
89 lineStyle: {
90 color: '#e8e8e8',
91 },
92 },
93 axisLabel: { // y轴的刻度
94 textStyle: {
95 color: '#999',
96 },
97 },
98 },
99 series: [{
100 name: 'pie',
101 type: 'pie',
102 center: ['50%', '45%'],
103 radius: ['0', '45%'],
104 data: data,
105 }, {
106 name: '模拟一个pie容器',
107 type: 'pie',
108 center: ['50%', '45%'],
109 radius: ['0', '49%'],
110 cursor: 'default',
111 hoverAnimation: true,
112 hoverOffset: 2,
113 label: {
114 show: false,
115 },
116 labelLine: {
117 show: false,
118 },
119 tooltip: {
120 padding: 0,
121 formatter: function() {
122 return '';
123 },
124 },
125 z: 0,
126 data: [{
127 value: 0,
128 name: '容器',
129 itemStyle: {
130 color: '#000',
131 opacity: '.1',
132 },
133 }],
134 }],
135 };
136
137 chart.setOption(option, true);
138
139 var sector = null; // 鼠标点击选中的扇形
140 var sectorIndex; // 选中扇形在data中的index
141 var sx; // 原型横坐标距离鼠标位置横坐标的偏移距离
142 var sy; // 原型纵坐标距离鼠标位置纵坐标的偏移距离
143 var zr = chart.getZr(); // 生成一个zrender实例
144 var circleData = null; // 记录鼠标选中的小圆点的数据
145 var circleEl = []; // 保存生成的小圆点的数据,注意目前只有push,没有将废数据清除
146
147 function refreshChart() {
148 data = [].slice.call(originData)
149 option.series = {
150 name: 'pie',
151 type: 'pie',
152 center: ['50%', '45%'],
153 radius: ['0', '45%'],
154 data: data,
155 };
156
157 circleEl.forEach(function(list) {
158 zr.remove(list.el);
159 });
160 // zr.clear(); // clear会把整个chart画布清除
161 sector = null;
162 chart.setOption(option, true);
163 }
164
165 // chart.on 绑定的事件只能在chart图形内部执行
166 // 利用chart绑定的事件会比zrender绑定的事件先执行的特点来判断小圆是否进入饼图范围
167 chart.on('mouseup', function(params) {
168 if (params.componentSubType === 'pie') {
169 // 圆
170 if (circleData) {
171 data.push(circleData.data);
172 chart.setOption({
173 series: {
174 data: data,
175 }
176 });
177 zr.remove(circleData.el);
178 circleData = null;
179 }
180
181 // 扇形
182 if (sector) {
183 zr.remove(sector);
184 sector = null;
185 }
186 }
187 });
188
189 zr.on('mousedown', function(e) {
190 // 如果出现:触发鼠标点击扇形事件,并且移动到echarts的DOM元素外,释放鼠标点击,
191 // 再移动到饼图内,点击鼠标,则会再次触发一个鼠标点击和释放事件,这时候,上一个选中的扇形不会被正确的移除
192 // 所以在mosuedown多一个对sector的判定
193 if (e.target && sector) {
194 zr.remove(sector);
195 sector = null;
196 }
197 if (e.topTarget) {
198 // 这个是pie容器
199 if (e.target && e.target.seriesIndex === 1) {
200 return;
201 }
202
203 // 发现一个圆
204 circleEl.forEach(function(list) {
205 if (list.id === e.topTarget.id) {
206 circleData = list;
207 }
208 });
209
210 // 是一个扇形
211 if (!circleData && e.target && !e.target.__title) {
212 var target = e.target;
213 sectorIndex = target.dataIndex;
214 sector = new echarts.graphic.Sector({
215 shape: echarts.util.extend({}, target.shape),
216 style: {
217 fill: target.style.fill,
218 opacity: 0.5
219 },
220 silent: true,
221 z: 1000,
222 });
223
224 sx = e.offsetX - target.shape.cx;
225 sy = e.offsetY - target.shape.cy;
226
227 zr.add(sector);
228
229 }
230 }
231 });
232
233 zr.on('mousemove', function (e) {
234 if (circleData) {
235 circleData.el.setShape({
236 cx: e.offsetX,
237 cy: e.offsetY,
238 });
239 } else if (sector) {
240 sector.setShape({
241 cx: e.offsetX - sx,
242 cy: e.offsetY - sy,
243 });
244
245 chart.dispatchAction({
246 type: 'showTip',
247 seriesIndex: 0,
248 dataIndex: sectorIndex,
249 position: [e.offsetX + 24, e.offsetY + 24], // 加24是为了避免tip影响mouseup事件判定
250 });
251 }
252 });
253
254 zr.on('mouseup', function(e) {
255 if (circleData) {
256 circleData = null;
257 } if (sector) {
258 var circle = new echarts.graphic.Circle({
259 shape: {
260 cx: e.offsetX,
261 cy: e.offsetY,
262 r: 10,
263 },
264 style: {
265 text: data[sectorIndex].name + ':' + data[sectorIndex].value,
266 textFill: sector.style.fill,
267 fill: sector.style.fill,
268 textOffset: [0, -20],
269 },
270 silent: true,
271 z: 1000,
272 });
273 zr.add(circle);
274 circleEl.push({
275 id: e.topTarget.id + 1,
276 el: circle,
277 data: data[sectorIndex],
278 });
279
280 data.splice(sectorIndex, 1);
281 chart.setOption({
282 series: {
283 data: data,
284 }
285 });
286
287 zr.remove(sector);
288 sector = null;
289 }
290 });
291 </script>
292 </body>
293 </html>
这个是一年前工作里用到,莫名翻了出来。