文章目录

  • 引言
  • D3介绍和使用
    • 确定大概流程
    • SVG介绍
    • 确定布局
    • 获得并且设置svg
    • 绑定数据
    • 设置比例尺
    • 绘制坐标轴
    • 添加标题
    • 添加交互效果
    • 导出可视化结果
  • 拓展
  • 小结
  • 参考资料

引言

《复仇者联盟4:终局之战》如今正在热映当中。最高高达300多元的票价也真的是“前无古人,后无来者”,出现了“今天你请我看《复联4》,明天我们就是兄弟”的江湖义气。

《复联4》的大火,很大程度和去年的《复仇者联盟3:无限战争》的悲惨的结局有关——宇宙里一半的生命消失了。而这个结果是由很多因素导致的,但是超级英雄的之一的星爵的最后一顿坑爹操作得负很大的责任。影迷们都异常愤怒,于是根据《复联3》中超级英雄的表现,下面这张图诞生了。
十七世纪的大科学家伽利略曾经说过:“我们要测量那些可以测量的东西,至于那些无法测量的东西,我们也要想办法加以测量”。的确,“坑”这种说法太模糊了,下面我们就来“测量”一下星爵“坑”的程度。假如星爵的战斗力为1,并且高一级别的每个英雄的战斗力是低一级别的2倍,那么就获得如下的这张表格。

级别 每个英雄的战斗力 人数 总战斗力
超神 32 1 32
很厉害 16 2 32
有帮上忙 8 4 32
尽力了 4 11 44
废物 2 5 20
一坨屎 1 1 1


看了这个表,大家应该能隐隐约约地感受到了星爵的坑队友行为了,但是这还不够。接下来我们要一起可视化一下这些数据,用D3写一个可以在浏览器展示的可以交互的条形图,一起更真切地感受星爵的坑爹行为。效果如下:

现在我们来仔细看看这个条形图(如下图)。星爵的“坑”简直铺面而来,有没有?在队友的战斗力面前,他就像蚂蚁遇见了姚明一样微不足道。另一方面我们也可以很快地发现一个有趣的现象,那就是虽然“尽力了”级别每个英雄的战斗力不高,但是这个级别的战斗力总和却是最高的!难道三个臭皮匠真的可以顶一个诸葛亮?

下面我们就从0到1来实现上面到效果,当然这里必须强调说明上面的数据纯属娱乐,大家不要当真。

本篇文章一共有两个部分:第一部分介绍网页的组成和开发基础(HTML、CSS、JavaScript等),让你们可以开发和调试一些简单的网页;第二部分介绍D3的基本概念和使用,并且一起来完成上述条形图。

如果按耐不住内心激动的同学,可以先看看这个条形图的在线效果或者完整代码(代码量不多)。

同时本人水平有限,接下来内容若有讲解得不恰当的地方,希望大家指出,我感激不尽!
  

