用d3绘制区间图,组合图

用d3绘制区间图
在这里插入图片描述
js、微信小程序创建区间图请看http://t.csdn.cn/Ddenp


前言

需求要求绘制血压区间图,在网上找了一圈,没有找到适合的,d3灵活性比较高,就用d3绘制了,用散点图和柱状图组合就是区间图了


一、安装d3

npm install d3 --save-dev

二、使用步骤

1.引入库

代码如下(示例):

import * as d3 from 'd3'

2.代码示例

<template>
  <div class="svg">
	  
  </div>
</template>

基础配置

var w = 600;
var h = 400;
const _colors = d3.scaleOrdinal(d3.schemeCategory10)
const config = {
    pointColor: _colors(0),
		  barColor: _colors(1),
    margins: {top: 80, left: 80, bottom: 50, right: 80},
    textColor: 'black',
    gridColor: 'gray',
    ShowGridX: [1, 2, 3, 4, 5, 6, 7 ,8, 9, 10],
    ShowGridY: [20, 40, 60, 80, 100, 120, 140 ,160, 180, 200],
    title: '散点图',
    pointSize: 5,
    hoverColor: 'white',
    animateDuration: 1000
}

尺度转换

// 点数据(这是一列四个点,两条数据)
const data = [{"x":"2021-12-20","y":119,"t":1},{"x":"2021-12-20","y":100,"t":1},{"x":"2021-12-20","y":74,"t":2},{"x":"2021-12-20","y":60,"t":2},{"x":"2021-12-21","y":122,"t":1},{"x":"2021-12-21","y":110,"t":1},{"x":"2021-12-21","y":82,"t":2},{"x":"2021-12-21","y":67,"t":2},{"x":"2021-12-22","y":120,"t":1},{"x":"2021-12-22","y":120,"t":1},{"x":"2021-12-22","y":78,"t":2},{"x":"2021-12-22","y":78,"t":2},{"x":"2021-12-23","y":120,"t":1},{"x":"2021-12-23","y":100,"t":1},{"x":"2021-12-23","y":86,"t":2},{"x":"2021-12-23","y":65,"t":2},{"x":"2021-12-24","y":124,"t":1},{"x":"2021-12-24","y":121,"t":1},{"x":"2021-12-24","y":77,"t":2},{"x":"2021-12-24","y":75,"t":2},{"x":"2021-12-25","y":109,"t":1},{"x":"2021-12-25","y":103,"t":1},{"x":"2021-12-25","y":91,"t":2},{"x":"2021-12-25","y":80,"t":2}]
const g_width= w - config.margins.left - config.margins.right //g元素(图表的宽度)
const g_height= h - config.margins.top - config.margins.bottom //g 元素的高

const left = g_height/(data.length/4)
var scaleY = d3.scaleLinear()
                .domain([0, Math.ceil(d3.max(config.ShowGridY, (d) => d)/10)*10])
                .range([g_height, 0])
/* ----------------------------尺度转换------------------------  */
const scaleX = d3.scaleBand()
         .domain(data.map((d) => d.x))
         .range([0, g_width])

const Y = d3.scaleLinear()
         .domain([0, d3.max(data, (d) => d.y)])
         .range([g_height, 0])
		
console.log(scaleX,scaleY)
var svg = d3.select(".svg")
			.append("svg")
			.attr("width", w)
			.attr("height", h);

坐标轴

svg.append("g")
        .attr('transform', 'translate('+ config.margins.left +',' + (parseFloat(config.margins.top) + parseFloat(g_height)) + ')')
        .attr('class', 'xAxis')
        .call(d3.axisBottom(scaleX));
svg.append("g")
		.attr('transform', 'translate('+ config.margins.left +',' + config.margins.top + ')')
		.attr('class', 'yAxis')
		.call(d3.axisLeft(scaleY));
//画线
d3.selectAll('.yAxis .tick')
    .each(function(d, i){
        if (config.ShowGridY.indexOf(d) > -1){
            d3.select(this).append('line')
              .attr('class','grid')
              .attr('stroke', config.gridColor)
              .attr('x1', 0)
              .attr('y1', 0)
              .attr('x2', g_width)
              .attr('y2', 0);
        }
    });

点坐标

