d3 柱状图

142 阅读1分钟

img

image.png

html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Document</title>
		<script src="https://d3js.org/d3.v5.min.js"></script>
	</head>
	<style>
		
		.MyText {
			font-size: 18px;
			width: 60px;
			padding-left: 5px;
		}
		.MyText div {
			display: inline-block;
		}
		.MyText div:first-child {
			color: #fcfc00;
		}
		.MyText div:last-child {
			color: blue;
		}
		.MyText div:first-child::after {
			content: '个';
			font-size: 12px;
		}
		.MyText div:last-child::after {
			content: '%';
			font-size: 12px;
		}
	</style>
	<body>
		<div>
			
			<svg width="230" height="205"></svg>
		</div>
	</body>
</html>
<script>
	var epidemicData = [
		{ name: '五级', amount: 30, percent: '60' },
		{ name: '六级', amount: 20, percent: '30' },
		{ name: '七级', amount: 5, percent: '10' },
	]

	function maxHeight() {
		return epidemicData.reduce((total, curVal) => {
			return total > curVal.amount ? total : curVal.amount
		}, 0)
	}
	const rectWidth = 20 //定义矩形的宽度
	const yLength = 180 //柱状图y轴的长度
	//定义矩形的高度
	const rectHeight = d3
		.scaleLinear()
		.domain([0, maxHeight() + 10])
		.range([0, yLength])
	const interval = 55 //定义矩形间的间隔
	//柱状图x轴的长度
	const xLength = (rectWidth + interval) * epidemicData.length
	const baseLine = 190 //定义一个基线的位置,调整柱状图的位置

	let svg = d3.select('svg')
	//g——分组,可以简单的将他视为一个容器的作用
	let g = svg.append('g')
	let xScale = addX()
	let yScale = addY()
	let rect = g
		.attr('transform', 'translate(' + 30 + ', ' + 0 + ')')
		.selectAll('rect')
		.data(epidemicData)
		.enter()
		.append('rect')
		.attr('x', (d, i) => i * (rectWidth + interval))
		.attr('y', d => baseLine - rectHeight(d.amount))
		.attr('width', rectWidth)
		.attr('height', d => rectHeight(d.amount))
		.attr('stroke', d => {
			return '#1A6A9030'
		})
		.attr('fill', d => {
			//50F0FB  07AAFC
			return getLinearColor()
		})
	svg
		.selectAll('.MyText')
		.data(epidemicData)
		.enter()
		.append('foreignObject')
		.attr('class', 'MyText')
		.attr('x', function (d, i) {
			return xScale(d.name) + 30 + rectWidth
			// return i * rectWidth
		})
		.attr('y', function (d) {
			return yScale(d.amount)
		})
		.html(function (d) {
			return `<div>${d.amount}</div><div>${d.percent}</div>`
		})

	function getLinearColor() {
		var defs = svg.append('defs')

		var linearGradient = defs
			.append('linearGradient')
			.attr('id', 'linearColor')
			.attr('x1', '0%')
			.attr('y1', '0%')
			.attr('x2', '0%')
			.attr('y2', '100%')

		var stop1 = linearGradient.append('stop').attr('offset', '0%').style('stop-color', '#50F0FB')

		var stop2 = linearGradient.append('stop').attr('offset', '100%').style('stop-color', '#07AAFC')
		return 'url(#' + linearGradient.attr('id') + ')'
	}
	function _address() {
		return epidemicData.reduce((total, curVal) => {
			total.push(curVal.name)
			return total
		}, [])
	}

	function addX() {
		const xTick = epidemicData.length //x轴的刻度数目
		//为坐标轴定义一个序数比例尺
		let xScale = d3.scaleBand().domain(_address()).range([0, xLength])
		//定义一个朝下的坐标轴
		let xAxis = d3.axisBottom(xScale).ticks(xTick).tickPadding(10) //设置刻度和刻度文本之间的间距
		let gx = g
			.append('g')
			.call(xAxis)
			.attr('transform', 'translate(' + -30 + ', ' + 180 + ')')
		//更改x轴的文本的样式
		gx.selectAll('text').style('color', '#bebebe')

		//将x轴的刻度隐藏起来
		gx.selectAll('line').attr('stroke', '')
		gx.selectAll('path').attr('stroke', '')
		return xScale
	}

	function addY() {
		const yTick = 5 //y轴刻度数目
		let gy = g.append('g')
		let yScale = d3
			.scaleLinear()
			.domain([0, maxHeight() + 10])
			.range([yLength, 0])

		const rectHeight = d3
			.scaleLinear()
			.domain([0, maxHeight() + 10])
			.range([0, yLength])

		let yAxis = d3.axisLeft(yScale).ticks(yTick)

		gy.call(yAxis).attr('transform', 'translate(' + -10 + ', ' + (baseLine - yLength) + ')')
		//更改y轴的刻度的样式
		gy.selectAll('line').attr('stroke', '#0D194B20').attr('x2', xLength).attr('stroke-width', 0.5)
		gy.selectAll('path').attr('stroke', '')
		gy.selectAll('text').style('color', '#01B2E2')
		return yScale
	}
</script>