react-radial-bar-chart
Version:
react component about radial bar chart
124 lines (110 loc) • 3.91 kB
JavaScript
import { randomColor } from 'color-conversion-rgb';
const incre = (Math.PI) / 18;
const circumference = Math.PI * 2;
const baseAngle = (2 * Math.PI) / 360;
const partCircumference = Math.PI / 2;
export const startRadius = -partCircumference; // start with 12: 00 direction
const getEndRadius = (percent) => {
return percent && (((circumference * percent) - partCircumference));
};
// percent direct out
const isPercentDirectOut = (percent) => {
return percent <= 0.25 || percent > 0.75;
};
// get point position
export const getPointPosition = ({ center, radius, percent, fontSize }) => {
const angle = baseAngle * ((360 * percent) - 90);
let realRadius = null;
if (isPercentDirectOut(percent)) { // percent direction is not same
realRadius = radius - (fontSize / 2);
} else {
realRadius = radius + (fontSize / 4); // back to orign size calc
}
return { x: center.x + (realRadius * Math.cos(angle)), y: (center.y + (realRadius * Math.sin(angle))) };
};
// get rotate
export const getRotate = ({ endRadius, percent }) => {
if (isPercentDirectOut(percent)) { // percent direction is not same
return endRadius - startRadius;
}
return endRadius + startRadius;
};
export const getTextAlignPercent = (percent) => {
if (isPercentDirectOut(percent)) {
return 'end';
}
return 'start';
};
export const getTextPercent = (percent) => {
if (isPercentDirectOut(percent)) {
return `${percent} `;
}
return ` ${percent}`;
};
export const getLineWidth = ({ list, max }) => {
const len = list.length;
const distanceLen = (len - 1) / 2;
return parseFloat((max - 16) / (len + distanceLen), 10);
};
// temp Angle change
export const changeTmpAngle = (tmpAngleList, endRadiusList) => {
let num = 0;
const length = endRadiusList.length;
for (let i = 0; i < length; i += 1) {
if (tmpAngleList[i] >= endRadiusList[i]) {
num += 1;
} else if (tmpAngleList[i] + incre > endRadiusList[i]) {
tmpAngleList[i] = endRadiusList[i];
} else {
tmpAngleList[i] += incre;
}
}
return num === length;
};
export const generateListObject = ({ list, maxRadius, lineWidth, distance }) => {
const radiusList = [];
const tmpAngleList = [];
const percentList = [];
const nameList = [];
const endRadiusList = [];
const strokeStyleList = [];
list.forEach((single, index) => {
radiusList.push(maxRadius - ((lineWidth + distance) * index));
tmpAngleList.push(startRadius);
percentList.push(single.percent);
nameList.push(single.name);
endRadiusList.push(getEndRadius(single.percent));
strokeStyleList.push(single.backgroundColor || randomColor(index));
});
return { radiusList, tmpAngleList, percentList, nameList, endRadiusList, strokeStyleList };
};
export const inWitchRing = ({ radiusList, endRadiusList, eventPosition, center, lineWidth, ratio, distance }) => {
if (!eventPosition) return null;
const x = (eventPosition.x * ratio) - center.x;
const y = (eventPosition.y * ratio) - center.y;
const pRadius = Math.sqrt((x * x) + (y * y)); // point radius
const halfLineWidth = lineWidth / 2;
for (let i = 0; i < radiusList.length; i += 1) {
const beginRadius = radiusList[i] - halfLineWidth - distance;
const endRadius = radiusList[i] + halfLineWidth;
if (pRadius >= beginRadius && pRadius <= endRadius && checkPointInRing({ x, y, endRadius: endRadiusList[i] })) {
return i;
}
}
return null;
};
// point is in this ring
const checkPointInRing = ({ x, y, endRadius }) => {
const xyangle = Math.atan(y / x) * (180 / Math.PI);
return endRadius > getEndRadius(getRealAngleByQuadrant({ xyangle, x, y }) / 360);
};
const getRealAngleByQuadrant = ({ xyangle, x, y }) => {
if (x >= 0 && y >= 0) {
return 90 - xyangle;
} else if (x >= 0 && y < 0) {
return 90 + xyangle;
} else if (x < 0 && y < 0) {
return 270 - xyangle;
}
return 270 + xyangle;
};