antv完成区间柱形图一列多柱配置实现详解
code_Bo 人气:0使用antv 配置区间柱形图
需求: 来源与产品的一个想法,想在 X 轴 每一行输出多个区间柱形,以时间为分段,X轴 底线显示时间, 找了一下 echarts 的实现, 可以使用配置函数的方式 实现,但只实现了一行,而且函数的配置项其API 文档也晦涩难懂, 最后使用 antv 的 区间柱形图来实现, 但是 antv 无法像 echarts 一样配置每一个柱形的颜色, 因为他的 color 配置回调函数只接受一个 type 字符串类型, 最后使用了数组队列匹配的方式来实现
使用的是 antv 的 g2plot 官方分组柱形图效果如下: 定位链接: g2plot.antv.vision/zh/examples…
实现之后的效果
分享思路
- 文件引入 这里是 html 文件, 直接可以复制, 下面的 js 文件我我们通过引入 CDN 的方式,这样在使用 demo 的时候更加方便
<!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> </head> <style> .root { padding: 50px; width: 1600px; height: 500px; } </style> <body> <div id="container" class="root"></div> </body> </html>
js文件
<script type="text/javascript" src="https://unpkg.com/@antv/g2plot@latest/dist/g2plot.min.js" ></script>
引入了 g2 以后
上面引入了 g2 以后 , 我们开始分享业务逻辑, 里面包含一些功能函数, 会拆开 首先是功能函数, 会在 我们的业务当中使用到的
// 时间处理 // 小时转分钟 function ChangeStrToMinutes(str) { var arrminutes = str.split(":"); if (arrminutes.length == 2) { var minutes = parseInt(arrminutes[0]) * 60 + parseInt(arrminutes[1]); return minutes; } else { return 0; } } // 分钟转小时 function ChangeHourMinutestr(str) { if (str !== "0" && str !== "" && str !== null) { return ( (Math.floor(str / 60).toString().length < 2 ? "0" + Math.floor(str / 60).toString() : Math.floor(str / 60).toString()) + ":" + ((str % 60).toString().length < 2 ? "0" + (str % 60).toString() : (str % 60).toString()) ); } else { return ""; } } // 样式处理 const setStyles = (container, styles) => { for (const key in styles) { container.style[key] = styles[key]; } }; // 动态设置画布高度 function setHeigh(data, name, height = 100) { const dom = document.getElementsByClassName(name)[0]; const count = data.length; dom.style["height"] = count * height + "px"; }
业务逻辑处理
注意点:
- 数据使用的是假数据, 这里我们可以根据自己的业务需求进行修改和扩展 因为区间柱形图使用的数据 data 是一个数组, 所以在使用我们的数据的时候需要进行一下改造
- 在使用 color 回调函数进行配置颜色的时候,不知道里面的循环为什么会进入两次,如果有大佬可以解答或有其他解决方案欢迎交流, 这里我使用了一个闭包的方式来记录次数,因为这里的数据我们业务上还没有和后端对接,所以暂时无法判定哪一条是第一个数据,而且 color 这回调函数也不提供 其他参数, 只提供一个 type 是字符串 作为参数, 所以我在上面数据处理的方法里面自己加入了一个 空字符的 type,用来区分循环的进入。
- 因为 color 方法的参数只有 type, 所以我也无法区分当前应该显示哪一种颜色, 数据里面的 way 就是颜色, 这里我使用了一个临时队列 arr 也是以闭包的形式存储, 然后从我处理好的数据中 过滤出当前 type 类型组成的一个数组, 通过下标的方式 取到当前对应的数据
- tooltip 如果想要自定义的话 需要使用 customContent API
- 由于我们这柱形一行有多个, 默认是鼠标悬浮到当前行,没有到我们的柱上,就会有 tooltip 提示, 可以设置shared 来匹配鼠标悬浮到柱形上才显示 tooltip
const { Bar } = G2Plot; // 假数据 var busDataInfo = [ { module: "BJ6123C7BTD", line: "8", wayLine: [ { time: ["05:50", "06:30"], way: "E", }, { time: ["06:42", "08:32"], way: "S", }, { time: ["08:46", "10:39"], way: "E", }, { time: ["14:06", "15:46"], way: "S", }, ], }, { module: "BJ6123C7BTD", line: "7", wayLine: [ { time: ["05:00", "06:30"], way: "S", }, { time: ["06:42", "08:32"], way: "E", }, { time: ["08:46", "10:39"], way: "S", }, { time: ["14:06", "15:46"], way: "E", }, ], }, { module: "BJ6123C7BTD", line: "6", wayLine: [ { time: ["05:00", "06:00"], way: "S", }, { time: ["06:12", "08:42"], way: "E", }, { time: ["08:46", "09:09"], way: "S", }, { time: ["14:06", "15:46"], way: "E", }, { time: ["16:10", "18:00"], way: "S", }, { time: ["18:34", "20:07"], way: "E", }, ], }, ]; // 数据改造 将上面的数据改造成我需要的数组格式 function changeData(data) { const outPutData = []; data.forEach((item) => { item.wayLine.forEach((every) => { outPutData.push({ type: item.line, module: item.module, way: every.way, values: [ ChangeStrToMinutes(every.time[0]), ChangeStrToMinutes(every.time[1]), ], }); }); }); //TODO 这里是为了解决 颜色 处理部分循环进入两次的问题, 这里写在 上面的数据处理之前和之后 会有分别,分别在于 后面是否使用 reverse 反转数组 outPutData.push({}); return outPutData; } // 样式 const divStyles = { position: "absolute", background: "rgba(255,255,255,0.95)", boxShadow: "rgb(174, 174, 174) 0px 0px 10px", borderRadius: "4px", padding: "10px", }; // 画布高度设置, 是根据数组数据长度,挂载点,以及高度 三个参数来进行设置 setHeigh(busDataInfo, "root", 60); const data = changeData(busDataInfo); // 画布实例化 const barPlot = new Bar("container", { barWidthRatio: 0.7, // 条形图宽度占比 data: data, xField: "values", yField: "type", colorField: "type", // 部分图表使用 seriesField color: ((arg) => { var count = 0; var arr = []; return (arg) => { const { type = "" } = arg; if (type === "") { count = count + 1; } // 解决循环会进入两次的问题 if (count !== 1) return; arr.push(type); let currentArr = data.filter((item) => item.type === type); let filterArr = arr.filter((item) => item === type); // 获取当前往返类型 const wayType = currentArr[filterArr.length - 1]?.way; console.log("type", type, wayType, currentArr); if (wayType === "E") { return "#FF5CA2"; } return "#6C3E00"; }; })(), xAxis: { // x轴文本标签配置项 label: { formatter: (value) => { return ChangeHourMinutestr(value); }, }, // 坐标轴网格线的配置项 grid: { // alignTick:false, }, // 坐标轴线样式 // line: // { // style: // { // stroke: 'black', // lineWidth: 1, // strokeOpacity: 0.7, // shadowColor: 'black', // shadowBlur: 10, // shadowOffsetX: 5, // shadowOffsetY: 5, // cursor: 'pointer' // } // }, // 坐标轴刻度线样式 tickLine: { length: 1, style: (item, index, items) => { return { stroke: "black", lineWidth: 2, lineDash: [4, 5], strokeOpacity: 0.7, shadowColor: "black", shadowBlur: 10, shadowOffsetX: 5, shadowOffsetY: 5, cursor: "pointer", }; }, }, min: 270, // 坐标轴最小值 这里指分钟数 tickCount: 20, // 坐标轴刻度数量 如果写了下面的刻度间隔, 则数量优先级变低 tickInterval: 30, // 坐标轴刻度间隔 }, isRange: true, // 柱形上面的文字 label: { content: "", }, // barBackground: { // style: { // fill: '#000', // fillOpacity: 0.01, // } // }, tooltip: { fields: ["type", "way", "module", "values"], // formatter:(data)=>{ // const { type,module,way,values} = data // console.log('data',data); // return { // name:module, // values:way // } // }, shared: false, // 只在鼠标悬浮到块上再展示 showCrosshairs: false, customContent: (value, item) => { console.log("customContent", value, item[0]); if (!value || !item) return; const { data } = item[0]; const container = document.createElement("div"); setStyles(container, divStyles); container.innerHTML = `<div>车辆号码${data.type}</div><div>往返:${data?.way}</div>`; return container; }, }, }); // 官方颜色主题 barPlot.update({ theme: { styleSheet: { brandColor: "#FF4500", paletteQualitative10: [ "#FF4500", "#1AAF8B", "#406C85", "#F6BD16", "#B40F0F", "#2FB8FC", "#4435FF", "#FF5CA2", "#BBE800", "#FE8A26", ], paletteQualitative20: [ "#FF4500", "#1AAF8B", "#406C85", "#F6BD16", "#B40F0F", "#2FB8FC", "#4435FF", "#FF5CA2", "#BBE800", "#FE8A26", "#946DFF", "#6C3E00", "#6193FF", "#FF988E", "#36BCCB", "#004988", "#FFCF9D", "#CCDC8A", "#8D00A1", "#1CC25E", ], }, }, }); 挂载 barPlot.render();
- 如果想查看本 demo 的效果, 可以把以上代码直接复制到 自己的 HTML 文件中, 运行即可
- 参考 antv g2plot
加载全部内容