d3动态坐标轴
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>动态坐标轴</title> <link rel="stylesheet" type="text/css" href="../../css/styles.css"/> <script type="text/javascript" src="../../lib/d3.js"></script> </head> <body> <div class="control-group"> <button onclick="rescale()">重新生成坐标轴</button> </div> <script type="text/javascript"> let height = 500, width = 500, margin = 30, xAxis, yAxis, xAxisLength, yAxisLength; xAxisLength = width - 2*margin; yAxisLength = height - 2*margin; //创建一个svg标签画布 //后面还要创建一个g标签,用于画坐标系 let svg = d3.select("body").append("svg") .attr("class", "axis") .attr("width", width) .attr("height", height) .style("background-color","#cedb9c"); /** * 创建坐标轴
* 一个坐标轴包含:尺度、刻度、相对位置
* 尺度:一个映射关系,请业务数据映射到画布的线上,所有要有两组数据,一组为业务数据,另外一组则是画布的一个线段
* 刻度:类似米尺上的刻度,比如一厘米一大格,中间又有一些代表毫米的小格
* 相对位置:米尺是个实物,而这里的刻度是画在画布上的,就是刻度在画布上的位置 */ function renderXAxis() { //domain是值就是d3.svg.axis坐标系的x与y的值 //svg.axis就是业务数据坐标系,其数据是有业务含义的 //range的值是svg画布像素的长度,意思就是要将业务数据domain画在(映射到)svg画布的指定长度范围内 let scale = d3.scale.linear() .domain([0,100]) .range([0,xAxisLength]);
xAxis = d3.svg.axis() .scale(scale) .tickSubdivide(1) .orient("bottom");
//<sgv class="axis"><g class="x-axis" >...<g class="y-axis" ... svg.append("g") .attr("class","x-axis") .attr("transform",function () { return "translate("+margin+","+(xAxisLength+margin)+")"; }) .call(xAxis); } function renderYAxis() { let scale = d3.scale.linear() .domain([100,0]) .range([0,yAxisLength]) yAxis = d3.svg.axis() .scale(scale) .tickSubdivide(1) .orient("left");
//坐标轴是以svg标签下的g标签为画板的 svg.append("g") .attr("class","y-axis") .attr("transform",function () { return "translate("+margin+","+margin+")"; }) .call(yAxis); } /** * X坐标轴对应的网格线对应的两个点 * 一个是坐标系原点(0,0) * 一个是Y轴的终点(0,-yAxisLength) */ function renderXGridLines() { //通常坐标重构前都会删除已有的图形,尽管有时它不并存在 d3.selectAll("g.x-axis g.tick") .select("line.grid-line") .remove(); //然后重新选取新的图形 let lines = d3.selectAll("g.x-axis g.tick") .append("line") .classed("grid-line",true); //图形中涉及的坐标系是SVG坐标系,上负下正,右正 lines.attr("x1",0) .attr("y1",0) .attr("x2",0) .attr("y2",-yAxisLength); } /** * Y坐标轴对应的网格线对应的两个点 * 一个是坐标系原点(0,0) * 一个是X轴的终点(xAxisLength,0) */ function renderYGridLines() { //通常坐标重构前都会删除已有的图形,尽管有时它不并存在 d3.selectAll("g.y-axis g.tick") .select("line.grid-line") .remove(); //然后重新选取新的图形 let lines = d3.selectAll("g.y-axis g.tick") .append("line") .classed("grid-line",true); lines.attr("x1",0) .attr("y1",0) .attr("x2",xAxisLength) .attr("y2",0); } /** * 通过改变坐标轴的尺度来重构坐标系 */ function rescale() { let max = Math.round(Math.random()*100); let duration = 5000; xAxis.scale().domain([0,max]); //构建坐标轴会在g标签中添加class为tick的g标签,删除这个就相当于删除了坐标轴 //call方法中会自动删除,所以这里不需要这一步了 // d3.selectAll("g.x-axis g.tick") // .remove(); d3.select("g.x-axis") .transition() .duration(duration) .call(xAxis); yAxis.scale().domain([max,0]); d3.select("g.y-axis") .transition() .duration(duration) .call(yAxis); renderXGridLines(); renderYGridLines(); } renderXAxis(); renderYAxis(); renderXGridLines(); renderYGridLines(); </script> </body> </html>
附css样式 css/styles.css
body { font-family: "helvetica"; } button { margin: 0 7px 0 0; background-color: #f5f5f5; border: 1px solid #dedede; border-top: 1px solid #eee; border-left: 1px solid #eee; font-size: 12px; line-height: 130%; text-decoration: none; font-weight: bold; color: #565656; cursor: pointer; } .box { width: 200px; height: 200px; margin: 40px; float: left; text-align: center; border: #969696 solid thin; padding: 5px; } .red { background-color: #e9967a; color: #f0f8ff; } .blue { background-color: #add8e6; color: #f0f8ff; } .cell { min-width: 40px; min-height: 20px; margin: 5px; float: left; text-align: center; border: #969696 solid thin; padding: 5px; } .fixed-cell { min-width: 40px; min-height: 20px; margin: 5px; position: fixed; text-align: center; border: #969696 solid thin; padding: 5px; } .h-bar { min-height: 15px; min-width: 10px; background-color: steelblue; margin-bottom: 2px; font-size: 11px; color: #f0f8ff; text-align: right; padding-right: 2px; } .v-bar { min-height: 1px; min-width: 30px; background-color: #4682b4; margin-right: 2px; font-size: 10px; color: #f0f8ff; text-align: center; width: 10px; display: inline-block; } .baseline { height: 1px; background-color: black; } .clear { clear: both; } .selected { background-color: #f08080; } .control-group { padding-top: 10px; margin: 10px; } .table { width: 70%; } .table td, th { padding: 5px; } .table-header { background-color: #00AFEF; font-weight: bold; } .table-row-odd { background-color: #f0f8ff; } .table-row-odd { background-color: #d3d3d3; } .code { display: inline-block; font-style: italic; background-color: #d3d3d3; border: #969696 solid thin; padding: 10px; margin-top: 10px; margin-bottom: 10px; } .countdown{ width: 150px; height: 150px; font-size: 5em; font-weight: bold; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .axis text { font: 10px sans-serif; } .axis .grid-line{ stroke: black; shape-rendering: crispEdges; stroke-opacity: .2; } .line{ fill: none; stroke: steelblue; stroke-width: 2; } .dot { fill: #fff; stroke: steelblue; } .area { stroke: none; fill: steelblue; fill-opacity: .2; } .pie text{ fill: white; font-weight: bold; } .circle { stroke: none; fill: red; fill-opacity: .7; } .cross { stroke: none; fill: blue; fill-opacity: .7; } .diamond { stroke: none; fill: green; fill-opacity: .7; } .square{ stroke: none; fill: yellow; fill-opacity: .7; } .triangle-down{ stroke: none; fill: blueviolet; fill-opacity: .7; } .triangle-up{ stroke: none; fill: darkred; fill-opacity: .7; } .bubble{ fill-opacity: .3; } .bar{ stroke: none; fill: steelblue; }