let points = svg.selectAll('.point')
	            .data(data);
			
    points.enter()
        .append('circle')
        .classed('point', true)
        .merge(points)
        .attr('transform', 'translate('+ (config.margins.left+left-12.5) +',' + config.margins.top + ')')
        .attr('cx', (d) => scaleX(d.x))
        .attr('cy', (d) => scaleY(d.y))
        .attr('r', 0)
        .attr('fill', (d) => {
          if(d.t==1){
            return _colors(0)
          } else {
            return _colors(1)
          }
				})
        .transition().duration(config.animateDuration)
        .attr('r', config.pointSize)

柱状图

let bars = svg.selectAll('.bar')
				.data(data1);
			
bars.enter()
		.append('rect')
		.attr('class','bar')
		.merge(bars)
		.attr('transform', 'translate('+ (config.margins.left+left-12.5) +','+ config.margins.top +')')
		.attr('x', (d) => {
			return scaleX(d.x) - 5
		})
		.attr('y', (d) => scaleY(d.y))
		.attr('width', 10)
		.attr('height', (d) => scaleY(d.h))
		.attr('fill', (d) => {
			if(d.t==1){
				return _colors(0)
			} else {
				return _colors(1)
			}
		})
		.transition().duration(config.animateDuration)
		.attr('height', (d) => g_height - scaleY(d.h))
		.attr('y', (d) => scaleY(d.y));

完整代码

<template>
  <div class="svg">
	  
  </div>
</template>