D3介绍和使用

  到目前为止,我们已经搭建好了网页的大概框架,下面我们要做的就是用D3完成可视化部分的代码。按照惯例我们先来了解一下D3。
  D3(Data-Driven Documents)是一个基于JavaScript的库(就像Processing是基于Java一样),主要目的是通过HMTL,SVG,CSS来给数据生命。D3允许我们将任意数据和基于网页的文档(Documnts)绑定起来(就是任意可以被浏览器渲染的东西,比如HTML、SVG),在数据和文档之间建立联系,这个就是所谓的数据驱动(Data-Driven)。
  在学习D3之前,我们先来谈谈我们选择D3进行可视化的理由。
  首先我们得说说为什么需要计算机来参与可视化的过程,直接用笔在纸上画为什么不行?。一方面是数据太多,将每一个数据画出来需要花太多的时间。比如下面的a图还勉强可以让人来画,但是面对b图,人就显得无能为力了。另一方面,数据集随着时间一般在变化,用一个基于计算机的工具显然可以节省更多人力。最后还有一个原因就是纸上的图表都是静态的,但是计算机可以给图表添加交互,前面我们也提到了,交互是可视化工具的一个法宝。

  其次计算机上可视化的软件可以说是很多,那为什么我们选则网页来探索和展现可视化的结果。那是因为给大家展现的可视化结果是很重要的,网页是一个获得全球性观众的最快途径。但是必须说一句,D3并不支持一些比较老的浏览器。
  最后就是为什么在众多相当优秀可视化的开源库选择了D3。诸如百度的Echarts,阿里蚂蚁金服的AntV,可以用很短的代码(甚至不用写代码),在很快的时间生成很漂亮的图片。相比之下D3的代码更多和更难以理解,呈现的结果不确定性也很大。
  那是因为D3更加底层,它没有给我们提供一些组件,而是给我们提供了一些数据驱动的函数来帮助我们创造自己的组件。也就说,其他的库就是卖汽车的,我们只要给商家说明我们想要汽车的型号、颜色等,就可以获得一辆崭新的汽车。但是D3是卖零件的,需要按照自己的需求组装这些零件,从而获得汽车。D3更像一个探索可视化原理的库,而不是一个可视化的库。
  同时D3的作者是纽约时报的工程师,而D3 项目的代码托管于 GitHub(一个开发管理平台,目前已经是全世界最流行的代码托管平台,云集了来自世界各地的优秀工程师)。在众多开源库中是一个很流行的库,目前star的数量在所有github开源项目里排11位,并且是这11位中唯一一个数据可视化的开源库。
  流行就意味着D3有很好的生态环境,有很多案例、教程和社区,我们能很容易找到学习资源、问题解答。
  如果你想在短的时间作出优美的可视化,你可以使用Echarts和AntV等,但是如果你希望了解每种可视化方法的原理,那么D3将是一个不错的选择。了解原理有很多好处,比如出了问题我知道问题的根源在哪里,同时可以制造更个性化和新颖的可视化图表。
  下面激动人心的可视化部分就要开始了。我们使用的是最新版本的D3(5.9.2)。
  

确定大概流程

  第一步我们来确定代码的大概执行流程,在之前代码的基础上我们加入一些代码,最后结果如图:

