The pie chart
Last time in the middle of the year, I said that I used SVG to draw a pie chart. This article will describe the process in detail. This article is a component written under the VUe-CLI scaffolding project
The environment
version
-
vue2.*
-
Snapsvg – > 0.5.1
-
Imports – loader – > 0.8.0
The important thing to note here is the version of the imports- Loader, which will cause the following import method to fail
The installation
npm install --save snapsvg || yarn add snapsvg
npm install --save-dev imports-loader@0.8. 0 || yarn add imports-loader@0.8. 0 --save-dev
Copy the code
The introduction of
// In the vUE component,
const snap = require(`imports-loader? this=>window,fix=>module.exports=0! snapsvg/dist/snap.svg.js`)
Copy the code
hands-on
Train of thought
- Figure out the proportions from the data
- Calculate the Angle in terms of proportion
- Calculate the finished coordinates based on the angles and initial coordinates
code
pie.vue
<template> <svg :id="id" :width="width" :height="height"></svg> </template> <script> const snap = require(`imports-loader? this=>window,fix=>module.exports=0! snapsvg/dist/snap.svg.js`); export default { name: "svg-pie", props: { width: { // eslint-disable-next-line vue/require-prop-type-constructor type: Number | String, default: "100%", }, height: { // eslint-disable-next-line vue/require-prop-type-constructor type: Number | String, default: "100%", }, r: { type: Number, default: 70, }, id: { type: String, required: true, }, title: { type: String, required: true, }, num: { type: Number, required: true, }, cx: { type: Number, default: 85, }, cy: { type: Number, default: 85, }, data: { type: Array, required: true, }, }, mounted() { this.init(); }, watch: { data() { this.init(); },}, methods: {init() {// If data has no data return if (this.data.length < 0) return; // snap SVG instance let s = snap(' #${this.id '); // let r = this.r; let cx = this.cx; let cy = this.cy; let sx = cx; let sy = cy - r; let srartX = sx; let srartY = sy; let endX; let endY; let angles = 0; let largeArcFlag; let dataArry = this.data; let lh = 16; let domArr = []; Dataarry. forEach((v, I) => {let Angle = (360 * v.r) / 100; angles += angle; let radian; If (angles < 90) {radian = ((2 * math.pi) / 360) * angles; endX = sx + r * Math.sin(radian); endY = sy + r - r * Math.cos(radian); } else if (angles === 90) { endX = sx + r; endY = sy + r; } else if (angles < 180) { radian = ((2 * Math.PI) / 360) * (180 - angles); endX = sx + Math.abs(r * Math.cos(radian)); endY = sy + r + Math.abs(r * Math.sin(radian)); } else if (angles === 180) { endX = sx; endY = sy + 2 * r; } else if (angles < 270) { radian = ((2 * Math.PI) / 360) * (270 - angles); endX = sx - Math.abs(r * Math.sin(radian)); endY = sy + r + Math.abs(r * Math.cos(radian)); } else if (angles === 270) { endX = sx - r; endY = sy + r; } else if (angles === 360) { endX = sx; endY = sy; } else { radian = ((2 * Math.PI) / 360) * (360 - angles); endX = sx - Math.abs(r * Math.sin(radian)); endY = sy + r - Math.abs(r * Math.cos(radian)); } largeArcFlag = v.ratio > 50 ? 1:0; let dom = s .path( `M${srartX},${srartY}A${r},${r},${angles},${largeArcFlag},1,${endX},${endY}` ) .attr({ stroke: v.color, strokeWidth: 20, fillOpacity: 0, cursor: "pointer", }) .hover( function () { this.animate({ strokeWidth: 35,}, 100); }, function () { this.animate({ strokeWidth: 20, }, 100 ); }); domArr.push(dom); s.circle(cx - r, cy + r + 20 + lh, 3) .attr({ fill: v.color, strokeWidth: 0, stroke: "#000", }) .hover( function () { domArr[i].animate({ strokeWidth: 35, }, 100 ); }, function () { domArr[i].animate({ strokeWidth: 20, }, 100 ); }); let titleDom = s .text(cx - r + 10, cy + r + lh + 25, v.title) .hover( function () { domArr[i].animate({ strokeWidth: 35,}, 100); }, function () { domArr[i].animate({ strokeWidth: 20, }, 100 ); } ) .attr({ cursor: "pointer", }); if (v.blodArr) { v.blodArr.forEach((val) => { titleDom.node.childNodes[val].style.fontWeight = "bold"; }); } lh += 20; srartX = endX; srartY = endY; }); S. circle(cx, cy, r-7.5). Attr ({fill: "#e3eaef", strokeWidth: 0,}); s.circle(cx, cy, r - 15).attr({ fill: "#fff", strokeWidth: 0, }); s.text(cx, cy - 8, this.title).attr({ textAnchor: "middle", }); s.text(cx, cy + 20, this.num).attr({ fontSize: "16px", fill: "#6462fe", fontWeight: "bold", textAnchor: "middle", }); ,}}}; </script>Copy the code
use
App.vue
< the template > < div id = "app" > < Pie id = "course" title = "total" : num = "22" : r = "60" : width = "600" : height = "600" : cy = "100" :data="data" /> </div> </template> <script> import Pie from "./components/pie.vue"; export default { name: "App", components: { Pie, }, data() { return { data: [{ blodArr: [2, 5], color: "#635ffd", num: 11, percent: 50, thewire: 50, title: [" type a ", "", 11," a ", "", 50," % "]}, {blodArr: [2, 5], color: "# 666", num: 11, percent: 50, thewire: 50, title: [" type 2 ", "", 11," a ", "", 50," % "]}],}; }}; </script>Copy the code
The meaning of each attribute
The property name | instructions |
---|---|
title | The contents of the middle disk |
num | The contents of the middle disk |
r | The radius of |
width | SVG wide |
height | SVG is high |
cy | The center of the circle is y |
cx | The center x coordinate |
data | data |
Data detailed description of each field
key | instructions |
---|---|
color | The color of the pie chart |
num | The number of |
ratio | Accounted for |
title | It can be a string or an array |
blodArr | The subscript of the title content to bold (applies if the title is an array) |
results
conclusion
The difficulty lies in the coordinate calculation of path drawing line, I apologize to my math teacher here, I feel I am a useless person!! Click “like” after reading it!!
🏆 technology project phase iii | data visualization of those things…