<script>
import * as d3 from 'd3'
// import {chart} from "@/assets/js/chart.js"
export default {
  name: 'HelloWorld',
  data () {
    return {
      // arr: [1,2,3,4,5]
    }
  },
  mounted() {
	  var w = 600;
	  var h = 400;
	  const _colors = d3.scaleOrdinal(d3.schemeCategory10)
	  const config = {
      pointColor: _colors(0),
      barColor: _colors(1),
      margins: {top: 80, left: 80, bottom: 50, right: 80},
      textColor: 'black',
      gridColor: 'gray',
      ShowGridX: [1, 2, 3, 4, 5, 6, 7 ,8, 9, 10],
      ShowGridY: [20, 40, 60, 80, 100, 120, 140 ,160, 180, 200],
      title: '散点图',
      pointSize: 5,
      hoverColor: 'white',
      animateDuration: 1000
	  }
    // 点数据
	  const data = [{"x":"2021-12-20","y":119,"t":1},{"x":"2021-12-20","y":100,"t":1},{"x":"2021-12-20","y":74,"t":2},{"x":"2021-12-20","y":60,"t":2},{"x":"2021-12-21","y":122,"t":1},{"x":"2021-12-21","y":110,"t":1},{"x":"2021-12-21","y":82,"t":2},{"x":"2021-12-21","y":67,"t":2},{"x":"2021-12-22","y":120,"t":1},{"x":"2021-12-22","y":120,"t":1},{"x":"2021-12-22","y":78,"t":2},{"x":"2021-12-22","y":78,"t":2},{"x":"2021-12-23","y":120,"t":1},{"x":"2021-12-23","y":100,"t":1},{"x":"2021-12-23","y":86,"t":2},{"x":"2021-12-23","y":65,"t":2},{"x":"2021-12-24","y":124,"t":1},{"x":"2021-12-24","y":121,"t":1},{"x":"2021-12-24","y":77,"t":2},{"x":"2021-12-24","y":75,"t":2},{"x":"2021-12-25","y":109,"t":1},{"x":"2021-12-25","y":103,"t":1},{"x":"2021-12-25","y":91,"t":2},{"x":"2021-12-25","y":80,"t":2}]
    // 柱状图数据
    const data1 = [{"x":"2021-12-20","y":119,"h":19,"t":1},{"x":"2021-12-20","y":74,"h":14,"t":2},{"x":"2021-12-21","y":122,"h":12,"t":1},{"x":"2021-12-21","y":82,"h":15,"t":2},{"x":"2021-12-22","y":120,"h":0,"t":1},{"x":"2021-12-22","y":78,"h":0,"t":2},{"x":"2021-12-23","y":120,"h":20,"t":1},{"x":"2021-12-23","y":86,"h":21,"t":2},{"x":"2021-12-24","y":124,"h":3,"t":1},{"x":"2021-12-24","y":77,"h":2,"t":2},{"x":"2021-12-25","y":109,"h":6,"t":1},{"x":"2021-12-25","y":91,"h":11,"t":2}]

	  const g_width= w - config.margins.left - config.margins.right //g元素(图表的宽度)
	  const g_height= h - config.margins.top - config.margins.bottom //g 元素的高
	  
	  const left = g_height/(data.length/4)
	  var scaleY = d3.scaleLinear()
	                  .domain([0, Math.ceil(d3.max(config.ShowGridY, (d) => d)/10)*10])
	                  .range([g_height, 0])
    /* ----------------------------尺度转换------------------------  */
    const scaleX = d3.scaleBand()
            .domain(data.map((d) => d.x))
            .range([0, g_width])
	
	  const Y = d3.scaleLinear()
            .domain([0, d3.max(data, (d) => d.y)])
            .range([g_height, 0])
					
    console.log(scaleX,scaleY)
    var svg = d3.select(".svg")
			.append("svg")
			.attr("width", w)
			.attr("height", h);
    //画点
    let points = svg.selectAll('.point')
	            .data(data);
			
    points.enter()
        .append('circle')
        .classed('point', true)
        .merge(points)
        .attr('transform', 'translate('+ (config.margins.left+left-12.5) +',' + config.margins.top + ')')
        .attr('cx', (d) => scaleX(d.x))
        .attr('cy', (d) => scaleY(d.y))
        .attr('r', 0)
        .attr('fill', (d) => {
          if(d.t==1){
            return _colors(0)
          } else {
            return _colors(1)
          }
				})
        .transition().duration(config.animateDuration)
        .attr('r', config.pointSize)
				//画坐标轴
    svg.append("g")
        .attr('transform', 'translate('+ config.margins.left +',' + (parseFloat(config.margins.top) + parseFloat(g_height)) + ')')
        .attr('class', 'xAxis')
        .call(d3.axisBottom(scaleX));
		svg.append("g")
				.attr('transform', 'translate('+ config.margins.left +',' + config.margins.top + ')')
				.attr('class', 'yAxis')
				.call(d3.axisLeft(scaleY));
		//画线
		d3.selectAll('.yAxis .tick')
		    .each(function(d, i){
		        if (config.ShowGridY.indexOf(d) > -1){
              d3.select(this).append('line')
                .attr('class','grid')
                .attr('stroke', config.gridColor)
                .attr('x1', 0)
                .attr('y1', 0)
                .attr('x2', g_width)
                .attr('y2', 0);
		        }
		    });
				
		// d3.selectAll('.xAxis .tick')
		//     .each(function(d, i){
		//         if (config.ShowGridX.indexOf(d) > -1){
		//             d3.select(this).append('line')
		//                 .attr('class','grid')
		//                 .attr('stroke', config.gridColor)
		//                 .attr('x1', 0)
		//                 .attr('y1', 0)
		//                 .attr('x2', 0)
		//                 .attr('y2', -g_height);
		//         }
		//     });
			
		//画柱状图
		
		
		/* ----------------------------渲染柱形------------------------  */
		let bars = svg.selectAll('.bar')
				.data(data1);
			
		bars.enter()
				.append('rect')
				.attr('class','bar')
				.merge(bars)
				.attr('transform', 'translate('+ (config.margins.left+left-12.5) +','+ config.margins.top +')')
				.attr('x', (d) => {
					return scaleX(d.x) - 5
				})
				.attr('y', (d) => scaleY(d.y))
				.attr('width', 10)
				.attr('height', (d) => scaleY(d.h))
				.attr('fill', (d) => {
					if(d.t==1){
						return _colors(0)
					} else {
						return _colors(1)
					}
				})
				.transition().duration(config.animateDuration)
				.attr('height', (d) => g_height - scaleY(d.h))
				.attr('y', (d) => scaleY(d.y));
		
		
  },
  methods: {
     }
}
</script>

<style>
.box{
    margin: 10% auto;
    width: 600px;
    height: 400px;
    background-color: #ddd;
}

.axisText{
    font-size: 15px;
}

.title{
    font-size: 20px;
}
</style>


总结

以上是组合图,也可以单独用柱状图显示区间,看需求和ui设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值