UNPKG

light-chart

Version:

Charts for mobile visualization.

315 lines (271 loc) 9.91 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>带旋转的饼图</title> <link rel="stylesheet" href="./assets/common.css"> <style> .wrapper { position: relative; height: 100%; } canvas { display: block; } .flag { position: absolute; bottom: 30px; width: 24px; height: 24px; left: 50%; margin-left: -12px; background-image: url("https://gw.alipayobjects.com/zos/rmsportal/eCukcsfJoNgSIvKtFniY.png") } #content { width: 100%; text-align: center; } </style> </head> <body> <div> <div class="wrapper"> <canvas id="pieRotate"></canvas> <div class="flag"></div> </div> <div id="content"></div> </div> <script src="./assets/jquery-3.2.1.min.js"></script> <script src="../build/f2-all.js"></script> <script src="./assets/hammer.js"></script> <script> // 绘制饼图 const { Util, G, Chart } = F2; const Matrix = G.Matrix; const data = [ {name: 'A',proportion: 0.8,a: '1'}, {name: 'B',proportion: 0.5,a: '1'}, {name: 'C',proportion: 0.45,a: '1'}, {name: 'D',proportion: 0.15,a: '1'}, {name: 'E',proportion: 0.12,a: '1' }, {name: 'F',proportion: 0.1, a: '1' }, {name: 'G',proportion: 0.03,a: '1'} ]; const chart = new Chart({ id: 'pieRotate', width: window.innerWidth, height: window.innerWidth * 0.64, pixelRatio: window.devicePixelRatio }); chart.source(data); chart.legend(false); chart.coord('polar', { transposed: true, radius: 0.8 }); chart.axis(false); chart.tooltip(false); const geom = chart.interval() .position('a*proportion') .color('name', ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#E6965C', '#223273', '#7564CC', '#8543E0', '#5C8EE6', '#13C2C2', '#5CA3E6']) .adjust('stack') .style({ lineWidth: 1, stroke: '#fff' }); chart.render(); // 开始交互逻辑 // 一些辅助工具类函数 const center = chart.get('coord').center; // 极坐标的圆点 const container = geom.get('container'); const canvas = chart.get('canvas'); const el = canvas.get('el'); let animating = false; // 动画状态标识位 function interpolateNumber(a, b) { a = +a; b -= a; return function (t) { return a + b * t; }; } function findShapeByName(name) { let result; const shapes = geom.get('container').get('children'); Util.each(shapes, shape => { const origin = shape.get('origin')._origin; if (origin.name === name) { result = shape; return false; } }); return result; } function repaintChart(angle) { const chartCoord = chart.get('coord'); const coordStart = chartCoord.startAngle + angle; const coordEnd = chartCoord.endAngle + angle; chart.coord('polar', { transposed: true, radius: 0.8, startAngle: coordStart, endAngle: coordEnd }); chart.animate(false); chart.repaint(); } function animation(angle, data, animateCfg) { const rotateAngle = Math.PI / 2 - angle; const diff = interpolateNumber(0, rotateAngle); if (rotateAngle !== 0) { container.animate().to(animateCfg).onFrame(t => { animating = true; const frameAngle = diff(t); container.setTransform([ ['t', center.x, center.y], ['r', frameAngle], ['t', -center.x, -center.y] ]); if (t === 1) { animating = false; repaintChart(rotateAngle); $('#content').html(data._origin.name + ': ' + data._origin.proportion); } }); } } let lastMouseAngle; let totalAngle; chart.pluginGesture({ options: { useCalculate: false, // 计算手势数据点,如果不需要可以关闭提高性能 useOffset: false // 计算数据是否需要计算图表相对页面偏移的坐标。当图表宽度超出, scroll模式,计算位置需要加上滚动记录 }, gesture: { tap: (data, e) => { if (animating) return; const currentPoint = e.center; const record = chart.getSnapRecords(currentPoint)[0]; if (!record) return; const shape = findShapeByName(record._origin.name); if (shape) { const startAngle = shape.attr('startAngle'); const endAngle = shape.attr('endAngle'); let middleAngle = (startAngle + endAngle) / 2; if (startAngle > endAngle && endAngle <= 0) { middleAngle = (Math.PI * 2 - Math.abs(startAngle - endAngle)) / 2 + startAngle; if (middleAngle > 1.5 * Math.PI) { middleAngle = middleAngle - 2 * Math.PI; } } animation(middleAngle, record, { duration: 650, easing: 'backOut' }); } }, 'panstart panmove panend': (data, e) => { if (animating) return; const currentPoint = e.center; const newMouseAngle = Math.atan2(currentPoint.y - center.y, currentPoint.x - center.x) + Math.PI; if (e.type === 'panstart') { lastMouseAngle = newMouseAngle; totalAngle = 0; } else if (e.type === 'panmove') { const diffAngle = newMouseAngle - lastMouseAngle; totalAngle += diffAngle; container.transform([ ['t', center.x, center.y], ['r', diffAngle], ['t', -center.x, -center.y] ]); canvas.draw(); } else if (e.type === 'panend') { repaintChart(totalAngle); const shapes = container.get('children'); let middleAngle = Math.PI * 0.5; let rotateShape; Util.each(shapes, s => { const startAngle = s.attr('startAngle'); const endAngle = s.attr('endAngle'); if (startAngle <= Math.PI * 0.5 && endAngle >= Math.PI * 0.5) { rotateShape = s; middleAngle = (startAngle + endAngle) / 2; return false; } }); animation(middleAngle, rotateShape.get('origin'), { duration: 250, easing: 'backOut' }); } lastMouseAngle = newMouseAngle; } } }); /* const hammer = new Hammer(el); // 点击操作 hammer.on('tap', e => { if (animating) return; const currentPoint = e.center; const record = chart.getSnapRecords(currentPoint)[0]; if (!record) return; const shape = findShapeByName(record._origin.name); if (shape) { const startAngle = shape.attr('startAngle'); const endAngle = shape.attr('endAngle'); let middleAngle = (startAngle + endAngle) / 2; if (startAngle > endAngle && endAngle <= 0) { middleAngle = (Math.PI * 2 - Math.abs(startAngle - endAngle)) / 2 + startAngle; if (middleAngle > 1.5 * Math.PI) { middleAngle = middleAngle - 2 * Math.PI; } } animation(middleAngle, { duration: 650, easing: 'backOut' }); } }); let lastMouseAngle; let totalAngle; hammer.on('panstart panmove panend', e => { if (animating) return; const currentPoint = e.center; const newMouseAngle = Math.atan2(currentPoint.y - center.y, currentPoint.x - center.x) + Math.PI; if (e.type === 'panstart') { lastMouseAngle = newMouseAngle; totalAngle = 0; } else if (e.type === 'panmove') { const diffAngle = newMouseAngle - lastMouseAngle; totalAngle += diffAngle; container.transform([ ['t', center.x, center.y], ['r', diffAngle], ['t', -center.x, -center.y] ]); canvas.draw(); } else if (e.type === 'panend') { repaintChart(totalAngle); const shapes = container.get('children'); let middleAngle = Math.PI * 0.5; Util.each(shapes, s => { const startAngle = s.attr('startAngle'); const endAngle = s.attr('endAngle'); if (startAngle <= Math.PI * 0.5 && endAngle >= Math.PI * 0.5) { rotateShape = s; middleAngle = (startAngle + endAngle) / 2; return false; } }); animation(middleAngle, { duration: 350, easing: 'backOut' }); } lastMouseAngle = newMouseAngle; }); */ </script> </body> </html>