shape-rendering: crispEdges


1 数轴简介

与比例尺相似,D3 的数轴实际上也是由你来定义参数的函数。但与比例尺不同的是,调用数轴函数并不会返回值,而是会生成数轴相关的可见元素,包括轴线、标签和刻度。

但要注意,数轴函数只适用于SVG 图形,因为它们生成的都是SVG 元素。同样,数轴是设计与定量比例尺(与序数比例尺相对)配合使用的。


2 设定数轴

使用d3.svg.axis() 可以创建通用的数轴函数:


var xAxis = d3.svg.axis();


要使用数轴,最起码要告诉它基于什么比例尺工作。在此,我们把绘制散点图时定义的xScale 传给它:


xAxis.scale(xScale);


还可以继续设置标签相对数轴显示在什么地方。默认位置是底部,也就是标签会出现在轴线下方。(虽然是默认值,但明确指定也不会引起异常。)水平数轴的位置可以在顶部也可以在底部。而垂直数轴则要么在左要么在右:


xAxis.orient("bottom");


当然,把这些方法连缀在一行会更简洁:


var xAxis = d3.svg.axis()

.scale(xScale)

.orient("bottom");


最后,要想实际生成数轴并把那些线条和标签插入到SVG 中,必须调用xAxis 函数。这一点与使用比例尺函数类似,即要先配置一番(设置参数),然后再通过调用将其付诸实用。

我想把这些代码放到脚本底部,以便在SVG 中的其他元素都生成之后再生成数轴,这样数轴就可以出现在“上面”了:


svg.append("g")

.call(xAxis);


的确看着有点不那么舒服。你可能会问,为什么调用数轴函数和调用比例尺函数看起来那么不一样呢?听我解释:

因为数轴函数实际上会在屏幕上绘制一些东西(通过把SVG 元素添加到DOM),所以我们需要指定在DOM 的什么地方插入这些新元素。这显然跟比例尺函数不一样,比例尺(比如xScale()),只是根据输入值来计算并返回值,主要是在其他函数里调用,不会影响DOM。

好,前面的代码首先引用了svg,即DOM 中的SVG 元素。然后,append() 在这个元素的末尾追加了一个新的g 元素。在SVG 标签内,g 元素就是一个分组。(group) 元素。分组元素是不可见的, 跟line、rect 和circle 不一样, 但它有两大用途:一是可以用来包含(或“组织”)其他元素,好让代码看起来简洁整齐;二是可以对整个分组应用变换,从而影响到该组中所有元素(line、rect 和circle)的视觉表现。关于变换,我们稍后就会介绍。

创建了新的g 元素后,直接在这个元素上面调用了call() 方法。那么call() 有什么用呢?

D3 的call() 函数会取得(比如刚才代码链中)传递过来的元素,然后再把它交给其他函数。对我们这例子而言,传递过来的元素就是新的分组元素g(虽然这个元素不是必需的,但鉴于数轴函数需要生成很多线条和数值,有了它就可以把所有元素都封装在一个分组对象内)。而call() 接着把g 交给了xAxis 函数,也就是要在g 元素里面生成数轴。

假设你喜欢把代码写得让人不容易看懂,那么可以把前面的两段合成下面这一段:


svg.append("g")

.call(d3.svg.axis()

.scale(xScale)

.orient("bottom"));


瞧,一行代码就定义并调用了数轴函数。不过,考虑到我们大脑的喜好,还是像前面那样先定义函数,然后再调用它更好理解。

无论如何,下图就是现在的结果


3 修整数轴

严格来讲,那确实是一个数轴。但从实用角度看,这家伙既不好看,也不中用。接下来看看怎么给它打扮一下。先给新创建的g 元素指定一个axis 类吧,这样好给它添加CSS 样式:


svg.append("g")

.attr("class", "axis") // 指定"axis" 类

.call(xAxis);


然后,在<head> 中的<style> 标签里写两条CSS 样式规则:


