气泡图
这里做的气泡图是柱形图的一种变体形式,但是基本思想其实差不多,只不过柱形的高矮换成的半径的大小,当然圆心的坐标也要随之改变,圆心的纵坐标要加上跟半径同比例的缩放系数才能保证圆的底部都在同一条水平线上
图一
function ybChart(data
, index
) {
var dataMax
= 0
for (let i
= 0; i
< data
.length
; i
++) {
data
[i
].riskNumber
= parseFloat(data
[i
].riskNumber
)
if (data
[i
].riskNumber
>= dataMax
) {
dataMax
= data
[i
].riskNumber
}
}
var canvas
= document
.querySelector("#cav7");
var zeroPoint
= [0, canvas
.clientHeight
- 10];
var cav
= canvas
.getContext("2d");
cav
.clearRect(0, 0, canvas
.clientWidth
, canvas
.clientHeight
);
var canvasBGHeight
= canvas
.clientHeight
- 20;
var startRowLinePosition
= canvas
.clientWidth
/ data
.length
/2;
var circlePointX
= canvas
.clientWidth
/ data
.length
/2;
var circlePointY
= canvas
.clientHeight
* 3 / 5;
var circleRadio
= canvas
.clientWidth
/data
.length
/2;
cav
.drawImage(
ybBG
,
0,
10,
canvas
.clientWidth
,
canvasBGHeight
);
for (let i
= 0; i
< data
.length
; i
++) {
cav
.beginPath();
cav
.moveTo(startRowLinePosition
- 10, zeroPoint
[1] - 3);
cav
.lineTo(startRowLinePosition
+ 10, zeroPoint
[1] - 3);
cav
.lineWidth
= 3;
cav
.setLineDash([1, 0]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
var normalBall
= cav
.createLinearGradient(
circlePointX
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointY
+ circleRadio
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointX
+ (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointY
+ circleRadio
- (circleRadio
* data
[i
].riskNumber
) / dataMax
);
normalBall
.addColorStop(0, "#5128FF");
normalBall
.addColorStop(1, "#9F77FF");
var lightHighBall
= cav
.createLinearGradient(
circlePointX
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointY
+ circleRadio
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointX
+ (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circlePointY
+ circleRadio
- (circleRadio
* data
[i
].riskNumber
) / dataMax
);
lightHighBall
.addColorStop(0, "#B444FC");
lightHighBall
.addColorStop(1, "#F14B6F");
var circleRadioYPosition
=
circlePointY
+ circleRadio
- (circleRadio
* data
[i
].riskNumber
) / dataMax
;
cav
.beginPath();
cav
.arc(
circlePointX
,
circleRadioYPosition
,
(circleRadio
* data
[i
].riskNumber
) / dataMax
,
0,
Math
.PI * 2,
false
);
cav
.fillStyle
= i
== index
? lightHighBall
: normalBall
;
cav
.fill();
if (i
== index
) {
cav
.beginPath();
cav
.moveTo(startRowLinePosition
, zeroPoint
[1] - 3);
cav
.lineTo(startRowLinePosition
, 10);
cav
.lineWidth
= 2;
cav
.setLineDash([3, 2]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
cav
.beginPath();
cav
.moveTo(0, circleRadioYPosition
);
cav
.lineTo(canvas
.clientWidth
, circleRadioYPosition
);
cav
.lineWidth
= 2;
cav
.setLineDash([3, 2]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
cav
.beginPath();
cav
.arc(circlePointX
, circleRadioYPosition
, 4, 0, Math
.PI * 2, false);
cav
.fillStyle
= "#fff";
cav
.fill();
cav
.beginPath();
cav
.arc(
circlePointX
,
circleRadioYPosition
,
(circleRadio
* data
[i
].riskNumber
) / dataMax
+ 5,
0,
Math
.PI * 2,
false
);
cav
.strokeStyle
= "#fff";
cav
.lineWidth
= 1;
cav
.setLineDash([1, 0]);
cav
.stroke();
if (
circleRadioYPosition
+ floatBG
.height
>=
canvasBGHeight
) {
var floatBGPositionY
=
circleRadioYPosition
- floatBG
.height
;
} else {
var floatBGPositionY
=
circleRadioYPosition
- floatBG
.height
/ 2;
}
var floatBGWidth
=
(floatBG
.width
* data
[i
].riskName
.length
) / 10 + 20;
if (index
< 3) {
var floatBGPositionX
= circlePointX
+ 5;
} else {
var floatBGPositionX
= circlePointX
- floatBGWidth
- 5;
}
var floatLineColor
= cav
.createLinearGradient(
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10,
floatBGPositionX
+ floatBGWidth
+ 5,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
floatLineColor
.addColorStop(0, "rgba(255, 255, 255,0)");
floatLineColor
.addColorStop(1, "rgba(255, 255, 255,1)");
} else {
cav
.beginPath();
cav
.moveTo(startRowLinePosition
, zeroPoint
[1] - 3);
cav
.lineTo(startRowLinePosition
, zeroPoint
[1] - 70);
cav
.lineWidth
= 2;
cav
.setLineDash([1, 0]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
}
circlePointX
+= canvas
.clientWidth
/ data
.length
;
startRowLinePosition
+= canvas
.clientWidth
/ data
.length
;
}
cav
.drawImage(
floatBG
,
floatBGPositionX
,
floatBGPositionY
,
floatBGWidth
,
80
);
cav
.beginPath();
cav
.moveTo(
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
cav
.lineTo(
floatBGPositionX
+ floatBGWidth
- 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
cav
.setLineDash([2, 1]);
cav
.strokeStyle
= floatLineColor
;
cav
.stroke();
cav
.textAlign
= "start";
cav
.textBaseline
= "bottom";
cav
.font
= "16px MeicrosoftYahei";
cav
.fillStyle
= "#fff";
cav
.fillText(
data
[index
].riskName
,
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 15
);
cav
.textAlign
= "start";
cav
.textBaseline
= "top";
cav
.font
= "bold 36px Akrobat-Black";
cav
.fillStyle
= "#fff";
cav
.fillText(
data
[index
].riskNumber
+ "%",
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 5
);
}
图二
这个图标跟上面那个其实差不多,只不过这里的圆心Y坐标的计算公式不一样 画布高度+圆心半径*数据比值-数据比值*画布高度+顶部预留高度
JS
function floatBallChart(data
, index
) {
var dataMax
= 0
for (let i
= 0; i
< data
.length
; i
++) {
data
[i
].riskNumber
= parseFloat(data
[i
].riskNumber
)
if (data
[i
].riskNumber
>= dataMax
) {
dataMax
= data
[i
].riskNumber
}
}
var canvas
= document
.querySelector("#cav10");
var zeroPoint
= [0, canvas
.clientHeight
- 10];
var cav
= canvas
.getContext("2d");
cav
.clearRect(0, 0, canvas
.clientWidth
, canvas
.clientHeight
);
var canvasBGHeight
= canvas
.clientHeight
- 20;
var startRowLinePosition
= canvas
.clientWidth
/ data
.length
*3/4+20;
var circlePointX
= canvas
.clientWidth
/ data
.length
*3/4+20;
var circleRadio
= canvas
.clientWidth
/data
.length
-10
cav
.drawImage(
ybBG
,
0,
10,
canvas
.clientWidth
,
canvasBGHeight
);
for (let i
= 0; i
< data
.length
; i
++) {
var circleRadioYPosition
=
canvasBGHeight
+circleRadio
*data
[i
].riskNumber
/ dataMax
- data
[i
].riskNumber
/ dataMax
*canvasBGHeight
+20;
var normalBall
= cav
.createLinearGradient(
circlePointX
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circleRadioYPosition
,
circlePointX
+ (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circleRadioYPosition
);
normalBall
.addColorStop(0, "#9F77FF");
normalBall
.addColorStop(1, "#9F77FF");
var lightHighBall
= cav
.createLinearGradient(
circlePointX
- (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circleRadioYPosition
,
circlePointX
+ (circleRadio
* data
[i
].riskNumber
) / dataMax
,
circleRadioYPosition
);
lightHighBall
.addColorStop(0, "#B444FC");
lightHighBall
.addColorStop(1, "#F14B6F");
cav
.beginPath();
cav
.arc(
circlePointX
,
circleRadioYPosition
,
(circleRadio
* data
[i
].riskNumber
) / dataMax
,
0,
Math
.PI * 2,
false
);
cav
.fillStyle
= i
== index
? 'rgba(222, 72, 154,0.3)' : 'rgba(119, 78, 255,0.3)';
cav
.fill();
if (i
== index
) {
cav
.beginPath();
cav
.moveTo(startRowLinePosition
, zeroPoint
[1] - 3);
cav
.lineTo(startRowLinePosition
, 10);
cav
.lineWidth
= 2;
cav
.setLineDash([3, 2]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
cav
.beginPath();
cav
.moveTo(0, circleRadioYPosition
);
cav
.lineTo(canvas
.clientWidth
, circleRadioYPosition
);
cav
.lineWidth
= 2;
cav
.setLineDash([3, 2]);
cav
.strokeStyle
= "#fff";
cav
.stroke();
cav
.beginPath();
cav
.arc(circlePointX
, circleRadioYPosition
, 4, 0, Math
.PI * 2, false);
cav
.fillStyle
= "#fff";
cav
.fill();
cav
.beginPath();
cav
.arc(
circlePointX
,
circleRadioYPosition
,
(circleRadio
* data
[i
].riskNumber
) / dataMax
+ 5,
0,
Math
.PI * 2,
false
);
cav
.strokeStyle
= "#fff";
cav
.lineWidth
= 1;
cav
.setLineDash([1, 0]);
cav
.stroke();
if (
circleRadioYPosition
+ floatBG
.height
>=
canvasBGHeight
) {
var floatBGPositionY
=
circleRadioYPosition
- floatBG
.height
;
} else {
var floatBGPositionY
=
circleRadioYPosition
- floatBG
.height
/ 2;
}
var floatBGWidth
=
(floatBG
.width
* data
[i
].riskName
.length
) / 10 + 20;
if (index
< 3) {
var floatBGPositionX
= circlePointX
+ 5;
} else {
var floatBGPositionX
= circlePointX
- floatBGWidth
- 5;
}
var floatLineColor
= cav
.createLinearGradient(
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10,
floatBGPositionX
+ floatBGWidth
+ 5,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
floatLineColor
.addColorStop(0, "rgba(255, 255, 255,0)");
floatLineColor
.addColorStop(1, "rgba(255, 255, 255,1)");
}
circlePointX
+= canvas
.clientWidth
/ data
.length
*3/4;
startRowLinePosition
+= canvas
.clientWidth
/ data
.length
*3/4;
}
cav
.drawImage(
floatBG
,
floatBGPositionX
,
floatBGPositionY
,
floatBGWidth
,
80
);
cav
.beginPath();
cav
.moveTo(
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
cav
.lineTo(
floatBGPositionX
+ floatBGWidth
- 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 10
);
cav
.setLineDash([2, 1]);
cav
.strokeStyle
= floatLineColor
;
cav
.stroke();
cav
.textAlign
= "start";
cav
.textBaseline
= "bottom";
cav
.font
= "16px MeicrosoftYahei";
cav
.fillStyle
= "#fff";
cav
.fillText(
data
[index
].riskName
,
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 15
);
cav
.textAlign
= "start";
cav
.textBaseline
= "top";
cav
.font
= "bold 36px Akrobat-Black";
cav
.fillStyle
= "#fff";
cav
.fillText(
data
[index
].riskNumber
+ "%",
floatBGPositionX
+ 10,
floatBGPositionY
+ floatBG
.height
/ 2 - 5
);
}