datavizstocklib
Version:
测试一下呗
1,161 lines (1,070 loc) • 42.6 kB
JavaScript
import * as d3 from "d3";
import { selectAll } from "d3";
let config = {
/**
* 控件名
*/
name: "BarChartRace",
/**
* svg 对象
*/
svg: {},
/**
* 展示类型 Dynamic Fixed Custom
*/
scaleType: "Dynamic",
/**
* 数据
*/
data: [],
/**
* 内部使用
*/
jsonData: {},
/**
* 内部使用 当前展示的数据
*/
currentData: [],
/**
* 表头名集合
*/
columnName: [],
/**
* 表头名集合 内部使用
*/
columnInnerName: [],
/**
* 表头名索引
*/
columnNameIndex: 2,
/**
* 图表默认高度
*/
clientHeight: 500,
/**
* 图表默认宽度
*/
clientWidth: 0,
/**
* 升序或降序 asc desc
*/
sort: "desc",
/**
* Y轴比例尺
*/
yScale: {},
/**
* X轴比例尺
*/
xScale: {},
/**
* 边距设置 上,右,下,左
*/
margin: [60, 100, 60, 100],
/**
* colors
*/
colors: ["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"],
/**
* 内部使用
*/
colorMap: null,
/**
* 按数据中第二列 数据分类来进行数据划分 true false
*/
colorsCateory: true,
/**
* 分类时是否展示图例
*/
showLegend: true,
/**
* 最大文字的字号
*/
fontsize: 50, //字号
/**
* 字体类型
*/
fontFamily: 'regular', //字体类型
/**
* 字体
*/
fontfamilyBase: "SourceHanSansK-Regular-plotly,Helvetica Neue,PingFang SC,Microsoft YaHei,Helvetica,Hiragino Sans GB,Arial,sans-serif",
/**
* 文字颜色
*/
rectTextColor: "#A3A3A3",
/**
* 条数
*/
barNumber: 5,
/**
* 柱高度自适应
*/
rectHeightFixed: true,
/**
* 条高度 只有rectHeightFixed 为false 该值生效
*/
rectHeight: 100,
/**
* 柱高度和 柱间距的比例
*/
rectRate: 0.6,
/**
* 内部使用
*/
rectSpace: 0,
/**
* X轴坐标位置 bottom top
*/
xAxisPos: "top",
/**
* 动画时长
*/
durationTime: 1000,
/**
* 最大值
*/
maxValue: 0,
/**
* 延时播放
*/
delay: 2000,
/**
* 展示右下角年份
*/
showYear: true,
/**
* 内部使用
*/
isRun: false,
/**
* 左侧文字大小
*/
YfontSize: 16,
/**
* 图例文字大小
*/
legendFontSize: 12,
//圆角
rx: 2,
showThousands: true,
pointFormat: 'auto',
useImages: true,
ticksNum: 5,
animateType: 'easeLinear',
d3Ease: '',
terminal: '',
el: '_dataviz'
}
String.prototype.replaceAll = function (s1, s2) {
return this.replace(new RegExp(s1, "gm"), s2);
}
export class BarChartRace {
/**
* 构造器
*/
constructor() {
let newconfig = JSON.parse(JSON.stringify(config));
Object.assign(this, newconfig);
}
/**
* 更新图表
* @param {JSON} obj
*/
update(obj) {
// console.log("执行UPDATE");
this.clearAllTimeout();
// 复制新配置
Object.assign(this, obj)
let that = this;
this.getEase();
// 更新数据格式
this.arrayToJson();
that.bar.transition().duration(that.durationTime)
.attr('transform', `translate(${this.margin[3]}, ${this.margin[0]})`).ease(this.d3Ease);
if (!that.isRun) { //非运行状态 渲染最后一帧
let year = that.columnInnerName[that.columnName.length - 1];
that.columnNameIndex = that.columnName.length - 1;
that.updateChart(year);
}
if (!that.showYear) {
that.svg.select(".year").attr("font-size", "0")
.attr("font-size", that.fontsize)
.attr("fill", that.rectTextColor)
} else {
that.svg.select(".year").attr("font-size", that.fontsize)
.attr("font-size", that.fontsize)
.attr("fill", that.rectTextColor)
}
if (that.templateType == 'template_virus') {
that.svg.select(".total")
.text(that.format(that.totalData[that.columnNameIndex].toFixed(0))).attr("font-size", function (d) {
if (that.showTotal) {
return 36
} else {
return 0
}
})
that.svg.select('.dataTitle')
.text(that.dataTitle).attr("font-size", function (d) {
if (that.showDataTitle) {
return 40
} else {
return 0
}
})
}
// else {
// // 右下角数据显示
// let tmpHeight = that.svg.attr("height") - that.margin[2];
// if ("asc" == that.sort) {
// tmpHeight = that.margin[0] + 50;
// if (that.isTemplate) tmpHeight = tmpHeight + 50
// }
// console.log(that.sort, tmpHeight);
// that.svg.select(".year").transition()
// .duration(that.durationTime)
// .attr("y", function () {
// if (that.templateType == 'template_virus') return tmpHeight - 820
// return tmpHeight
// })
// .attr("x", function () {
// if (that.templateType == 'template_virus') return 300
// if (that.isTemplate) return 670
// return that.clientWidth - that.margin[1]
// })
// .attr("font-size", that.fontsize)
// .attr("fill", that.rectTextColor);
// }
}
clearAllTimeout() {
//for (var i = 0; i < 9999; i++) {
// clearTimeout(i);
// console.log(i);
//}
}
/**
* 重新播放
*/
replay() {
let that = this;
this.clearAllTimeout();
if (that.isRun) {
clearTimeout(that.timeout);
if (that.timeout) that.timeout.stop();
}
that.mvar.selectAll('g').remove();
let year = that.columnInnerName[2];
that.columnNameIndex = 2;
that.currentData = [];
that.updateChart(year, true);
}
/** 播放 */
play() {
let that = this;
clearTimeout(that.timeout);
this.clearAllTimeout();
if (that.timeout) that.timeout.stop();
let year = that.columnInnerName[that.columnNameIndex];
that.currentData = [];
that.updateChart(year, false);
}
/** 暂停 */
pause() {
let that = this;
clearTimeout(that.timeout);
if (that.timeout) that.timeout.stop();
that.isRun = false;
}
/**
* 渲染指定页面
* @param {*} index
*/
renderIndex(index) {
let that = this;
if (that.isRun) { //播放中不支持直接跳转
return;
}
that.columnNameIndex = index;
let year = that.columnInnerName[that.columnNameIndex];
that.updateChart(year, true, true);
}
/**
* 初始化
* @param {Object} obj
*/
init(obj) {
let that = this;
Object.assign(this, obj);
this.getEase();
this.clearAllTimeout();
that.svg = d3.select("#" + this.el).append("svg");
that.svg.append("g").attr("class", "bcrlegend");
if (that.clientWidth == 0) {
that.clientWidth = document.getElementById(this.el).clientWidth;
}
that.arrayToJson();
that.svg.attr("width", that.clientWidth).attr("height", that.clientHeight);
let width = that.clientWidth - this.margin[1] - this.margin[3];
that.x = d3.scaleLinear().range([0, width])
that.xScale = that.x.domain([0, that.max()])
if (that.rectHeightFixed) {
that.rectHeight = (that.clientHeight - that.margin[0] - that.margin[2]) / (that.barNumber + (that.barNumber - 1) * that.rectRate);
}
that.rectSpace = that.rectHeight * that.rectRate;
if (that.isTemplate && that.templateType != 'template_virus') that.ticksNum = 0
that.gridscale = d3
.axisTop()
.scale(that.xScale)
.ticks(that.ticksNum)
.tickPadding(12)
.tickSize(-(that.clientHeight - that.margin[2] - that.margin[0] + 30), 0, 0)
.tickFormat(d => {
if (d < 0) {
return "";
}
if (that.isTemplate && d != 0 && that.templateType != 'template_virus') return "";
return that.format(d);
})
//添加竖线
that.svg
.append("g")
.attr("class", "grid")
.style("color", function () {
if (that.isTemplate && that.templateType != 'template_virus') return '#ffffff'
return "#A3A3A3"
})
.attr("opacity", that.showAxisX ? 1 : 0.0001)
.style("font-size", that.XfontSize)
.call(that.gridscale);
that.bar = this.svg.append("g");
that.bar.attr('transform', `translate(${this.margin[3]}, ${this.margin[0]})`)
that.mvar = that.bar.append("g");
let tmpHeight = that.svg.attr("height") - that.margin[2];
if ("asc" == that.sort) {
tmpHeight = that.margin[0] + 50;
}
that.svg.append("text").attr("class", "year")
.attr("y", function () {
if (that.templateType == 'template_virus') return tmpHeight - 820
return tmpHeight
})
.attr("x", function () {
if (that.templateType == 'template_virus') return 280
if (that.isTemplate) return 670
return that.terminal == 'mobile' ? that.clientWidth - 50 : that.clientWidth - 100
})
.text(that.columnName[2])
.attr("text-anchor", that.templateType == 'template_virus' ? "start" : "end")
.attr("font-size", that.fontsize)
.attr("fill", that.rectTextColor)
.attr("style", "font-family:" + that.fontFamily)
if (that.templateType == 'template_virus') {
that.svg.append("text")
.attr("y", function () {
return 280
})
.attr("x", function () {
if (that.showTotal) {
return 175
} else {
return 270
}
})
.attr('class', 'dataTitle')
.text(that.dataTitle)
.attr("text-anchor", "center")
.attr("font-size", 36)
.attr("fill", that.rectTextColor);
that.svg.append("rect")
.attr("class", 'line1')
.attr("y", function () {
return 267
})
.attr("x", function () {
return 110
})
.attr('width', 30)
.attr('height', function () {
if (that.showDataTitle || that.showTotal) {
return 2
} else {
return 0
}
})
.attr("fill", '#FF5A5A');
that.svg.append("rect")
.attr("class", 'line2')
.attr("y", function () {
return 267
})
.attr("x", function () {
return 580
})
.attr('width', 30)
.attr('height', function () {
if (that.showDataTitle || that.showTotal) {
return 2
} else {
return 0
}
})
.attr("fill", '#FF5A5A');
that.svg.append("text").text("0")
.attr("style", "font-family:" + that.fontFamily)
.attr("class", "total")
.attr('fill', function () {
return "#FF5A5A"
})
.attr("text-anchor", "start")
.attr("y", function () {
return 278
})
.attr("x", function () {
if (that.showDataTitle) {
return 385
} else {
return 302
}
})
.attr("font-size", 40)
}
if (!that.showYear) {
that.svg.select(".year").attr("font-size", "0")
}
//定义渐变色
that.colorGradient = that.svg.append("defs").append("linearGradient").attr('id', 'colorGradient').attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%")
//定义文字背景渐变色
if (that.showBgGradient) {
let bg = that.svg.append("defs").append("linearGradient").attr('id', 'bgGradient').attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%")
bg.append("stop")
.attr("offset", "0%")
.attr("stop-color", that.bgGradient[0])
bg.append("stop")
.attr("offset", "100%")
.attr("stop-color", that.bgGradient[1])
}
let rectFilter = that.svg.append("defs").append("filter").attr('id', 'f1').attr('x', '0').attr('y', '0').attr('width', '200%').attr('height', '200%')
rectFilter.append('feOffset').attr('result', 'offOut').attr('in', 'SourceAlpha').attr('dx', '2').attr('dy', '2')
rectFilter.append('feGaussianBlur').attr('result', 'blurOut').attr('in', 'offOut').attr('stdDeviation', '10')
rectFilter.append('feBlend').attr('in', 'SourceGraphic').attr('in2', 'blurOut').attr('mode', 'normal')
let rectFilter2 = that.svg.append("defs").append("filter").attr('id', 'empty').attr('x', '0').attr('y', '0').attr('width', '200%').attr('height', '200%')
rectFilter2.append('feOffset').attr('result', 'offOut').attr('in', 'SourceAlpha').attr('dx', '0').attr('dy', '0')
rectFilter2.append('feGaussianBlur').attr('result', 'blurOut').attr('in', 'offOut').attr('stdDeviation', '0')
rectFilter2.append('feBlend').attr('in', 'SourceGraphic').attr('in2', 'blurOut').attr('mode', 'normal')
that.updateChart(that.columnInnerName[2], true, false);
that.updateXAxis();
}
getEase() {
this.d3Ease = d3;
this.animateType.split(".").forEach(item => {
if (item.indexOf("(") > -1) {
let arr = item.split("(")
this.d3Ease = this.d3Ease[arr[0]](arr[1].replace(")", ""))
} else {
this.d3Ease = this.d3Ease[item]
}
})
}
/**
* 页面渲染
* @param {*} year
*/
updateChart(year, initflag, renderIndexFlag) {
let that = this;
if (!initflag) {
return;
}
//console.log("updateChart:" + year + " initflag:" + initflag + " renderIndexFlag:" + renderIndexFlag);
let durationTime = that.durationTime
if (this.columnNameIndex < 3) durationTime = 0
if (that.rectHeightFixed) {
that.rectHeight = (that.clientHeight - that.margin[0] - that.margin[2]) / (that.barNumber + (that.barNumber - 1) * that.rectRate);
}
that.rectSpace = that.rectHeight * that.rectRate;
if (that.clientWidth == 0) {
that.clientWidth = document.getElementById(this.el).clientWidth;
}
that.svg.attr("width", that.clientWidth).attr("height", that.clientHeight);
d3.select('#colorGradient').html('')
that.colorGradient.append('stop').attr('offset', '0%').attr('stop-color', that.colors[0])
that.colorGradient.append('stop').attr('offset', '100%').attr('stop-color', that.colors[1])
//数据排序
that.jsonData = that.jsonData.sort(function (a, b) {
if ("desc" == that.sort) {
return d3.descending(+a[year], +b[year]);
} else {
return d3.ascending(+a[year], +b[year])
}
});
that.currentData = [];
//取前几多条数据
let index = 0;
for (var i = 0; i < that.jsonData.length; i++) {
let tmpIdx = Number(that.jsonData[i][year]);
if (that.showZero) {
if (!isNaN(tmpIdx) && tmpIdx >= 0) {
that.currentData[index] = that.jsonData[i];
index++;
if (index == that.barNumber) { break; }
}
} else {
if (!isNaN(tmpIdx) && tmpIdx > 0) {
that.currentData[index] = that.jsonData[i];
index++;
if (index == that.barNumber) { break; }
}
}
}
//数据二次排序
that.currentData.sort(function (a, b) {
if ("desc" == that.sort) {
return d3.descending(+a[year], +b[year]);
} else {
return d3.ascending(+a[year], +b[year]);
}
});
that.gridscale = d3
.axisTop()
.scale(that.xScale)
.ticks(that.ticksNum)
.tickPadding(12)
.tickSize(-(that.clientHeight - that.margin[2] - that.margin[0] + 30), 0, 0)
.tickFormat(d => {
if (d < 0) {
return "";
}
if (that.isTemplate && that.templateType != 'template_virus') return "";
return that.format(d);
})
let width = that.clientWidth - this.margin[1] - this.margin[3];
that.x = d3.scaleLinear().range([0, width])
that.xScale = that.x.domain([0, that.max(year)])
that.gridscale.scale(that.xScale)
//更新竖线位置
that.svg.select(".grid").transition()
.duration(durationTime)
.ease(that.d3Ease)
.attr("opacity", that.showAxisX ? 1 : 0.0001)
.call(that.gridscale);
d3.select(".xAxis").remove();
d3.select(".grid").select(".domain").remove();
// console.log(that.currentData)
//数据绑定对象
var binding = that.mvar.selectAll('g').
data(that.currentData, function (d) { return d[that.columnInnerName[0]] });
//退出排名的数据 离场动画
binding.exit().transition()
.duration(durationTime)
.attr("transform", function (d, i) {
return "translate(0," + (that.barNumber) * (that.rectHeight + that.rectSpace) + ")";
})
.style("opacity", 0.0001).remove();
//补充新的元素
that.enterG = binding.enter().append("g");
// 新元素初始化
that.enterG.attr("transform", function (d, i) {
return "translate(0," + (that.barNumber - 1) * (that.rectHeight + that.rectSpace) + ")";
}).transition()
.duration(durationTime)
.attr("transform", function (d, i) {
return "translate(0," + i * (that.rectHeight + that.rectSpace) + ")";
}).attr("width", function (d) {
return that.xScale(d[year]);
}).ease(that.d3Ease);
//添加rect节点
that.enterG.append("rect")
.attr("class", "rect")
.attr("width", function (d) {
return that.xScale(d[year]);
})
.attr("rx", that.rx)
.attr("y", function (d, i) {
return that.rectHeight / 2;
})
.attr('filter', function () {
if (that.templateType == 'template3') return "url(#f1)"
return 'url(#empty)'
})
.attr("height", that.rectHeight)
.attr("fill", function (d, i) {
let index = that.colorsCateory ? 1 : 0;
let name = that.columnInnerName[index];
if (index == 1) {
name = "category_dsd";
}
if (that.isTemplate && that.gradient) return 'url(#colorGradient)'
return that.colorMap.get(d[name]);
});
//添加text节点
that.enterG.append("text").text("0")
.attr("class", "vtips")
.attr('fill', function () {
// if (that.isTemplate) return that.colors[1]
return that.fontColor
})
.attr("x", that.vtipsOffsiteX)
.attr("y", function (d, i) {
return (that.rectHeight + (5 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber))
//return that.rectHeight + i * (that.rectHeight + that.rectSpace);
})
.attr("style", "font-family:" + that.fontFamily)
.attr("text-anchor", "start")
.attr("transform", function (d, i) {
if (that.useImages) return "translate(" + (that.xScale(d[year]) + that.vtipsOffsite) + ")";
return "translate(" + (that.xScale(d[year]) + 10) + ")";
images
})
.attr("font-size", that.YfontSize - 2).transition()
.duration(durationTime)
.tween("text", function (d) {
var self = this;
let num = self.textContent;
let numLen = d[year].toString().split('.')[1] === undefined ? 0 : d[year].toString().split('.')[1].length
var i = d3.interpolate(num, d[year]);
return function (t) {
let num = parseFloat(i(t)).toFixed(numLen)
self.textContent = that.format(num);
};
})
.ease(that.d3Ease);
if (that.useImages) {
that.enterG.append('image')
.attr("class", "image")
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("width", function (d, i) {
if (d['image']) {
let w = that.rectHeight * 3 / 2 - 5
if (w > 50) w = 50
if (that.templateType == 'template3') return that.rectHeight - 5
return w
} else {
return 0
}
})
.attr("height", function (d, i) {
if (that.templateType == 'template3') return that.rectHeight - 5
return that.rectHeight
})
.attr("x", 0)
.attr("y", function (d, i) {
return (that.rectHeight + (8 * that.YfontSize / that.rectHeight + 1.5 * that.rectHeight / that.barNumber)) - that.rectHeight + that.imageOffsite
//return that.rectHeight + i * (that.rectHeight + that.rectSpace);
})
.attr("transform", function (d, i) {
return "translate(" + (that.xScale(d[year]) + 10) + "," + 10 + ")";
})
.attr("xlink:href", function (d, i) {
let img = d['image']
if (img) return img
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAABVCAYAAADNCyPqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAADGSURBVHhe7dAxAQAwDMCg+ffctSr4cmCA92c2TsFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjBWMFYwVjB1OwBeFHfxoh6bUcAAAAASUVORK5CYII="
})
.transition()
.duration(durationTime)
.ease(that.d3Ease);
binding.select(".image")
.transition().duration(durationTime)
.attr("width", function (d, i) {
if (d['image']) {
let w = that.rectHeight * 3 / 2 - 5
if (w > 50) w = 50
if (that.templateType == 'template3') return that.rectHeight - 5
return w
} else {
return 0
}
})
.attr("height", function (d, i) {
if (that.templateType == 'template3') return that.rectHeight - 5
return that.rectHeight
})
.attr("x", 0)
.attr("y", function (d, i) {
return (that.rectHeight + (8 * that.YfontSize / that.rectHeight + 1.5 * that.rectHeight / that.barNumber)) - that.rectHeight + that.imageOffsite
//return that.rectHeight + i * (that.rectHeight + that.rectSpace);
}).attr("text-anchor", "start")
.attr("transform", function (d, i) {
return "translate(" + (that.xScale(d[year]) + 10) + "," + 10 + ")";
}).ease(that.d3Ease);
}
//名字添加背景渐变
if (that.showBgGradient) {
that.enterG.append("rect")
.attr("class", "bgRect")
.attr("fill", "url(#bgGradient)")
.attr("height", that.YfontSize + 5)
.attr("width", this.margin[3] - 4)
.attr("x", -this.margin[3] + 2)
.attr("y", function (d, i) {
return (that.rectHeight + (8 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber)) - that.YfontSize;
})
.attr("fill-opacity", "0.6")
binding.select(".bgRect").attr("height", that.YfontSize + 5)
.attr("width", this.margin[3] - 4)
.attr("x", -this.margin[3] + 2)
.attr("y", function (d, i) {
return (that.rectHeight + (8 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber)) - that.YfontSize;
})
.attr("fill-opacity", "0.6")
}
// 添加最左侧文本
that.enterG.append("text").attr("class", "lefttext").text(function (d) {
return d[that.columnInnerName[0]];
})
.attr("x", -5)
.attr("y", function (d, i) {
return (that.rectHeight + (5 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber));
}).attr("font-size", that.YfontSize)
.attr("text-anchor", "end")
.attr('fill', that.fontColor);
// 修改最左侧文字
binding.select(".lefttext").transition().duration(durationTime)
.attr("font-size", that.YfontSize)
.attr("y", function (d, i) {
return (that.rectHeight + (5 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber));
}).attr('fill', that.fontColor);
//进度条宽度变化动画
binding.select(".rect").transition()
.duration(durationTime).attr("width", function (d) {
return that.xScale(d[year]);
}).attr("height", that.rectHeight).attr("y", function (d, i) {
return that.rectHeight / 2;
}).attr("rx", that.rx).attr("fill", function (d, i) {
let index = that.colorsCateory ? 1 : 0;
let name = that.columnInnerName[index];
if (index == 1) {
name = "category_dsd";
}
if (that.isTemplate && that.gradient) return 'url(#colorGradient)'
return that.colorMap.get(d[name]);
}).ease(that.d3Ease);
//进度数值
binding.select(".vtips")
.attr("font-size", that.YfontSize - 2)
.attr('fill', function () {
// if (that.isTemplate) return that.colors[1]
return that.fontColor
}).transition().duration(durationTime)
.attr("x", that.vtipsOffsiteX)
.attr("y", function (d, i) {
return (that.rectHeight + (5 * that.YfontSize / that.rectHeight + that.rectHeight / that.barNumber))
//return that.rectHeight + i * (that.rectHeight + that.rectSpace);
}).attr("text-anchor", "start")
.tween("text", function (d) {
var self = this;
var i = d3.interpolate(self.textContent.replaceAll(",", ""), d[year]);
return function (t) {
//console.log(t)
let len = 0
if (d[year].toString().split('.')[1]) len = d[year].toString().split('.')[1].length
let num = parseFloat(i(t)).toFixed(len)
self.textContent = that.format(num);
};
}).attr("transform", function (d, i) {
if (that.useImages) return "translate(" + (that.xScale(d[year]) + that.vtipsOffsite) + ")";
return "translate(" + (that.xScale(d[year]) + 10) + ")";
}).ease(that.d3Ease);
let tmpHeight = that.svg.attr("height") - that.margin[2];
if ("asc" == that.sort) {
tmpHeight = that.margin[0] + 50;
}
that.svg.select(".year").text(that.columnName[that.columnNameIndex]).attr("y", function () {
if (that.templateType == 'template_virus') return tmpHeight - 820
return tmpHeight
}).attr("x", function () {
if (that.templateType == 'template_virus') return 280
if (that.isTemplate) return 670
return that.terminal == 'mobile' ? that.clientWidth - 50 : that.clientWidth - 100
}).attr('font-size', function () {
if (that.showYear) {
return that.fontsize
} else {
return 0
}
});
if (that.templateType == 'template_virus') {
that.svg.select(".total")
.text(that.format(that.totalData[that.columnNameIndex].toFixed(0))).attr("font-size", function (d) {
if (that.showTotal) {
return 36
} else {
return 0
}
})
.attr("x", function () {
if (that.showDataTitle) {
return 385
} else {
return 302
}
})
that.svg.select('.dataTitle')
.text(that.dataTitle).attr("font-size", function (d) {
if (that.showDataTitle) {
return 40
} else {
return 0
}
})
.attr("x", function () {
if (that.showTotal) {
return 175
} else {
return 270
}
})
that.svg.select(".line1")
.attr('height', function () {
if (that.showDataTitle || that.showTotal) {
return 2
} else {
return 0
}
})
that.svg.select(".line2")
.attr('height', function () {
if (that.showDataTitle || that.showTotal) {
return 2
} else {
return 0
}
})
}
//进度条位置变化动画
binding.transition()
.duration(durationTime)
.style("opacity", 1)
.attr("transform", function (d, i) {
return "translate(0," + i * (that.rectHeight + that.rectSpace) + ")";
}).ease(that.d3Ease);
that.updateXAxis();
if (renderIndexFlag) {
return;
}
// 打开下一帧
if (that.columnNameIndex < that.columnName.length - 1) {
if (initflag) {
that.timeout = d3.timeout(function () {
that.columnNameIndex++;
year = that.columnInnerName[that.columnNameIndex];
that.updateChart(year)
}, that.delay);
} else {
that.timeout = d3.timeout(function () {
that.columnNameIndex++;
year = that.columnInnerName[that.columnNameIndex];
that.updateChart(year)
}, that.durationTime);
}
} else {
that.isRun = false;
}
}
/**
* 更新X坐标位置
*/
updateXAxis() {
let that = this;
if (!that.showAxisX) {
that.svg.select(".grid").selectAll("text").attr('font-size', "0");
} else {
that.svg.select(".grid").selectAll("text").attr('font-size', that.XfontSize);
}
if ("bottom" == that.xAxisPos) {
that.svg.select(".grid").attr('transform', 'translate(' + that.margin[3] + ',' + that.margin[0] + ' )');
let t = that.clientHeight - that.margin[2] - that.margin[0] + 50;
that.svg.select(".grid").selectAll("text").attr('transform', 'translate(' + 0 + ',' + t + ')');
} else {
that.svg.select(".grid").selectAll("text").attr('transform', "");
that.svg.select(".grid").attr('transform', 'translate(' + that.margin[3] + ',' + that.margin[0] + ' )');
}
}
/**
* 千分位格式化
* @param {String} num
*/
format(num) {
// var reg = /\d{1,3}(?=(\d{3})+$)/g;
// return (num + '').replace(reg, '$&,');
if (this.pointFormat == 0) {
num = parseInt(num)
} else if (this.pointFormat == 1) {
num = parseFloat(num).toFixed(1)
} else if (this.pointFormat == 2) {
num = parseFloat(num).toFixed(2)
}
let result = '';
if (this.showThousands) {
num = (num || 0).toString();
let a = num.split('.')[0] || num
let b = num.split('.')[1] || ""
while (a.length > 3) {
result = ',' + a.slice(-3) + result;
a = a.slice(0, a.length - 3);
}
if (a) { result = a + result; }
if (b) { result = result + "." + b }
} else {
result = num
}
if (this.showPercent) result = result + '%'
return result
}
/**
* 计算最大值
* @param {*} year
*/
max(year) {
let that = this;
let max = 0;
if ("Dynamic" == that.scaleType) {
for (var i = 0; i < that.currentData.length; i++) {
let tmp = Number(that.currentData[i][year]);
if (!isNaN(tmp)) { max = max > tmp ? max : tmp; }
}
} else if ("Fixed" == that.scaleType || "Custom" == that.scaleType) {
max = that.maxValue;
}
return max;
}
arrayToJson() {
let that = this;
//第一行为列名
that.columnName = that.data[0];
for (let i = 0; i < that.columnName.length; i++) {
that.columnInnerName[i] = "cn_" + i; //内部名称
}
let data = [];
let max = 0;
for (var i = 1; i < that.data.length; i++) {
let obj = {};
for (var j = 0; j < that.columnName.length; j++) {
that.data[i][j] = that.data[i][j] + "";
if (j == 1) {
obj["category_dsd"] = that.data[i][j];
} else {
obj[that.columnInnerName[j]] = that.data[i][j];
}
let tmp = Number(that.data[i][j]);
if (!isNaN(tmp)) { max = max > tmp ? max : tmp; }
}
data.push(obj);
}
that.jsonData = data;
if ("Custom" != that.scaleType) {
that.maxValue = max;
}
this.updateColors();
if (that.useImages) this.updataImages();
}
/**
* 分配颜色
*/
updateColors() {
let that = this;
that.colorMap = new Map();
if (that.colorsCateory) {
//取分组
var m = new Map();
var s = new Set();
let j = 0;
for (var i = 0; i < that.jsonData.length; i++) {
let key = that.jsonData[i]['category_dsd'];
if (!s.has(key)) {
m.set(key, j);
s.add(key);
j++;
}
let index = m.get(key);
let c = that.colors[index % (that.colors.length)];
that.colorMap.set(key, c)
}
if (that.showLegend && !that.isTemplate) {
that.addLegend(m);
} else {
that.svg.select(".bcrlegend").selectAll("g").remove();
}
} else {
for (var i = 0; i < that.jsonData.length; i++) {
let c = that.colors[i % (that.colors.length)];
let key = that.jsonData[i][that.columnInnerName[0]];
that.colorMap.set(key, c);
}
that.svg.select(".bcrlegend").selectAll("g").remove();
}
}
updataImages() {
// let that = this;
// that.imageMap = new Map();
// var m = new Map();
// var s = new Set();
// let j = 0;
// that.useImages = false
// for (var i = 0; i < that.jsonData.length; i++) {
// let key = that.jsonData[i]['category_dsd'];
// if (!s.has(key)) {
// m.set(key, j);
// s.add(key);
// j++;
// }
// let index = m.get(key);
// let c = that.dynamicImages[index % (that.dynamicImages.length)];
// that.imageMap.set(key, c)
// if (c) that.useImages = true
// }
let that = this;
for (var i = 0; i < that.jsonData.length; i++) {
that.jsonData[i]["image"] = that.dynamicImages[i]
}
}
/**
* 显示图例
* @param {Object} m
*/
addLegend(m) {
let that = this;
//清空原图例下所有数据
that.svg.select(".bcrlegend").selectAll("g").remove();
let data = [];
m.forEach(function (item, key, mapObj) {
let color = that.colors[item % (that.colors.length)]
let tmp = { key: key, v: item, color: color };
data.push(tmp);
});
var binding = that.svg.select(".bcrlegend").selectAll("g").data(data, function (d) { return d.key; });
binding.exit().transition().duration(that.durationTime).remove();
that.svg.select(".bcrlegend").transition().duration(that.durationTime)
.attr('transform', 'translate(' + ((that.unitSize - 16) * 2 + 120) + ',' + (that.margin[0] - 45 + 1.5 * (that.titleFontSize - 36)) + ' )').ease(that.d3Ease);
let enterG = binding.enter().append("g");
let offset = 0
enterG.append("rect")
.attr("width", (that.legendFontSize - 2)).attr("height", (that.legendFontSize - 2))
.attr("rx", that.rx)
.attr('transform', function (d, i) {
let beforeOffset = offset
offset = parseInt(d.key.length * 5) + parseInt(beforeOffset) + 20 + that.legendFontSize * 4
return 'translate(' + beforeOffset + ',' + -(that.legendFontSize - 6) / 2 + ' )';
// return 'translate(' + i * 75 + ',' + 0 + ' )';
}).attr("fill", function (d, i) {
if (that.isTemplate && that.gradient) return 'url(#colorGradient)'
return d['color'];
});
let offsetText = 0
enterG.append("text").attr("font-size", that.legendFontSize)
.attr('fill', that.fontColor)
.attr('transform', function (d, i) {
let beforeOffset = offsetText || 25
offsetText = parseInt(d.key.length * 5) + parseInt(beforeOffset) + 20 + that.legendFontSize * 4
return 'translate(' + beforeOffset + ',' + 7 + ' )';
//return 'translate(' + (i * 75 + 12) + ',' + 10 + ' )';
}).text(function (d, i) {
return d.key;
})
// binding.selectAll("rect").transition()
// .duration(that.durationTime).attr("fill", function(d, i) {
// console.log(that.colorMap.get(d['key']) + " = " + d['key'] + " = " + i);
// return that.colorMap.get(d['key']);
// }).attr("rx", that.rx).attr("font-size", that.legendFontSize).ease(d3.easeLinear);
}
}
export default BarChartRace;