全国服务热线:4008-888-888

公司新闻

小程序运营教程_D3.js 完成带伸缩时间轴拓扑图的

D3.js 实现带伸缩时间轴拓扑图的示例代码       这篇文章主要介绍了D3.js 实现带伸缩时间轴拓扑图的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧


基于d3-v5, 依赖dagre-d3, 直接上代码:

 !DOCTYPE html 
 html lang="en" 
 head 
 meta charset="UTF-8" 
 meta name="viewport" content="width=device-width, initial-scale=1.0" 
 meta http-equiv="X-UA-Compatible" content="ie=edge" 
 title Document /title 
 style 
 svg {
 border: 1px solid darkcyan;
 /* 拓扑图--start */
 /* 节点状态颜色 */
 g.type-current circle {
 fill: #FFAC27;
 g.ess circle {
 fill: #9270CA;
 g.type-fail circle {
 fill: #67C23A;
 g.type-done circle {
 fill: #E8684A;
 /* 拓扑图--end */
 /* 坐标轴-start */
 .axis path,
 .axis line {
 fill: none;
 stroke: #DCDCDC;
 shape-rendering: crispEdges;
 .axis text {
 font-family: sans-serif;
 font-size: 12px;
 fill: #999999;
 .axis .x2-axis text {
 font-size: 14px;
 font-weight: 400;
 fill: #333;
 .axis .x2-axis .tick {
 stroke-width: 2px;

script src=" d3.v5.min.js " /script script src="dagre-d3/0.6.3/dagre-d3.js" /script body /body script let nodeInfo = [{ id: 0, label: "", status: 'success', date: 00 }, { id: 1, label: "", status: 'fail', date: 00 }, { id: 2, label: '', status: 'success', date: 00 }, { id: 3, label: '', status: 'fail', date: 00 }, { id: 4, label: '', status: 'current', date: 00 }, { id: 5, label: '', status: 'done', date: 00 }, { id: 6, label: '', status: 'done', date: 00 }, { id: 7, label: '', status: 'done', date: 00 }, { id: 8, label: '', status: 'success', date: 00 let lineInfo = [ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 2, to: 4 }, { from: 2, to: 5 }, { from: 3, to: 6 }, { from: 6, to: 7 }, { from: 6, to: 8 }, let nodeMap = new Map() //节点信息map let nodeDomMap = new Map() //节点dom--map let timeArr = [] //存储时间 const width = 1200 const height = 400 const padding = { top: 0, bottom: 40, left: 40, right: 40 } // 节点信息转化为map nodeInfo.forEach(item = { nodeMap.set(item.id, item); timeArr.push(item.date) let max = new Date(d3.max(timeArr)) let min = new Date(d3.min(timeArr)) maxY = max.getFullYear() maxM = max.getMonth() minY = min.getFullYear() minM = min.getMonth() // 创建画布 svg let svg = d3.select("body").append("svg") .attr("id", "svg-canvas") .attr("preserveAspectRatio", "xMidYMid meet") .attr("viewBox", `0 0 ${width} ${height}`) // 初始化元素 let background = svg.append("rect").attr("class", "bg") let view = svg.append("g").attr("class", "view") let grid = svg.append("g").attr("class", "grid") let axis = svg.append("g").attr("class", "axis") let separateLine = svg.append("line").attr("class", "separate-line") // 绘制箭头以供引用 d3.select("#svg-canvas").append("defs").append("marker") .attr("id", "triangle").attr("viewBox", "0 0 10 10") .attr("refX", "17").attr("refY", "5") .attr("markerWidth", "6").attr("markerHeight", "6") .attr("orient", "auto").append("path") .attr("d", "M 0 0 L 10 5 L 0 10 z").style("fill", "#bbbbbb") // 添加背景板 rect background.attr("fill", "#FAFAFA") .attr("x", 0).attr("y", 0) .attr("width", width).attr("height", height - padding.bottom) const monthNum = d3.timeMonth.count(min, max) // 区间月份数量 // 确定比例尺 let xScale = d3.scaleTime() .domain([new Date(minY, minM, 1), new Date(maxY, ++maxM, 1)]) .range([0, width - padding.left - padding.right]) // 坐标轴文本格式化 let formatDay = d3.axisBottom(xScale).tickFormat((d, i) = { const date = new Date(d) const day = date.getDate() return `${day === 1 "" : day}` // 如果是1号, 不显示刻度,直接由xAxis2显示年月 let formatMonth = d3.axisBottom(xScale).ticks(d3.timeMonth.every(1)).tickPadding(6).tickSizeInner(20).tickFormat((d, i) = { const date = new Date(d) const mon = date.getMonth() + 1 const year = date.getFullYear() return `${year} - ${mon 9 mon : "0" + mon}` axis.attr('transform', `translate(${padding.left},${height - padding.bottom})`) let xAxisDay = axis.append("g") .attr("class", "x-axis").call(formatDay) let xAxisMonth = axis.append("g") .attr("class", "x2-axis").call(formatMonth)
const lineGroup = grid.attr("transform", `translate(${padding.left},0)`) .selectAll("g") .data(xScale.ticks(monthNum)) .enter().append("g") lineGroup.append("line") .attr("x1", d = { return xScale(new Date(d)) }) .attr("x2", d = { return xScale(new Date(d)) }) .attr("y1", padding.top) .attr("y2", height - padding.bottom) .attr("class", "grid-line") .style("stroke", "#DCDCDC") .style("stroke-dasharray", 6) // 添加坐标轴与拓扑图分隔线 separateLine.style("stroke", "#DCDCDC") .style("stroke-width", 2) .attr("x1", 0) .attr("x2", width) .attr("y1", height - padding.bottom) .attr("y2", height - padding.bottom) // 绘制流程图 节点--箭头 let g = new dagreD3.graphlib.Graph() .setGraph({}) .setDefaultEdgeLabel(function () { return {}; }); g.graph().rankdir = "LR"; // 控制水平显示 g.graph().marginx = 0; g.graph().marginy = 50; nodeInfo nodeInfo.map((item, i) = { g.setNode(item.id, { label: item.label, class: "type-" + item.status, style: "stroke-width: 2px; stroke: #fff", shape: "circle", id: item.id lineInfo lineInfo.map((item, i) = { g.setEdge(item.from, item.to, arrowheadStyle: "stroke:none; fill: none", // 箭头头部样式 style: "stroke:none; fill: none" //线条样式 let render = new dagreD3.render(); render(view.attr("transform", `translate(${padding.left},0)`), g); // 重新定位节点x坐标 const nodesArr = d3.select(".nodes").selectAll(".node")._grou凡科抠图[0] nodesArr.forEach((item) = { let dom = d3.select(item)._grou凡科抠图[0][0] let id = Number(dom.id) let date = nodeMap.get(id).date const x = xScale(new Date(date)); const y = dom.transform.animVal[0].matrix.f d3.select(item).attr("transform", `translate(${x},${y})`) nodeDomMap.set(Number(item.id), item) // 重新绘制箭头 lineInfo lineInfo.map((item, i) = { let fromDom = nodeDomMap.get(Number(item.from)) let toDom = nodeDomMap.get(Number(item.to)) const [x1, y1, x2, y2] = [ fromDom.transform.animVal[0].matrix.e, fromDom.transform.animVal[0].matrix.f, toDom.transform.animVal[0].matrix.e, toDom.transform.animVal[0].matrix.f, d3.select(".edgePaths").append("g") .append("line") .attr("class", `to-${item.to}`) // 设置唯一的class方便修改路径 .attr("stroke-width", "2") .attr("stroke", "#bbbbbb") .style("stroke-dasharray", 8) .attr("marker-end", "url(#triangle)") .attr("x1", x1).attr("y1", y1) .attr("x2", x2).attr("y2", y2) // 设置zoom参数 let zoom = d3.zoom() .scaleExtent([1, 10]) .translateExtent([[0, 0], [width, height]]) //移动的范围 .extent([[0, 0], [width, height]])//视窗 (左上方,右下方) svg.call(zoom.on("zoom", reRender.bind(this)));
function reRender() { const t = d3.event.transform.rescaleX(xScale) //获得缩放后的比例尺 xAxisDay.call(formatDay.scale(t)) //重新设置x坐标轴的scale xAxisMonth.call(formatMonth.scale(t)) //重新设置x坐标轴的scale const view = d3.select(".output") const axis = d3.select(".axis-month") const grid = d3.selectAll(".grid-line") // 重新绘制节点 nodesArr.forEach((item) = { let dom = d3.select(item)._grou凡科抠图[0][0] let id = Number(dom.id) let date = nodeMap.get(id).date const x = t(new Date(date)); const y = dom.transform.animVal[0].matrix.f d3.select(item).attr("transform", `translate(${x},${y})`) nodeDomMap.set(Number(item.id), item) // 重新绘制箭头 lineInfo lineInfo.map((item, i) = { let fromDom = nodeDomMap.get(Number(item.from)) let toDom = nodeDomMap.get(Number(item.to)) const [x1, y1, x2, y2] = [ fromDom.transform.animVal[0].matrix.e, fromDom.transform.animVal[0].matrix.f, toDom.transform.animVal[0].matrix.e, toDom.transform.animVal[0].matrix.f, d3.select(`.to-${item.to}`) .attr("x1", x1).attr("y1", y1) .attr("x2", x2).attr("y2", y2) //重新绘制x网格 svg.selectAll(".grid-line") .attr("x1", d = { return t(new Date(d)) }) .attr("x2", d = { return t(new Date(d)) })


在线客服

关闭

客户服务热线
4008-888-888


点击这里给我发消息 在线客服

点击这里给我发消息 在线客服