.axis path,

.axis line {

fill: none;

stroke: black;

shape-rendering: crispEdges;

}

.axis text {

font-family: sans-serif;

font-size: 11px;

}


现在知道把所有数轴元素都组织在一个g 分组中的好处了吧?这样只要使用简单的CSS 选择符.axis 就能为其中的任何元素应用样式。数轴本身是由path、line 和text 元素构成的,因此上面CSS 瞄准了这三个元素。其中,路径(path)和线条(line)可以共用相同的规则,而文本(text)则有自己的字体和字号设置。

注意到了吗,通过CSS 给SVG 元素应用样式时,只能使用SVG 的属性名,而不能使用常规的CSS 属性。要注意的是,虽然很多属性在CSS 和SVG 中的名字相同,但也有一些不相同。比如,要使用常规的CSS 属性设置文本颜色,那应该这样写:


p {

color: olive;

}


这样就给所有段落p 的文本设定了橄榄绿色(olive)。但同样的属性如果应用给SVG 元素,比如


text {

color: olive;

}


不会有什么效果,因为color 不是SVG 能够识别的属性名。这时候,必须使用SVG 中不同名但作用一样的fill 属性:


text {

fill: olive;

}


如果你在给SVG 元素应用样式时,发现CSS 代码根本不起作用,我劝你不要心急。深呼吸,稍等一下,再仔细瞧瞧那些属性名,一定要保证是SVG 的,而不是CSS的。(要了解SVG 都有哪些属性,可以参考w3 网站:http://www.w3school.com.cn/svg/index.asp。)


这里用到的shape-rendering 也是一个奇怪的SVG 属性。使用它是为了保证数轴和刻度线精确到像素级。不要给我一个模糊的数轴!

用CSS 打扮后的数轴如图所示

好些了,但数轴顶部的线被切掉了,而且数轴本来应该显示在图表底下嘛。这时候,就该用到SVG 变换(transform)了。只要添加一行代码,就可以把整个数轴分组平移到图表下方:


svg.append("g")

.attr("class", "axis")

.attr("transform", "translate(0," + (h - padding) + ")")

.call(xAxis);


新增的这行代码在attr() 中设置了g 元素的属性transform。SVG 中的变换功能非常强大,有多种不同的变换方式,包括缩放和旋转。但我们暂时只介绍平移(translation)变换,它可以把整个g 分组向下移动一定距离。

平移变换的语法很简单,就是translate(x,y),其中x 和y 的含义都非常明确,就是要把元素移动到的新位置的x 和y 坐标。因此,在DOM 中我们会看到g 元素动态添加了如下代码:


<g class="axis" transform="translate(0,280)">


由此可见,g.axis 不会水平移动,但会向下移动280 像素,正好移到图表底部。

下面大概解释一下设置平移变换的代码:


.attr("transform", "translate(0," + (h - padding) + ")")


注意这里使用了(h-padding), 这是要把分组的顶边y 坐标设置为h, 即整个SVG 元素的高度——然后,再减去我们前面定义的边距值(padding)。经过计算,(h-padding) 等于280,再跟其他字符串拼接起来,就得到了最终的变换属性值:translate(0,280)。

如图所示的结果看起来舒服多了!完整代码请查看02_axes_bottom.html 吧。


4 优化刻度

数轴的刻度线(tick)是用来传达信息的,但也不是越多越好,多过某个数量,刻度线反而会让图表显得混乱。到现在为止,我们还没有指定数轴上要显示多少根刻度线,也没有指定两根刻度线的间距。就在我们全无指示的情况下,D3 自动检测了比例尺xScale,从而作出了有数量依据的判断,帮我们确定了要画多少刻度线,以及刻度线之间的间隔(这里是50 像素)。

当然,你可以干预数轴的任何方面。比如,使用ticks() 方法就可以粗略地指定刻度线的数量:


var xAxis = d3.svg.axis()

.scale(xScale)

.orient("bottom")

.ticks(5); // 粗略地设置刻度线的数量


完整代码请参见03_axes_clean.html。

通过下图可以看到,尽管我们设置了5 根刻度线,但D3 则擅自作主,画出了7根。这是D3 在保护你呢,因为它发现5 根刻度线会把输入值域切分成不够恰当的值(也就是0、150、300、450 和600)。D3 只将ticks() 的值作为一个建议,如果它发现有更清晰更方便理解的值(比如以100 为间隔),哪怕比你设置的值多一点或少一点,它也会采用。实际上,这是一个非常出彩的功能,可以确保设计的可伸缩性。随着数据集的变化,输入值域的扩大或缩小(数值变得更大或更小),D3 都可以保证刻度标签的数量合适而且易读。

好了,关于横坐标轴的方面的代码就介绍到这里,下一节我们将为你介绍纵坐标的代码。其实,只要在今天的代码上改那么一点点就可以了,你有没有兴趣先试试呢?


cd C:\Program Files\FlightGear fgfs --fg-root=C:\Program Files\FlightGear\data --aircraft=ufo --in-air --fdm=null --telnet=5501 --telnet=5502 --telnet=5503 --disable-ai-traffic --disable-real-weather-fetch --disable-random-objects --disable-terrasync --disable-clouds --disable-sound --disable-panel --disable-hud --disable-specular-highlight --timeofday=noon --prop:/sim/rendering/multi-sample-buffers=1 --prop:/sim/rendering/multi-samples=2 --prop:/sim/rendering/draw-mask-clouds=false --prop:/sim/rendering/draw-mask-terrain=true --prop:/sim/rendering/draw-mask-objects=true --prop:/sim/rendering/draw-mask-lights=true --prop:/sim/rendering/draw-mask-internal=true --prop:/sim/rendering/draw-mask-cockpit=true --prop:/sim/rendering/draw-mask-effects=true --prop:/sim/rendering/draw-mask-overlay=true --prop:/sim/rendering/draw-mask-world=true --prop:/sim/rendering/draw-mask-panel=true --prop:/sim/rendering/draw-mask-vr=true --prop:/sim/rendering/draw-mask-2d=true --prop:/sim/rendering/draw-mask-3d=true --prop:/sim/rendering/draw-mask-sky=true --prop:/sim/rendering/draw-mask-shadows=true --prop:/sim/rendering/draw-mask-cabin=true --prop:/sim/rendering/draw-mask-weather=true --prop:/sim/rendering/draw-mask-stereo=true --prop:/sim/rendering/draw-mask-internal-cockpit=true --prop:/sim/rendering/draw-mask-internal-windows=true --prop:/sim/rendering/draw-mask-internal-instruments=true --prop:/sim/rendering/draw-mask-internal-overlay=true --prop:/sim/rendering/draw-mask-internal-effects=true --prop:/sim/rendering/draw-mask-internal-lights=true --prop:/sim/rendering/draw-mask-internal-world=true --prop:/sim/rendering/draw-mask-internal-panel=true --prop:/sim/rendering/draw-mask-internal-3d=true --prop:/sim/rendering/draw-mask-internal-sky=true --prop:/sim/rendering/draw-mask-internal-cabin=true --prop:/sim/rendering/draw-mask-internal-weather=true --prop:/sim/rendering/draw-mask-internal-stereo=true --prop:/sim/rendering/draw-mask-internal-shadow=true --prop:/sim/rendering/draw-mask-internal-stall=true --prop:/sim/rendering/draw-mask-internal-aoa=true --prop:/sim/rendering/draw-mask-internal-thermal=false --prop:/sim/rendering/draw-mask-internal-ice=false --prop:/sim/rendering/draw-mask-internal-glass=true --prop:/sim/rendering/draw-mask-internal-dead=true --prop:/sim/rendering/draw-mask-internal-reflection=true程序显示错误unknown command-line option: enable-hud-2d怎么解决
05-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值