Angular2使用SVG自定义图表(条形图、折线图)组件示例
程序员文章站
2022-03-20 14:59:09
本文实例讲述了angular2使用svg自定义图表(条形图、折线图)组件。分享给大家供大家参考,具体如下:
要求:用户将数据作为参数传进来,通过类型决定渲染何种类型的图标...
本文实例讲述了angular2使用svg自定义图表(条形图、折线图)组件。分享给大家供大家参考,具体如下:
要求:用户将数据作为参数传进来,通过类型决定渲染何种类型的图标。
demo:
html:
<ngo-chart [inputparams]="options"></ngo-chart>
ts:
options = { type: 'line', //图表类型 xaxis: { //x轴的数据 data: ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] }, yaxis: { //x轴的数据 data: [120, 220, 150, 111, -150, 55, 60], }, width: 600, //宽 height: 500, //高 datapadding: 8 //条形图之间的距离 };
效果:
源代码:
import { input, oninit, viewchild, component, viewencapsulation, elementref, afterviewinit, changedetectorref, } from '@angular/core'; import { ngochartsvgparams, scale, axis, chart } from './chart-svg-params'; @component({ selector: 'ngo-chart-svg', templateurl: './chart-svg.html', styleurls: ['./chart-svg.scss'], encapsulation: viewencapsulation.native }) export class ngochartsvg implements oninit, afterviewinit { @input() inputparams: ngochartsvgparams; @viewchild('svg') svg: elementref; @viewchild('polyline') polyline: elementref; params: ngochartsvgparams; axisy: axis; // y轴 axisx: axis; // x轴 valuetopxratio: number; // 值转px的比率 y0: number; // 坐标轴 (0,0)的y轴 yscale: array<scale> = []; // y轴刻度值 xscale: array<scale> = []; // x轴刻度值 xgapwidth: number; // x轴刻度之间的间隙宽度 data: array<chart> = []; color: string; type: string; polylinepoints: string; polylinelength: number; constructor( private ele: elementref, private cd: changedetectorref ) { } ... ngoninit() { this.initparams(); const svg = this.svg.nativeelement; const _width = this.params.width; const _height = this.params.height; svg.setattribute('width', _width); svg.setattribute('height', _height); // 绘制 y轴 this.drawaxisy(); this.drawscaley(); // 绘制 x轴 this.drawaxisx(); this.drawscalex(); this.drawrect(); if (this.params.type === 'line') { this.drawline(); } } ngafterviewinit() { if (this.polyline) { this.polylinelength = this.polyline.nativeelement.gettotallength(); this.cd.detectchanges(); } } }
html
<svg #svg> <!-- y轴 --> <g> <line [attr.x1]="axisy.x1" [attr.y1]="axisy.y1+15" [attr.x2]="axisy.x2" [attr.y2]="axisy.y2" [attr.stroke]="color" [attr.fill]="color" style="stroke-width:3" /> <polygon [attr.points]="axisy.arrow" /> <ng-container *ngfor="let scale of yscale"> <line class="dash" [attr.x1]="scale.x1" [attr.x2]="scale.x2" [attr.y1]="scale.y1" [attr.y2]="scale.y2" stroke="rgba(0,0,0,0.3)" /> <text class="_label" [attr.x]="scale.x1-5" style="text-anchor: end" [attr.y]="scale.y1" [attr.fill]="color" [attr.fill]="color">{{scale.label}}</text> </ng-container> </g> <!-- x轴 --> <g> <line [attr.x1]="axisx.x1-15" [attr.x2]="axisx.x2" [attr.y1]="axisx.y1" [attr.y2]="axisx.y2" [attr.stroke]="color" [attr.fill]="color" style="stroke-width:3" /> <polygon [attr.points]="axisx.arrow" /> <ng-container *ngfor="let scale of xscale"> <line [attr.x1]="scale.x1" [attr.x2]="scale.x2" [attr.y1]="scale.y1" [attr.y2]="scale.y2" [attr.stroke]="color" [attr.fill]="color" style="stroke-width:1" /> <text class="_label" [attr.x]="scale.x1-xgapwidth/2" [attr.y]="axisy.y1+15" [attr.fill]="color" style="text-anchor: middle;">{{scale.label}}</text> </ng-container> </g> <!-- 矩形 --> <ng-container *ngif="type==='bar'"> <text x="10" y="20" fill="red">bar</text> <g> <ng-container *ngfor="let item of data"> <ng-container *ngif="item.value<=0"> <rect class="_rect" [attr.x]="item.x" [attr.y]="item.y" [attr.width]="item.w" [attr.height]="item.h" fill="color"> <animate attributename="height" [attr.from]="item.h*0.6" [attr.to]="item.h" begin="0s" dur="1.1s" /> </rect> <text [attr.x]="item.x+item.w/2" [attr.y]="item.y+item.h-5" fill="white" style="text-anchor: middle;">{{item.value}}</text> </ng-container> <ng-container *ngif="item.value>0"> <rect [attr.x]="item.x" [attr.y]="item.y" [attr.width]="item.w" [attr.height]="item.h" fill="color"> <animate attributename="y" [attr.from]="item.y+item.h*0.4" [attr.to]="item.y" begin="0s" dur="1.1s" /> <animate attributename="height" [attr.from]="item.h*0.6" [attr.to]="item.h" begin="0s" dur="1.1s" /> </rect> <text class="_label" [attr.x]="item.x+item.w/2" [attr.y]="item.y+18" fill="white" style="text-anchor: middle;">{{item.value}} <animate attributename="opacity" from="0" to="1" begin="0s" dur="1.1s" /> </text> </ng-container> </ng-container> </g> </ng-container> <!--折线 --> <ng-container *ngif="type==='line'"> <text x="10" y="20" fill="red">line</text> <g> <polyline #polyline class="_polyline" [attr.points]="polylinepoints" fill="none" [attr.stroke]='color' [attr.stroke-dasharray]="polylinelength" [attr.stroke-dashoffset]="polylinelength" /> <ng-container *ngfor="let item of data"> <circle [attr.cx]="item.x+item.w/2" [attr.cy]="item.y" r="2" [attr.fill]="color" [attr.stroke]='color' /> <text class="_label" [attr.x]="item.x+item.w/2" [attr.y]="item.y+20" fill="white" style="text-anchor: middle;">{{item.value}} <animate attributename="opacity" from="0" to="1" begin="0s" dur="1.1s" /> </text> </ng-container> </g> </ng-container> </svg>
css
svg { background: rgba(0, 0, 0, 0.2); border: 1px solid black; } svg * { position: static; font-size: 16px; } ._polyline { fill: none; animation: linemove 1.5s ease-in-out forwards; } @keyframes linemove { to { stroke-dashoffset: 0; } }
一、初始化参数
//首先获取传入的参数 @input() inputparams; //初始化 const _params: ngochartsvgparams = { xaxis: this.inputparams.xaxis, yaxis: this.inputparams.yaxis, type: this.inputparams.type ? this.inputparams.type : 'bar', width: this.inputparams.width ? this.inputparams.width : 700, height: this.inputparams.height ? this.inputparams.height : 500, datapadding: this.inputparams.datapadding !== undefined ? this.inputparams.datapadding : 8, yscaleno: this.inputparams.yscaleno >= 3 ? this.inputparams.yscaleno : 6, }; this.color = 'black'; this.type = _params.type; this.params = _params;
二:绘制坐标轴y轴
const _height = this.params.height; const _pad = this.params.padding; const _arrow = _pad + ',' + (_pad - 5) + ' ' + (_pad - 6) + ',' + (_pad + 12) + ' ' + (_pad + 6) + ',' + (_pad + 12); this.axisy = { x1: _pad, y1: _height - _pad, x2: _pad, y2: _pad, arrow: _arrow };
三、绘制y轴的刻度
const _height = this.params.height; const _width = this.params.width; // 显示label的边距 const _padding = this.params.padding; const _ydata = this.params.yaxis.data; // 显示的刻度数 const _yscaleno = this.params.yscaleno; const _datamax = this.getminandmaxdata(_ydata).datamax; const _datamin = this.getminandmaxdata(_ydata).datamin; let _yminvalue; let _ygapvalue; if (_datamin < 0) { _ygapvalue = math.ceil((_datamax - _datamin) / (_yscaleno) / 10) * 10; _yminvalue = math.floor(_datamin / _ygapvalue) * _ygapvalue; } else { _ygapvalue = math.ceil((_datamax) / (_yscaleno) / 10) * 10; _yminvalue = 0; } // y轴坐标点 const _y2 = this.axisy.y2; const _y1 = this.axisy.y1; const _x1 = this.axisy.x1; // y轴刻度的间隙宽度 const _ygapwidth = (_y1 - _y2) / (this.params.yscaleno); this.valuetopxratio = _ygapvalue / _ygapwidth; // 坐标轴(0,0)的y轴坐标 const _y0 = _y1 - math.abs(_yminvalue / this.valuetopxratio); this.y0 = _y0; for (let i = 0; i < this.params.yscaleno; i++) { const _obj: scale = { x1: 0, x2: 0, y1: 0, y2: 0, label: '', value: 0 }; _obj.x1 = _x1; _obj.y1 = _y1 - _ygapwidth * i; _obj.x2 = _x1 + _width - 2 * _padding; _obj.y2 = _y1 - _ygapwidth * i; _obj.label = _yminvalue + _ygapvalue * i; this.yscale.push(_obj); }
四、绘制x坐标轴
const _width = this.params.width; // 显示label的边距 const _pad = this.params.padding; const _x2 = _width - _pad; const _y2 = this.y0; const _arrow = (_x2 + 5) + ',' + _y2 + ' ' + (_x2 - 10) + ',' + (_y2 - 6) + ' ' + (_x2 - 10) + ',' + (_y2 + 6); this.axisx = { x1: _pad, y1: _y2, x2: _x2, y2: _y2, arrow: _arrow };
五、绘制x轴刻度
const _width = this.params.width; const _xdata = this.params.xaxis.data; const _ydata = this.params.yaxis.data; const y0 = this.y0; const _x1 = this.axisx.x1; const _x2 = this.axisx.x2; const xgapwidth = ((_x2 - _x1) / (this.params.xaxis.data.length + 1)); this.xgapwidth = xgapwidth; for (let i = 0; i < _xdata.length; i++) { const _obj: scale = { x1: 0, x2: 0, y1: 0, y2: 0, value: 0, label: '' }; _obj.y1 = y0; _obj.y2 = y0 + 5; _obj.label = _xdata[i]; _obj.value = _ydata[i]; _obj.x1 = _x1 + xgapwidth * (i + 1); _obj.x2 = _x1 + xgapwidth * (i + 1); this.xscale.push(_obj);
六、绘制矩形
const _value = this.params.yaxis.data; const _datapadding = this.params.datapadding; const _xgapwidth = this.xgapwidth; for (let i = 0; i < _value.length; i++) { const element = _value[i]; const _obj: chart = { x: 0, y: 0, w: 0, h: 0, value: 0 }; _obj.w = _xgapwidth - 2 * _datapadding; _obj.x = this.xscale[i].x1 - _obj.w - _datapadding; _obj.h = math.abs(this.xscale[i].value / this.valuetopxratio); _obj.value = this.xscale[i].value; if (this.xscale[i].value >= 0) { _obj.y = this.y0 - (this.xscale[i].value) / this.valuetopxratio; } else { _obj.y = this.y0; } this.data.push(_obj); } }
七、绘制折线
const _data = this.data; let _str = ''; _data.foreach(ele => { if (ele.value < 0) { ele.y = ele.y + ele.h; } _str += (ele.x + ele.w / 2) + ',' + ele.y + ' '; }); this.polylinepoints = _str;
上一篇: 这3大妙招快速调经 女生必读