react-score-indicator
Version:
React component to display a score with a doughnut chart
345 lines (285 loc) • 11 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = _interopDefault(require('react'));
var PropTypes = _interopDefault(require('prop-types'));
function hex2rgba(hex) {
var opacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var newhex = hex.replace('#', '');
var r = parseInt(newhex.substring(0, 2), 16);
var g = parseInt(newhex.substring(2, 4), 16);
var b = parseInt(newhex.substring(4, 6), 16);
var result = 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity / 100 + ')';
return result;
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css = "/* add css styles here (optional) */\n\n.styles_wrapper__3KXDn {\n display: block;\n font-family: sans-serif;\n text-align: center;\n margin: 0 auto;\n position: relative;\n}\n\n.styles_scoreWrapper__2ELf- {\n width: 100%;\n}\n\n.styles_rangeSvg__1TDxQ .styles_pathEl__j7uKd {\n opacity: 0.3;\n}\n\n.styles_rangeSvg__1TDxQ .styles_pathEl--active__1aVpT {\n opacity: 1;\n}\n\n.styles_scoreValue__2dBgK {\n position: absolute;\n left: 0;\n right: 0;\n width: 75%;\n max-width: 75%;\n margin: 0 auto;\n text-shadow: 0px 1px 1px #bfbfbf;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.styles_scoreValue__2dBgK .styles_value__2Y4_G {}\n\n.styles_scoreValue__2dBgK .styles_separator__1X7r0 {\n padding: 0 4px;\n}\n\n.styles_scoreValue__2dBgK .styles_maxValue__3RXTR {}\n";
var styles = { "wrapper": "styles_wrapper__3KXDn", "scoreWrapper": "styles_scoreWrapper__2ELf-", "rangeSvg": "styles_rangeSvg__1TDxQ", "pathEl": "styles_pathEl__j7uKd", "pathEl--active": "styles_pathEl--active__1aVpT", "scoreValue": "styles_scoreValue__2dBgK", "value": "styles_value__2Y4_G", "separator": "styles_separator__1X7r0", "maxValue": "styles_maxValue__3RXTR" };
styleInject(css);
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var inherits = function (subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
};
var possibleConstructorReturn = function (self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
};
var Score = function (_React$Component) {
inherits(Score, _React$Component);
function Score() {
classCallCheck(this, Score);
var _this = possibleConstructorReturn(this, (Score.__proto__ || Object.getPrototypeOf(Score)).call(this));
_this.canvas = React.createRef();
_this.ctx = null;
_this.devicePixelRatio = null;
return _this;
}
createClass(Score, [{
key: 'draw',
value: function draw(ctx) {
if (!ctx || !this.devicePixelRatio) return;
var _props = this.props,
width = _props.width,
maxAngle = _props.maxAngle,
rotation = _props.rotation,
stepsColors = _props.stepsColors,
lineGap = _props.lineGap,
lineWidth = _props.lineWidth,
scoreNumber = _props.scoreNumber,
fadedOpacity = _props.fadedOpacity;
// change size canvas when HDPI screen
var pixelRatio = this.devicePixelRatio;
var wRatio = width * pixelRatio;
this.canvas.current.width = wRatio;
this.canvas.current.height = wRatio;
var halfWidth = wRatio / 2;
var pieSize = maxAngle / stepsColors.length;
var lastval = 0;
ctx.clearRect(halfWidth * -1, halfWidth * -1, wRatio, wRatio);
ctx.resetTransform();
ctx.translate(wRatio / 2, wRatio / 2);
ctx.rotate(Math.PI * 2 * ((rotation + (360 - maxAngle - lineGap) / 2) / 360));
for (var i = 0; i < stepsColors.length; i++) {
ctx.beginPath();
ctx.arc(0, 0, halfWidth - lineWidth * pixelRatio / 2, Math.PI * 2 * ((lastval + lineGap) / 360), Math.PI * 2 * ((lastval + pieSize) / 360));
lastval += pieSize;
if (scoreNumber < i + 1) ctx.strokeStyle = hex2rgba(stepsColors[i], fadedOpacity);else ctx.strokeStyle = stepsColors[i];
ctx.lineWidth = lineWidth * pixelRatio;
ctx.stroke();
}
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
this.devicePixelRatio = window.devicePixelRatio;
this.ctx = this.canvas.current.getContext('2d');
this.draw(this.ctx);
}
}, {
key: 'render',
value: function render() {
var width = this.props.width;
this.draw(this.ctx);
return React.createElement('canvas', {
className: styles.rangeSvg,
ref: this.canvas,
style: { width: width },
width: width,
height: width
});
}
}]);
return Score;
}(React.Component);
Score.propTypes = {
scoreNumber: PropTypes.number.isRequired,
width: PropTypes.number,
lineWidth: PropTypes.number,
lineGap: PropTypes.number,
maxAngle: PropTypes.number,
rotation: PropTypes.number,
stepsColors: PropTypes.array.isRequired,
fadedOpacity: PropTypes.number
};
Score.defaultProps = {
width: 200,
lineWidth: 5,
lineGap: 5,
maxAngle: 260,
rotation: 90,
fadedOpacity: 40
};
var Score$1 = function (_React$PureComponent) {
inherits(Score$$1, _React$PureComponent);
function Score$$1() {
var _ref;
var _temp, _this, _ret;
classCallCheck(this, Score$$1);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = Score$$1.__proto__ || Object.getPrototypeOf(Score$$1)).call.apply(_ref, [this].concat(args))), _this), _this.getCurrentColor = function (num) {
var stepsColors = _this.props.stepsColors;
if (num <= 0) return stepsColors[0];
if (num > stepsColors.length) return stepsColors[stepsColors.length - 1];
return stepsColors[num - 1];
}, _temp), possibleConstructorReturn(_this, _ret);
}
createClass(Score$$1, [{
key: 'render',
value: function render() {
var _props = this.props,
value = _props.value,
maxValue = _props.maxValue,
width = _props.width,
stepsColors = _props.stepsColors,
textStyle = _props.textStyle;
var stepRange = maxValue / stepsColors.length;
var numberHighlight = Math.ceil(value / stepRange);
var valueSize = 36 * width / 200;
var maxValueSize = 20 * width / 200;
var scoreValuePosition = 25 * width / 200;
return React.createElement(
'div',
{ className: styles.scoreWrapper },
React.createElement(Score, _extends({ scoreNumber: Number(numberHighlight) }, this.props)),
React.createElement(
'div',
{
className: styles.scoreValue,
style: _extends({
bottom: scoreValuePosition,
color: this.getCurrentColor(numberHighlight)
}, textStyle)
},
React.createElement(
'span',
{ className: styles.value, style: { fontSize: valueSize } },
value
),
React.createElement(
'span',
{ className: styles.separator, style: { fontSize: maxValueSize } },
'/'
),
React.createElement(
'span',
{ className: styles.maxValue, style: { fontSize: maxValueSize } },
maxValue
)
)
);
}
}]);
return Score$$1;
}(React.PureComponent);
Score$1.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
maxValue: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
stepsColors: PropTypes.array.isRequired,
textStyle: PropTypes.object
};
Score$1.defaultProps = {
textStyle: {}
};
var DEFAULT_STEP_COLORS = ['#d12000', '#ed8d00', '#f1bc00', '#84c42b', '#53b83a', '#3da940', '#3da940', '#3da940'];
function ReactScoreIndicator(props) {
var width = props.width,
style = props.style;
return React.createElement(
'div',
{ className: styles.wrapper, style: _extends({ width: width + 'px' }, style) },
React.createElement(Score$1, props)
);
}
ReactScoreIndicator.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
maxValue: PropTypes.number.isRequired,
width: PropTypes.number,
lineWidth: PropTypes.number,
lineSpacing: PropTypes.number,
style: PropTypes.object,
textStyle: PropTypes.object,
maxAngle: PropTypes.number,
rotation: PropTypes.number,
stepsColors: PropTypes.array,
fadedOpacity: PropTypes.number
};
ReactScoreIndicator.defaultProps = {
width: 200,
maxAngle: 260,
lineWidth: 5,
lineSpacing: 5,
rotation: 90,
stepsColors: DEFAULT_STEP_COLORS,
style: {},
textStyle: {},
fadedOpacity: 40
};
module.exports = ReactScoreIndicator;
//# sourceMappingURL=index.js.map