react-funnel-chart
Version:
react component about funnel chart
227 lines (200 loc) • 7.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _colorConversionRgb = require('color-conversion-rgb');
var _config = require('./config');
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
* props: {
list: [
{ name: 'Q1', value: 500, backgroundColor: '', ... },
{ name: 'Q2', value: 400, backgroundColor: '' },
{ name: 'Q3', value: 300, backgroundColor: '' },
{ name: 'Q4', value: 200, backgroundColor: '' },
],
isGradient: false,
labelStyle: '#333',
dataStyle: '#000',
strokeStyle: '#000',
tooltipStyle: {},
minPercent: 0.2,
* }
*/
var Funnel = function Funnel(props) {
_classCallCheck(this, Funnel);
_initialiseProps.call(this);
this.setValue(props);
};
var _initialiseProps = function _initialiseProps() {
var _this = this;
this.setValue = function () {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_this.labelStyle = props.labelStyle || _this.labelStyle || '#333';
_this.dataStyle = props.dataStyle || _this.dataStyle || '#000';
_this.strokeStyle = props.strokeStyle || _this.strokeStyle || '#000';
if (_this.isGradient === undefined) {
_this.isGradient = props.isGradient === undefined ? false : props.isGradient;
} else {
_this.isGradient = props.isGradient === undefined ? _this.isGradient : props.isGradient;
}
_this.ratio = props.ratio || _this.ratio || 1;
_this.list = props.list || _this.list || [];
_this.gap = props.gap || _this.gap || 2;
_this.width = props.width || _this.width || 250;
_this.height = props.height || _this.height || 250;
_this.fontSize = props.fontSize || _this.fontSize || 12;
_this.minPercent = props.minPercent || _this.minPercent || 0.2;
// 事件
_this.eventPosition = props.eventPosition;
_this.event = props.event;
// generate
_this.offset = (0, _config.getOffsetPixel)(_this.width, _this.height);
_this.hasText = _this.width > 600;
var object = (0, _config.generateListObject)({ list: _this.list, offset: _this.offset, gap: _this.gap, minPercent: _this.minPercent });
_this.coordList = object.coordList;
_this.leftTextList = object.leftTextList;
_this.leftLineList = object.leftLineList;
_this.rightTextList = object.rightTextList;
_this.rightLineList = object.rightLineList;
_this.centerTextList = object.centerTextList;
_this.fillStyleList = object.fillStyleList;
};
this.update = function (props, ctx) {
_this.setValue(props);
_this.currentArea = (0, _config.inWitchArea)({
coordList: _this.coordList,
eventPosition: _this.eventPosition,
offset: _this.offset,
ctx: ctx
});
_this.draw(ctx);
var item = _this.list[_this.currentArea];
if (item) {
var nextItem = _this.list[+_this.currentArea + 1] || {};
var rateText = _.get(_this.leftTextList[_this.currentArea] || [], ['0'], '转化率 0%');
return Object.assign({ rateText: rateText, nextItem: nextItem }, item);
}
return null;
};
this.getTextWidth = function (ctx, fillX, direction) {
return function (text) {
var _ctx$measureText = ctx.measureText(text),
width = _ctx$measureText.width;
if (direction === 'start') {
return width + fillX > _this.width;
}
return fillX - width < 0;
};
};
this.computedDrawText = function (ctx, param, direction) {
// 文字的宽度是否超出canvas
var fillText = param[0];
var fillX = param[1];
var fillY = param[2];
var curryGetTextWidth = _this.getTextWidth(ctx, fillX, direction);
var textList = [];
if (direction === 'end') {
var isExceed = curryGetTextWidth(fillText);
if (isExceed) {
textList = fillText.split(' ');
if (_.size(textList) < 1) {
textList = (0, _config.getTextList)(fillText, curryGetTextWidth);
}
} else {
textList.push(fillText);
}
} else {
textList = (0, _config.getTextList)(fillText, curryGetTextWidth);
}
var size = _.size(textList);
if (size > 1) {
fillY -= 10 * size;
}
textList.forEach(function (value, index) {
ctx.fillText(value, fillX, fillY + index * 25);
});
};
this.drawText = function (ctx) {
var realFontSize = _this.fontSize * _this.ratio;
var lineWidth = 2;
ctx.font = realFontSize + 'px Helvetica Neue For Number';
ctx.fillStyle = _this.labelStyle;
ctx.strokeStyle = _this.strokeStyle;
ctx.lineWidth = lineWidth;
if (_this.hasText) {
ctx.textAlign = 'start';
var rightLen = _.size(_this.rightTextList);
_this.rightTextList.forEach(function (param, index) {
var initY = param[2] - 10;
// 额外计算两图表之间的缝隙
var y = rightLen === 1 ? initY + lineWidth : index === rightLen - 1 ? initY - lineWidth : initY + lineWidth;
var coordX = _this.rightLineList[index];
ctx.beginPath();
ctx.moveTo(coordX.x1, y);
ctx.lineTo(coordX.x2, y);
ctx.stroke();
ctx.closePath();
_this.computedDrawText(ctx, param, ctx.textAlign);
});
ctx.textAlign = 'end';
_this.leftTextList.forEach(function (param, index) {
var initY = param[2] - 10;
var y = initY + lineWidth / 2;
var coordX = _this.leftLineList[index];
ctx.beginPath();
ctx.moveTo(coordX.x1, y);
ctx.lineTo(coordX.x2, y);
ctx.stroke();
ctx.closePath();
_this.computedDrawText(ctx, param, ctx.textAlign);
});
}
ctx.textAlign = 'center';
_this.centerTextList.forEach(function (param, index) {
if (index === _this.currentArea) {
ctx.fillStyle = '#fff';
} else {
ctx.fillStyle = _this.dataStyle;
}
ctx.fillText.apply(ctx, _toConsumableArray(param));
});
};
this.drawFunnel = function (ctx) {
ctx.translate(0, 0);
ctx.clearRect(0, 0, _this.width, _this.height);
_this.coordList.forEach(function (item, index) {
ctx.beginPath();
var start = void 0;
var end = void 0;
item.forEach(function (param, ind) {
if (ind === 0) {
ctx.moveTo.apply(ctx, _toConsumableArray(param));
start = param[1];
} else {
ctx.lineTo.apply(ctx, _toConsumableArray(param));
end = param[1];
}
});
var color = _this.fillStyleList[index];
if (index === _this.currentArea) {
ctx.fillStyle = (0, _colorConversionRgb.getHoverRgbColor)(color);
} else if (_this.isGradient) {
var gradient = ctx.createLinearGradient(0, start, 0, end);
gradient.addColorStop('0', (0, _colorConversionRgb.getHoverRgbColor)(color, 1));
gradient.addColorStop('1', (0, _colorConversionRgb.getHoverRgbColor)(color, 0.2));
ctx.fillStyle = gradient;
} else {
ctx.fillStyle = color;
}
ctx.closePath();
ctx.fill();
});
};
this.draw = function (ctx) {
_this.drawFunnel(ctx);
_this.drawText(ctx);
};
};
exports.default = Funnel;