- 有刻度,且可以根据数据变化
- 柱状图可以根据数据变化
let data = [
{ name:"吃饭", value: 300, },
{ name:"购物", value: 100, },
{ name:"交通", value: 500, },
{ name:"罚款", value: 200, },
{ name:"投资", value: 700, }
];
let config = {
warpW: 500, // svg 画布宽
warpH: 400, // svg 画布高
warpBg: "#faf0b1", // svg 画布背景颜色
wrapPadding: 30, // svg 画布的内边距
barW: 30, // 柱状图宽
};
注意:dom 元素一定要设定宽高,和 echarts 一样
function initD3(ele) {
let _svgEle = d3.select(ele).append("svg");
_svgEle
.attr("width", "100%")
.attr("height", "100%")
.attr("style", `background: ${config.warpBg};`);
return _svgEle;
}
let svgEle = initD3(".svg-box");
- 用来确定坐标轴的刻度
- 用来确定柱状图的相对高度以及 x 轴的相对位置
/**
* @fn 获得 x 轴 y 轴的刻度,以及y轴最大值
* @param data<array>: 需要渲染的数组
* @param option<object>: 渲染参数
* @return <array>: 返回 x 轴比例,y轴比例,最大值
*/
function getScale(data, option) {
let nameArr = data.map(val => val.name);
let valueArr = data.map(val => val.value);
let maxValue = d3.max(valueArr);
let xScale = d3.scaleBand()
.domain(nameArr)
.rangeRound([0, (option.warpW - option.wrapPadding * 2)]);
// 渲染y轴,线性
let yScale = d3.scaleLinear()
.domain([0, maxValue])
.rangeRound([(option.warpH - option.wrapPadding * 2), 0]);
return [
xScale,
yScale,
maxValue,
];
}
let [xScale, yScale, maxValue] = getScale(data, option);
/**
* @fn 渲染 x 轴 y 轴
* @param data<array>: 需要渲染的数组
* @param svg<obj>: svg 画布对象
* @param option<object>: 渲染参数
* @param xScale<function>: x轴比例尺
* @param yScale<function>: y轴比例尺
*/
function renderAxis(data, svgEle, config, xScale, yScale) {
// 渲染x轴,离散型
let xAxis = d3.axisBottom().scale(xScale);
svgEle.selectAll("g").remove();
svgEle
.append("g")
.attr(
"transform",
`translate(
${config.wrapPadding},
${config.warpH - config.wrapPadding}
)`
)
.call(xAxis);
let yAxis = d3.axisLeft().scale(yScale);
svgEle
.append("g")
.attr(
"transform",
`translate(
${config.wrapPadding},
${config.wrapPadding}
)`
)
.call(yAxis);
}
renderAxis(data, svgEle, option, xScale, yScale)
- svgEle.selectAll("g").remove(): 但需要重新渲染时将所有坐标轴删除,然后在渲染
/**
* @fn 渲染柱状图
* @param svgEle<object>: svg 画布对象
* @param data<array>: 需要渲染的数据
* @param xScale<function>: x轴比例尺
* @param yScale<function>: y轴比例尺
* @param option<object>: 渲染参数
* @param maxValue<number>: 渲染数据最大值
*/
function renderBar(svgEle, data, xScale, yScale, option, maxValue) {
let type = "rect";
let updateBar = svgEle.selectAll(type).data(data);
updateBar
.attr("width", option.barW)
.attr("height", val => {
return yScale(maxValue - val.value);
})
.attr("fill", "red")
.attr("x", (val, i) => {
return xScale(val.name)
+ option.wrapPadding
+ (xScale.bandwidth() - option.barW) / 2;
}).attr("y", val => {
return option.warpH
- yScale(maxValue - val.value)
- option.wrapPadding;
});
// 数据大于元素节点,初次渲染
let enterBar = updateBar.enter();
// 处理数据大于元素时的情况
enterBar.append(type)
.attr("width", option.barW)
.attr("height", val => {
return yScale(maxValue - val.value);
})
.attr("fill", "red")
.attr("x", (val, i) => {
return xScale(val.name)
+ option.wrapPadding
+ (xScale.bandwidth() - option.barW) / 2;
}).attr("y", val => {
return option.warpH
- yScale(maxValue - val.value)
- option.wrapPadding;
});
// 元素节点大于数据
let exitBar = updateBar.exit();
exitBar.remove();
}
renderBar(svgEle, data, xScale, yScale, option, maxValue);
/**
* @fn 渲染文字说明
* @param svgEle<object>: svg 画布对象
* @param data<array>: 需要渲染的数据
* @param xScale<function>: x轴比例尺
* @param yScale<function>: y轴比例尺
* @param option<object>: 渲染参数
* @param maxValue<number>: 渲染数据最大值
*/
function renderTxt(svgEle, data, xScale, yScale, option, maxValue) {
// 渲染节点说明
let updateTxt = svgEle.selectAll(".name").data(data);
updateTxt
.attr("x", (val, i) => {
return xScale(val.name)
+ option.wrapPadding
+ (xScale.bandwidth() - option.barW) / 2
+ option.barW / 2;
})
.attr("y", val => {
return option.warpH
- yScale(maxValue - val.value)
- option.wrapPadding;
})
.text(data => {
return data.value;
})
.attr("text-anchor", "middle")
.attr("fill", "#080");
let enterTxt = updateTxt.enter();
enterTxt.append("text")
.attr("class", "name")
.attr("x", (val, i) => {
return xScale(val.name)
+ option.wrapPadding
+ (xScale.bandwidth() - option.barW) / 2
+ option.barW / 2;
})
.attr("y", val => {
return option.warpH
- yScale(maxValue - val.value)
- option.wrapPadding;
})
.text(data => {
return data.value;
})
.attr("text-anchor", "middle").attr("fill", "#080");
// 删除多余元素
let exitTxt = updateTxt.exit();
exitTxt.remove();
}
renderTxt(svgEle, data, xScale, yScale, option, maxValue);