zmp-react
Version:
Build full featured iOS & Android apps using ZMP & React
189 lines (168 loc) • 6.04 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import React, { forwardRef, useRef, useImperativeHandle, useState, useEffect } from 'react';
import { classNames, getExtraAttrs, emit } from '../shared/utils';
import { zmp } from '../shared/zmp';
var PieChart = /*#__PURE__*/forwardRef(function (props, ref) {
var className = props.className,
id = props.id,
style = props.style,
_props$size = props.size,
size = _props$size === void 0 ? 320 : _props$size,
_props$tooltip = props.tooltip,
tooltip = _props$tooltip === void 0 ? false : _props$tooltip,
_props$datasets = props.datasets,
datasets = _props$datasets === void 0 ? [] : _props$datasets,
formatTooltip = props.formatTooltip,
children = props.children;
var extraAttrs = getExtraAttrs(props);
var _useState = useState(null),
currentIndex = _useState[0],
setCurrentIndex = _useState[1];
var previousIndex = useRef(null);
var elRef = useRef(null);
var zmpTooltip = useRef(null);
useImperativeHandle(ref, function () {
return {
el: elRef.current
};
});
var getSummValue = function getSummValue() {
var summ = 0;
datasets.map(function (d) {
return d.value || 0;
}).forEach(function (value) {
summ += value;
});
return summ;
};
var getPaths = function getPaths() {
var paths = [];
var cumulativePercentage = 0;
function getCoordinatesForPercentage(percentage) {
var x = Math.cos(2 * Math.PI * percentage) * (size / 3);
var y = Math.sin(2 * Math.PI * percentage) * (size / 3);
return [x, y];
}
datasets.forEach(function (_ref) {
var value = _ref.value,
label = _ref.label,
color = _ref.color;
var percentage = value / getSummValue();
var _getCoordinatesForPer = getCoordinatesForPercentage(cumulativePercentage),
startX = _getCoordinatesForPer[0],
startY = _getCoordinatesForPer[1];
cumulativePercentage += percentage;
var _getCoordinatesForPer2 = getCoordinatesForPercentage(cumulativePercentage),
endX = _getCoordinatesForPer2[0],
endY = _getCoordinatesForPer2[1];
var largeArcFlag = percentage > 0.5 ? 1 : 0;
var points = ["M " + startX + " " + startY, // Move
"A " + size / 3 + " " + size / 3 + " 0 " + largeArcFlag + " 1 " + endX + " " + endY, // Arc
'L 0 0' // Line
].join(' ');
paths.push({
points: points,
label: label,
color: color
});
});
return paths;
};
var formatTooltipText = function formatTooltipText() {
if (currentIndex === null) return '';
var _datasets$currentInde = datasets[currentIndex],
value = _datasets$currentInde.value,
label = _datasets$currentInde.label,
color = _datasets$currentInde.color;
var percentage = value / getSummValue() * 100;
var round = function round(v) {
if (parseInt(v, 10) === v) return v;
return Math.round(v * 100) / 100;
};
if (formatTooltip) {
return formatTooltip({
index: currentIndex,
value: value,
label: label,
color: color,
percentage: percentage
});
}
var tooltipText = "" + (label ? label + ": " : '') + round(value) + " (" + round(percentage) + "%)";
return "\n <div class=\"pie-chart-tooltip-label\">\n <span class=\"pie-chart-tooltip-color\" style=\"background-color: " + color + ";\"></span> " + tooltipText + "\n </div>\n ";
};
var setTooltip = function setTooltip() {
if (currentIndex === null && !zmpTooltip.current) return;
if (!tooltip || !elRef.current || !zmp) return;
if (currentIndex !== null && !zmpTooltip.current) {
zmpTooltip.current = zmp.tooltip.create({
trigger: 'manual',
containerEl: elRef.current,
targetEl: elRef.current.querySelector("path[data-index=\"" + currentIndex + "\"]"),
text: formatTooltipText(),
cssClass: 'pie-chart-tooltip'
});
zmpTooltip.current.show();
return;
}
if (!zmpTooltip.current) return;
if (currentIndex !== null) {
zmpTooltip.current.setText(formatTooltipText());
zmpTooltip.current.setTargetEl(elRef.current.querySelector("path[data-index=\"" + currentIndex + "\"]"));
zmpTooltip.current.show();
} else {
zmpTooltip.current.hide();
}
};
useEffect(function () {
if (previousIndex.current === currentIndex) return;
previousIndex.current = currentIndex;
emit(props, 'select', currentIndex, datasets[currentIndex]);
setTooltip();
}, [currentIndex]);
useEffect(function () {
return function () {
if (zmpTooltip.current && zmpTooltip.current.destroy) {
zmpTooltip.current.destroy();
}
zmpTooltip.current = null;
};
}, []);
var classes = classNames('pie-chart', className);
var paths = getPaths();
return /*#__PURE__*/React.createElement("div", _extends({
id: id,
style: style,
className: classes,
ref: elRef
}, extraAttrs), /*#__PURE__*/React.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: size,
height: size,
viewBox: "-" + size / 3 + " -" + size / 3 + " " + size * 2 / 3 + " " + size * 2 / 3,
style: {
transform: 'rotate(-90deg)'
}
}, paths.map(function (path, index) {
return /*#__PURE__*/React.createElement("path", {
key: path.label || index,
d: path.points,
fill: path.color,
"data-index": index,
className: classNames({
'pie-chart-hidden': currentIndex !== null && currentIndex !== index
}),
onClick: function onClick() {
return setCurrentIndex(index);
},
onMouseEnter: function onMouseEnter() {
return setCurrentIndex(index);
},
onMouseLeave: function onMouseLeave() {
return setCurrentIndex(null);
}
});
})), children);
});
PieChart.displayName = 'zmp-pie-chart';
export default PieChart;