<html>
<head><!-- 一个简单的html --><meta charset="UTF-8"><title>条形图</title><style>/*之前定义的一些样式信息*/</style><!-- 在这个script标签里我们引入D3.js这个库,只有加了这一行的代码我们才能用D3.js中的方法当让你可以D3.js的代码下载下来,然后引用。--><script src="https://d3js.org/d3.v5.min.js"></script><script>function changeColor(){//之前些的代码....}//这个函数是将data对应的条形图现实在网页中function drawBarChart(data){//设置svg//获得svg//设置比例尺//绘制条形//绘制坐标轴//绘制标题//添加交互}</script>
</head>
<body><h1 class='text' onclick="changeColor()">D3与可视化的第一次邂逅</h1><p class="text" id="introduction">星爵的“坑”简直铺面而来,有没有?在队友的战斗力面前,他就像蚂蚁遇见了姚明一样微不足道。</p><!-- 这个是我们的画布,我们将在它上面完成我们的可视化 --><svg></svg><script>//这个是我们要可是化的数据let data = [{key: '一坨屎', value: 1},{key: '废物', value: 10},{key: '尽力了', value: 44},{key: '有帮上忙', value: 32},{key: '很厉害', value: 32},{key: '超神', value: 32},]//在控制台以表格形式输出数据console.table(data)drawBarChart(data);</script>
</body>
</html>

  浏览器渲染引擎渲染一个网页过程大概如下。
  浏览器渲染引擎会从上到下地渲染HMTL文档。<head>标签中会包含一些引用外部文件的代码,从开始运行就会下载这些被引用的外部文件。当遇见<script>标签的时候会暂停解析,将控制权交给JavaScript引擎。如果<script>标签引用了外部脚本,就下载该脚本,否则就直接执行,执行完毕后将控制权交给浏览器渲染引擎继续渲染。当<body>中的代码全部执行完毕、并且整个页面的CSS样式加载完毕后,CSS会重新渲染整个页面的html元素。
  我们来看一下浏览器渲染BarChart.html的过程。浏览器会首先遇见第一个标签<script>,下载D3.js。下载完成后,会让JavaScript引擎执行D3.js里面的代码。执行完毕后会遇见第二个<script>,执行里面的代码,在这里面我们定义了两个函数changColor和drawBarChart。最后当浏览器遇见到第三个<script>标签的时候,会调用在第二个<script>标签里定义的drawBarChart函数,来绘制我们的可视化图形。
  保存为BarChart.html,打开浏览器效果如图:

  按F12打开开发者工具,在Elements里我们可以看见我们目前的网页结构:

  在Console里可以看见我们将要可视化的数据:

  接下来我们的任务就是来完成drawBarChart里面代码的编写。
  

SVG介绍

  可以发现我们在<p>标签后面新增了一个<svg>标签,这就是我们条形图的画布,我们首先来了解一下它。
  SVG,指可缩放矢量图形(Scalable Vector Graphics),是用于描述二维矢量图形的一种图形格式。除了 IE8 之前的版本外,绝大部分浏览器都支持 SVG。
  在网页中我们可以用<svg>标签在网页中嵌入SVG。SVG里面有很多视觉元素可以放在<svg>标签里,包括<rect><circle>< ellipse>< line><text><path>。而我们的条形图就是由这些基本元素构成的。
  下面我们来看一个最基本也是我们马上会用的元素<rect/>

<svg><rect x="100" y="100" height="100" width="100" fill="red"/>
</svg>

  效果如图:

  关于SVG还有几点需要说明:

  • svg标签里面的svg元素必须要设定width和height属性,同时在<svg>标签外面的元素是看不见的。
  • SVG的坐标系和processing相同都是以屏幕左上方为坐标原点,水平方向是x方向,垂直方向是y方向,如下图:
  • SVG还有一个g元素,g是group的意思,可以把一些列元素变成一个组,这样移动g元素的时候,所有的元素都会跟着一起移动。

确定布局

  第二步我们来确定我们画布的布局。
  我们希望我我们的画布如下图,其中紫色区域是我们的svg容器,黄色区域是我们条形图所在的区域。

  所以在函数drawBarChart的“设置svg”区域输入如下代码:

const margin = {top: 80, right: 180, bottom: 80, left: 180}, //确定内边距containerDimensions = {height: 500, width: 960}, //确定整个svg的大小chartDimensions = { //根据svg的大小和内边距确定条形图的大小height: containerDimensions.height - margin.top - margin.bottom, width: containerDimensions.width - margin.left - margin.right}

  

获得并且设置svg

  第三步我们就应该选择我们的画布SVG, 并且修改它的属性了。
  在 D3 中,我们可以用select和selectAll来选择我们想要的DOM对象。这两个函数输入是CSS选择器,返回对应的DOM对象,返回的结果称为选择集。

d3.select() //选择所有指定元素的第一个
d3.selectAll() //是选择指定元素的全部//基于之前提到过的css选择器
const p1 = d3.select('p') //根据标签名选择
const text = d3.select('#text') //根据类名选择
const title = d3.select('.title') //根据id选择

  在 D3 中,我们可以添加通过append函数在当前选择集后面添加元素,并且返回这个元素。

const p2 = p1.append('p') //p1原属后面添加一个p标签,并返回这个元素

  在 D3 中,我们可以在获得DOM对象后,通过attr和style函数来改变它的属性和样式。

p2.attr('class', 'text'); //将p的class设置为text
p2.style('color', 'red'); //设置字体颜色为红色

  在D3中,链式调用是一个特色。因为JavaScript不关心空格符号和换行符,所以上面的代码我们可以写成如下的形式:

const p2 = d3.select('p').append('p').attr('class', 'text').style('color', 'red')

  接下来我们就在drawBarChart函数的“获得svg”区域加入如下的代码:

const svg = d3.select('svg') //获得网页中svg元素.attr('width', containerDimensions.width) //设置svg的高.attr('height', containerDimensions.height) //设置svg的宽.style('background', 'black') //设置背景颜色const group = svg.append('g') //改变后面绘制的坐标原点.attr('transform', `translate(${margin.left}, ${margin.top})`);

  保存BarChart.html,用浏览器执执行,在开发者工具里我们可以看见当前HTML的网页结构如下所示:

  

绑定数据

  一个级别的英雄的对应一个条,每一个条为一个rect元素。第四步,我们需要将每个级别英雄的数据和一个rect元素绑定起来,这样不仅能在网页中增加对应数量的rect元素,还可以根据数据来确定每一个rect的位置和大小。
  D3 中是通过datum和data来将数据绑定到DOM上,然后用join函数来返回当前绑定好的DOM:

datum() //绑定一个数据到选择集上
data() //绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定,相对而言,data() 比较常用。
join() //返回所有绑定绑定好的DOM

  接下来在BarChart.html的drawBarChart中的“绘制条形图”加入以下的代码:

//绘制bar
const bars = group.append('g').selectAll('rect') //选择关联的svg元素.data(data) //需要关联的数据.join('rect') //获得绑定了数据的rect元素

  就这样我们将每个级别英雄的战斗力总和和一个rect元素绑定起来了。那么如何确定已经绑定起来了呢?
  首先保存BarChart.html,并且用浏览器打开,切换到Elements界面。可以发现已经增加了6个rect元素,现在的网页结构如下图:

  接着我们切换到Console界面,在控制台里输入console.log(d3.selectAll('rect')),可以看见选择集的NodeList由6个rect对象组成,如下图:

  而每一个rect对像都有一个__data__属性,就是我们的绑定的数据,如下图:

  

设置比例尺

  虽然目前我们在开发者工具界面可以看见该网页已经多了6个rect元素,但是网页上还看不见任何的矩形。这是因为我们还没设置每一个rect元素的位置和大小,接下来第五步我们需要确定每一个rect元素的大小和位置。
  我们可以把每个rect的宽度设为定值,比100px。我们一共有6个rect,那么就一共是600px。但是如果我们数据有100个呢,那岂不是6000px?所以我们把每个rect的宽度设置成定值是不合理的。高度也是同样的道理。我们希望不管的数据的有多少,条形图都能充满某个固定大小的区域,那么这个时候就需要比例尺了。
  比例尺是D3中很重要的一个概念,D3的作者Mike Bostock对比例尺定义如下:

“Scales are functions that map from an input domain to an output range.”

  比例尺是就是一个函数。在定义它的时候我们需要指定一些参数,比如定义域(domain)和值域(range)。当我们调用它的时候,我们传入一个值,该函数会根据我们定义的参数返回一个缩放后的值。
  因为数据类型有多种(连续的,不连续的),所以D3 提供了多种比例尺。下面介绍最常用也是我们将要用到的两种。
  第一种是线性比比例尺,类似于processing里面的map函数。能将一个连续的区间的数,映射到另一连续的区间。工作原理如图:

  定义方法如下:

const y = d3.scaleLinear().domain([1, 5]).range([0, 100]);y(1) // 0
y(4) // 75
y(5) // 100

  第二种是序数比比例尺,与线性比例不同的是,它的定义域是离散的,映射到另一连续的区间。工作原理如图:

  定义方法如下:

const x = d3.scaleBand().domain([1, 2, 3, 4]).range([0, 100])x(1); // 0
x(2); // 25
x(3); // 50
x(4); // 75

  因为数据的种类(超神,很厉害……)是离散的,而它们对应条的位置是连续的([0, 700],所以我们需要一个序数比例尺。同时数据的值([1, 44])是连续的,对应条的高度也是连续的([0, 340]),所以我们需要一个线性比例尺。在drawBarChart的“设置比例尺”区域加入如下的代码:

const y = d3.scaleLinear().domain([0, d3.max(data, d => d.value)]) .nice()//扩展定义域的两段使其都为整数,比如[1.0021, 2.999] => [1, 3].range([chartDimensions.height, 0])const x = d3.scaleBand().domain(data.map(d => d.key)) .range([0, chartDimensions.width]) .padding(0.1)  //设置条之间的间距,通过改变每一个条的宽度来实现

  这里得加一点说明关于js中map和D3中的d3.max函数的使用:

/*d3.max函数返回data中的最大值,第二个参数是指定用什么来比较*/
const a = [{key:'a', value: 1}, {key:'b', value: 2}, {key:'c', value: 3}]
const maxA = d3.max(a, d => d.value)
maxA // 3/*js中数组的map函数会对原数组的每一个元素执行传入的函数,然后返回一个新的数组*/
const a = [1, 2, 3]
const b = a.map(d => d * 2)
b // [2, 4, 6]

  接下来我们就可以用定义好的比例尺来设置每个rect的位置和大小了,在drawBarChart的“绘制条形”区域加入如下的代码:

bars.attr('x', d => x(d.key)) //设置rect的x坐标.attr('y', d => y(d.value))//设置rect的y坐标.attr('height', d => y(0) - y(d.value))//设置rect的width.attr('width', x.bandwidth())//设置rect的width, 已经被比例尺计算好了,通过x.bandwidth()获得.attr('fill', 'steelblue'); //设置颜色

  在这里要说明一下,上面的attr函数传入的第一个参数是我们想给选择集设置的属性名称,第二个参数是一个箭头函数,该箭头函数的参数d就是绑定的数据,返回的值就是需要设定的值。同时,选择集上的每一DOM都会执行这个函数。所以执行完成后,网页显示和结构如下图:


  

绘制坐标轴

  第七步,我们需要绘制坐标轴。一个坐标轴是有一些列svg元素(line,text,path)构成的。至于如何构成的,我们之后会看见。不过,D3有现成的坐标轴生成器。坐标生成器是一个函数,该函数会在输入的svg元素后面添加一系列元素构成坐标轴:

const axisGenerator = d3.axisBottom(x) //x是一个比例尺,用于控制坐标轴的范围,刻度等属性
const g = d3.select('g')
axisGenerator(g) //在g元素后面添加一个坐标轴

  D3的call函数传入一个函数,该函数会作用到调用call函数的选择集上。在call函数的帮助下,上面的代码可以写成如下更简洁的形式:

g.call(axisGenerator) //与上面等价

  在drawBarChart的“绘制坐标轴”区域加入如下的代码:

//绘制x轴
group.append('g').attr('class', 'axis') //把容纳坐标轴的g元素设置class为axis.attr('transform', `translate(0, ${chartDimensions.height})`)//平移到指定位置.call(d3.axisBottom(x))//绘制y轴
group.append('g').attr('class', 'axis') //把容纳坐标轴的g元素设置class为axis.call(d3.axisLeft(y))

  保存barChart.html,用浏览器打开。我们发现还是看不见坐标轴,那是因为D3的坐标轴默认是黑色的 。我们进入开发者页面,选择Elements,可以发现一个坐标轴的构成如下图:

  于是我们就用css对这些元素的颜色进行更改,在<style>元素里面加入如下代码:

.axis line, path{stroke: white;
}
.axis text{fill: white;
}

  保存barChart.html,用浏览器打开。效果如下:

  

添加标题

  第八步我们来添加标题,这一步很简单。在“绘制标题”区域添加如下代码:

//绘制title
group.append('text') //添加一个text元素.attr('x', x(data[0].key)) //将和第一个条形对齐.attr('font-size', 14) //设置文本字体的粗细.attr('font-weight', 'bold') //设置文本字体的粗细.attr('fill', 'white') //设置文本的颜色.text('复联3战力分布') //设定文本的内容

  

添加交互效果

  到目前为止我们的完整的条形图已经实现了,但是目前还不能交互。我们希望当鼠标移动到任意一个条上的时候,这个条的颜色会从蓝色变成褐色。当我们的鼠标移出任意一个条的时候,这个条的颜色会变回蓝色。
  这个时候就是需要给rect的元素们绑定事件监听器。
  D3绑定的事件监听器的方法很简单,使用on函数。这个函数有两个参数,第一个参数我们想绑定的事件,第二个参数是响应该事件的函数。同样on函数也会对选择集中的每一个元素执行。
  在drawBarChart的的“添加交互”区域输入如下的代码:

bars.on('mouseover', d => { //mousevoer是鼠标移到的元素上触发的事件d3.selectAll('rect').filter(data => data.key == d.key) //筛选出被选中的rect元素并且改变颜色.attr('fill', 'brown')}).on('mouseleave', d => { //mouseleav是鼠标离开的元素上触发的事件d3.selectAll('rect') //离开时将所有rect元素的颜色设置为蓝色.attr('fill', 'steelblue')})

  D3的filter函数用来对选择集进行筛选。它的参数是一个函数,这个函数会对选择集里的没一个元素执行。如果执行结果是true那么保存这个元素,否者删除这个元素。
  保存BarChart.html,用浏览器打开。效果如下:

  

导出可视化结果

  目前我们的写代码部分就完成了,接下来就可以导出可视化的结果了。这里介绍三种方式。
  第一种是导出成位图png。直接用截图软件截图即可,可以使用QQ自带的截图工具。
  第二种是导出成PDF。方法是使用Chrome浏览器,点击顶部菜单栏的文件,选择打印即可。

  最后一种是导出成SVG。在Chrome的开发者工具Elements中,选中你想要导出的svg元素,选择复制。接着新建一个扩展名为svg的文件,比如BarChart.svg。用文本编辑器打开,将内容复制进去,保存。然后就可以用Illustrator等处理矢量图的软件打开了。

  

拓展

  我们的复联3战力分布图已经制作完成了,你只要把data按照我们给定的形式替换成你自己的数据,这个条形图就是你自己的条形图了。
  我们上面介绍的只是最基本的条形图,条形图有很多兄弟姐妹。大家请看下面的条形图大家庭,可以想想可以如何用D3来实现它们,它们又分别在什么时候使用。
  关于D3想了解更多的同学可以去D3的官网。

  相信大家看了这么多,已经很累啦,接下来给大家看一个有趣的视频。大家可以分析一下视频中的可视化为什么好?你获得了哪些有趣的事实。

  

小结

  我们大概了解了一下数据可视化,也亲手实现了一个简单的条形图,最重要的知道了星爵在《复仇者联盟3》中有多么的坑。
  不过话又说回来,“三十年河东,三十年河西,莫欺少年穷”,《复联4》中的星爵也许就不坑了呢?所以,感兴趣的同学可以走进电影院看看这次超级英雄们是如何“超越无限,逆转未来的”,毕竟这可是漫威10年的收官之作!

  

参考资料

  • The Visual Display of Quantitative Information - Edward Tufte
  • Visualization Analysis & Design
  • Beautiful Visualization - Oreilly
  • Getting Started with D3
  • Interactive Data Visualization for the Web
  • 廖雪峰老师JavaScript教程
  • 阮一峰老师ES6教程
  • 吕之华先生的D3教程
  • 吴军先生的《智能时代》

D3基础 | 条形图相关推荐

  1. d3 制作条形图_停止制作常见的坏条形图的5个简单技巧

    d3 制作条形图 Bar charts were probably the first type of chart you were ever introduced to in first grade ...

  2. d3 制作条形图_停止错误制作条形图的5个技巧

    d3 制作条形图 Bar charts were probably the first type of chart you were ever introduced to in first grade ...

  3. 在vue中使用antV-G2展示基础条形图

    介绍 在vue中使用antV-G2展示基础条形图 G2 是一套基于图形语法理论的可视化底层引擎,以数据驱动,提供图形语法与交互语法,具有高度的易用性和扩展性.使用 G2,你可以无需关注图表各种繁琐的实 ...

  4. Vue+D3 绘制条形图和力导向图

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Vue+D3 绘制条形图和力导向图 准备:D3代码 1.条形图 2.力导向图 本篇blog在于把已经编写好的D3代码从一般HTML文件 ...

  5. 如何创建多个条形图_学习使用D3创建条形图-初学者教程

    如何创建多个条形图 D3.js is the most popular JavaScript library for creating visual representations of your d ...

  6. D3 - 动态条形图制作

    数据来自csv文件. 绘制效果图: 数据集解释:数据信息为美国六个主要城市每个月的光照时间变化. 代码详细解释: let Color = new Array();// 随机生成每个城市的代表颜色for ...

  7. Dimple.js基础

    dimple是建立在D3基础上的库,通过他我们可以操控抽象级的图表. 启动本地HTTP服务 python -m http.server 在命令行窗口下输入命令,默认是8000端口. 要想停止本地服务器 ...

  8. matlab 条形图横坐标,Matlab条形图bar横坐标间距设置

    1. 默认横坐标 数据 X=[x1, x2, x3, x4, x5, x6]  %一行六列 bar(X);   %绘制基础条形图 2. 修改横坐标标签 #考虑横坐标标签文本较长且字体较大的情况 bar ...

  9. Matlab条形图bar横坐标间距设置

    1. 默认横坐标 数据 X=[x1, x2, x3, x4, x5, x6]  %一行六列 bar(X);   %绘制基础条形图 2. 修改横坐标标签 #考虑横坐标标签文本较长且字体较大的情况 bar ...

  10. Matlab条形图bar误差棒绘制errorbar

    基础条形图 set(gca, 'position', [.13 .17 .80 .74] );   % 设置绘图框大小 [x-start, y-start, width, height] set(gc ...

最新文章

  1. buffer busy waits等待事件的原因:hot block [转]
  2. 百行代码打造一个DI容器(支持瞬时生命周期、单利生命周期、构造函数自动注入、属性自动注入、字段自动注入)...
  3. 网络营销专员浅析网络营销优化对企业来说意味着什么?
  4. 2009计算机统考真题,2009年计算机统考真题(完整版).PDF
  5. 强烈推荐!分享一个持续连载的《特征工程小锦囊》项目,代码已开源!
  6. keybd_event跟SendMessage,PostMessage模拟键盘消息的区别 z
  7. Java高并发入门-线程初步(二)
  8. 详述一次大量删除导致MySQL慢查的分析
  9. 关注 Web Client Software Factory [Weekly Drop 08]
  10. linux+redhat+5下载地址,Redhat_Linux5下载地址集锦最终.docx
  11. Oracle安装教程
  12. 12款高质量的免费 HTML 网页模板下载
  13. 计算机英语期末论文格式,计算机英文论文大纲格式 计算机英文论文大纲如何写...
  14. Android集成LeanCloud用户反馈SDK要注意点
  15. 使用NAudio音频文件剪切指定片段
  16. css 宽度为百分比, 高度和宽度相等的设置
  17. 51单片机入门 - 并行I/O口扩展实例(74LS244/74LS373/4071)
  18. 用js获取浏览器当前版本
  19. PTA 7-81 电费
  20. 【我的技术我做主】致那些奋斗在测试界挨踢人们--聊聊技术、发展

热门文章

  1. window.open 服务器运行失败,win10 openssh服务器安装失败的最佳解决方法
  2. Ant实现自动打包部署
  3. STK开发包用法探讨
  4. Oracle 只读表空间 说明
  5. winedit使用教程_latex及winedit入门指导教程.pdf
  6. 我用Python爬了4400条淘宝商品数据,竟发现了这些“潜规则”
  7. 计算机教室最适合的植物,适合放电脑前的植物 电脑前放什么植物比较好
  8. GhostXP_SP3雨林木风纯净版Y7.0(09年12月更新版) 【雪豹】
  9. java将uuid转换成大写_java实现无符号数转换、字符串补齐、md5、uuid、随机数示例...
  10. Golang 信息采集