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

  1. Figure out the proportions from the data
  2. Calculate the Angle in terms of proportion
  3. 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…