转自:https://www.cnblogs.com/kidsitcn/p/7182274.html

比例尺函数是这样的javascript函数:

  • 接收通常是数字,日期,类别等data输入并且:
  • 返回一个代表可视化元素的值,比如坐标,颜色,长度或者半径等

比例尺通常用于变换(或者说映射)抽象的数据值到可视量化变量(比如位置,长度,颜色等)

比如,假设我们有以下数组数据:

[ 0, 2, 3, 5, 7.5, 9, 10 ]

我们可以这样创建一个比例尺函数:

var myScale = d3.scaleLinear()
.domain([0, 10])
.range([0, 600]);

d3将创建一个myScale函数用于接收[0,10]之间的数据输入(domain)映射为[0,600]像素的位置数据(range)

我们可以使用myScale函数来计算对应数据的positions数据:

myScale(0);   // returns 0
myScale(2); // returns 120
myScale(3); // returns 180
...
myScale(10); // returns

如上面所说,比例尺主要用于将抽象数据映射为可视的量化元素,比如位置,长度,半径,颜色等。比如,他们可以这样应用

  • 将抽象数据映射为0到500的长度值以便在bar chart中使用
  • 将抽象数据映射为0到200之间的位置数据值以便作为line charts中点的坐标来使用
  • 将百分比变化数据(+4%,+10%,-5%等)映射为颜色的对应变化(比如使用红色表示为正值,正的越多越红,负值为绿色,负的越多绿色饱和度越高)
  • 将日期数据映射为x轴上的位置

Constructing scales

这部分我们集中使用线性比例尺linear scale作为例子探讨scale的相关知识,在后面再探讨其他类型的比例尺

var myScale = d3.scaleLinear();

注意:v4和v3的声明方式是不同的 d3.scaleLinear() in v4 and d3.scale.linear() in

myScale
.domain([0, 100])
.range([0, 800]);

通过上面的代码,myScale就成为有特定意义的比例尺函数了。现在myScale可以接收任何在0,100之间的domain,而映射到0到800的range里面。我们可以像下面一样来调用这个比例尺函数:

myScale(0);    // returns 0
myScale(50); // returns 400
myScale(100); // returns 800

D3 scale types

D3大约有12种不同的比例尺类型(scaleLinear, scalePow, scaleQuantise, scaleOrdinal etc.) ,而总体来说我们可以分为3类

下面我们一个一个地来仔细学习一下

Scales with continuous input and continuous output(连续性输入连续性输出)

scaleLinear

线性比例尺可能是应用最为广泛的比例尺类型了,因为他们最适合将数据转化为位置和长度。因此往往也以线性比例尺为例去讲解和学习比例次的知识

他们使用一个线性函数(y=m*x+b)来表达(domain)和(range)之间的数学函数关系

var linearScale = d3.scaleLinear()
.domain([0, 10])
.range([0, 600]); linearScale(0); // returns 0
linearScale(5); // returns 300
linearScale(10); // returns 600

典型地,他们被用于将抽象数据转换为位置,长度等可视元素。因此当我们创bar chart,line chart,或者其他很多图标类型时,我们可以使用它。

除了位置长度作为range,也可以使用颜色值哦(实际上颜色也可以作为连续性数据的):

var linearScale = d3.scaleLinear()
.domain([0, 10])
.range(['yellow', 'red']); linearScale(0); // returns "rgb(255, 255, 0)"
linearScale(5); // returns "rgb(255, 128, 0)"
linearScale(10); // returns "rgb(255, 0, 0)"

这个特性常常被用于等值线图(choropleth),当然我们也可以使用scaleQuantize,scaleQuantile和scaleThrshold.

scalePow

scalePow这个比例次使用y = m * x^k + b这个数学函数来表达domain和range之间的数学函数关系。指数k使用.exponent()来设定:

var powerScale = d3.scalePow() .exponent(0.5) .domain([0, 100]) .range([0, 30]);
powerScale(0); // returns 0
powerScale(50); // returns 21.21...
powerScale(100); // returns 30

scaleSqrt

scaleSqrt 比例次是一种scalePow的特殊形式(k=0.5)通常用于通过面积来表征圆(而不用半径)(当使用圆的大小来表达数据值的大小时,通常最佳实践是使用和数据等比例的面积而非半径来表达)

var sqrtScale = d3.scaleSqrt()
.domain([0, 100])
.range([0, 30]); sqrtScale(0); // returns 0
sqrtScale(50); // returns 21.21...
sqrtScale(100); // returns 30

我们可以看到这个例子和上面的例子输出是一样的。

scaleLog

Log scales 使用数学对数函数(y = m * log(x) + b)来映射domain和range.如果数据之间有指数关系的话,这个log比例尺最适合

var logScale = d3.scaleLog()
.domain([10, 100000])
.range([0, 600]); logScale(10); // returns 0
logScale(100); // returns 150
logScale(1000); // returns 300
logScale(100000); // returns 600

scaleTime

scaleTime和scaleLinear是类似的,唯一的区别是domain用于代表date的数组。(通常对于时间序列非常有用)

timeScale = d3.scaleTime() .domain([new Date(2016, 0, 1), new Date(2017, 0, 1)]) .range([0, 700]);
timeScale(new Date(2016, 0, 1)); // returns 0
timeScale(new Date(2016, 6, 1)); // returns 348.00...
timeScale(new Date(2017, 0, 1)); // returns 700

scaleSequential

scaleSequential用于将连续性的数据映射为由预定义或者定制的插值函数决定的range.(一个插值函数是一个接受0到1之间的数值而输出一个在两个数字,两个颜色值或者两个字符串之间的插值的函数)

D3提供了很多预定义的插值函数,其中包含着很多颜色相关的插值函数。例如,我们可以使用d3.interpolateRainbow来创建著名的彩虹色系图:

var sequentialScale = d3.scaleSequential()
.domain([0, 100])
.interpolator(d3.interpolateRainbow); sequentialScale(0); // returns 'rgb(110, 64, 170)'
sequentialScale(50); // returns 'rgb(175, 240, 91)'
sequentialScale(100); // returns 'rgb(110, 64, 170)'

需要注意的是插值函数决定了output range,因此你不需要对这个sequential scale来指定range

下面的列子展示由d3提供的其他颜色插值范围函数:

var linearScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 600]); var sequentialScale = d3.scaleSequential()
.domain([0, 100]); var interpolators = [
'interpolateViridis',
'interpolateInferno',
'interpolateMagma',
'interpolatePlasma',
'interpolateWarm',
'interpolateCool',
'interpolateRainbow',
'interpolateCubehelixDefault'
]; var myData = d3.range(0, 100, 2); function dots(d) {
sequentialScale
.interpolator(d3[d]); d3.select(this)
.append('text')
.attr('y', -10)
.text(d); d3.select(this)
.selectAll('rect')
.data(myData)
.enter()
.append('rect')
.attr('x', function(d) {
return linearScale(d);
})
.attr('width', 11)
.attr('height', 30)
.style('fill', function(d) {
return sequentialScale(d);
});
} d3.select('#wrapper')
.selectAll('g.interpolator')
.data(interpolators)
.enter()
.append('g')
.classed('interpolator', true)
.attr('transform', function(d, i) {
return 'translate(0, ' + (i * 70) + ')';
})
.each(dots);

除了d3定义的这些颜色插值范围函数,也有一个 d3-scale-chromatic plugin, 提供著名的 ColorBrewer colour schemes.

Clamping

默认情况下 scaleLinearscalePowscaleSqrtscaleLogscaleTime and scaleSequential 允许输入值在domain范围之外比如:

var linearScale = d3.scaleLinear()

  .domain([0, 10])
.range([0, 100]); linearScale(20); // returns 200
linearScale(-10); // returns -100

在这种情况下scale函数就使用外推算法来返回domain范围之外的输入值对应的返回值。

如果我们希望比例尺函数严格限制输入值必须在domain规定的范围内,我们则可以使用.clamp()调用

linearScale.clamp(true);

linearScale(20);  // returns 100
linearScale(-10); // returns 0

我们也可以随时通过clamp(false)来关闭这个功能

Nice

如果domain是由实际数据自动算出来的,比如使用d3.extent,d3.min/max来定义,那么起始和结束数据可能并不是整数。这本身并不是什么问题,但是如果使用这个比例尺函数来定义一个坐标轴,则显得很不整洁

var data = [0.243, 0.584, 0.987, 0.153, 0.433];
var extent = d3.extent(data); var linearScale = d3.scaleLinear()
.domain(extent)
.range([0, 100]);

我们通过使用.nice()函数,那么就将domain做了nice处理:

linearScale.nice();

需要注意的是.nice()函数必须在domain更新后每次都必须重新调用!

Multiple segments

The domain and range of scaleLinearscalePowscaleSqrtscaleLog and scaleTime usually consists of two values, but if we provide 3 or more values the scale function is subdivided into multiple segments:

通常scaleLinear,scalePow,scaleSqrt,scaleLog和scaleTime比例尺的domain和range都只包含两个数值:起始和结束值来定义,但是如果我们提供3个甚至更多的值,那么比例尺函数就将被划分为几个段segments:

var linearScale = d3.scaleLinear()
.domain([-10, 0, 10])
.range(['red', '#ddd', 'blue']); linearScale(-10); // returns "rgb(255, 0, 0)"
linearScale(0); // returns "rgb(221, 221, 221)"
linearScale(5); // returns "rgb(128, 128, 255)"

看看一个例子效果:

var xScale = d3.scaleLinear()
.domain([-10, 10])
.range([0, 600]); var linearScale = d3.scaleLinear()
.domain([-10, 0, 10])
.range(['red', '#ddd', 'blue']); var myData = [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10]; d3.select('#wrapper')
.selectAll('circle')
.data(myData)
.enter()
.append('circle')
.attr('r', 10)
.attr('cx', function(d) {
return xScale(d);
})
.style('fill', function(d) {
return linearScale(d);
});

典型地,多segment的比例尺通常用于区分正负值(正如上面例子所示)。只要domain和range的段数是相同的,我们可以使用任意多segments的比例尺.

Inversion

.invert() 方法接受一个range输出来反算对应的input domain

var linearScale = d3.scaleLinear()
.domain([0, 10])
.range([0, 100]); linearScale.invert(50); // returns 5
linearScale.invert(100); // returns 10

A common use case is when we want to convert a user’s click along an axis into a domain value:

这个方法的典型使用场景是我们将用户沿着某坐标轴点击坐标反转为domain值:

var width = 600;

var linearScale = d3.scaleLinear()
.domain([-50, 50])
.range([0, width])
.nice(); var clickArea = d3.select('.click-area').node(); function doClick() {
var pos = d3.mouse(clickArea);
var xPos = pos[0];
var value = linearScale.invert(xPos);
d3.select('.info')
.text('You clicked ' + value.toFixed(2));
} // Construct axis
var axis = d3.axisBottom(linearScale);
d3.select('.axis')
.call(axis); // Update click area size
d3.select('.click-area')
.attr('width', width)
.attr('height', 40)
.on('click', doClick);

Scales with continuous input and discrete output

scaleQuantize

scaleQuantize 接受连续性的range输入而输出由range定义的离散输出

var quantizeScale = d3.scaleQuantize()
.domain([0, 100])
.range(['lightblue', 'orange', 'lightgreen', 'pink']); quantizeScale(10); // returns 'lightblue'
quantizeScale(30); // returns 'orange'
quantizeScale(90); // returns 'pink'
Each range value is mapped to an equal sized chunk in the domain so in the example above:
每一个range值都被映射为一个domain的等分量值区间
  • 0 ≤ u < 25 is mapped to ‘lightblue’
  • 25 ≤ u < 50 is mapped to ‘orange’
  • 50 ≤ u < 75 is mapped to ‘lightgreen’
  • 75 ≤ u < 100 is mapped to ‘pink’

u 是输入domain值

注意由于我们使用了.clamp指示,因此quantizeScale(-10)返回'lightblue',而quantizeScale(110)返回'pink'

scaleQuantile

scaleQuantile 将输入的连续性domain值映射为离散的值。domain是由数组来定义:

var myData = [0, 5, 7, 10, 20, 30, 35, 40, 60, 62, 65, 70, 80, 90, 100];

var quantileScale = d3.scaleQuantile()
.domain(myData)
.range(['lightblue', 'orange', 'lightgreen']); quantileScale(0); // returns 'lightblue'
quantileScale(20); // returns 'lightblue'
quantileScale(30); // returns 'orange'
quantileScale(65); // returns 'lightgreen'

var myData = [0, 5, 7, 10, 20, 30, 35, 40, 60, 62, 65, 70, 80, 90, 100];

var linearScale = d3.scaleLinear()
.domain([0, 100])
.range([0, 600]); var quantileScale = d3.scaleQuantile()
.domain(myData)
.range(['lightblue', 'orange', 'lightgreen']); d3.select('#wrapper')
.selectAll('circle')
.data(myData)
.enter()
.append('circle')
.attr('r', 3)
.attr('cx', function(d) {
return linearScale(d);
})
.style('fill', function(d) {
return quantileScale(d);
});

排好序的domain数组被均分为n个子范围,这里n是range数值的个数

这样在上面的例子中domain数组就被均分为3个groups:

  • the first 5 values are mapped to ‘lightblue’
  • the next 5 values to ‘orange’ and
  • the last 5 values to ‘lightgreen’.

具体的domain均分点可以通过.quantiles()来访问

quantileScale.quantiles();  // returns [26.66..., 63]

如果range包含4个值,那么quantileScale将这样计算quantiles: 最低25%的数据被映射为range[0], 下一个25%则映射为range[1],以此类推。

scaleThreshold

scaleThreshold 映射连续的输入domain为由range来定义的离散值. 如果range值有n个,则将会有n-1个切分点

下面的例子我们在050和100处切分

  • u < 0 is mapped to ‘#ccc’
  • 0 ≤ u < 50 to ‘lightblue’
  • 50 ≤ u < 100 to ‘orange’
  • u ≥ 100 to ‘#ccc’

这里u 是input value.

var thresholdScale = d3.scaleThreshold()
.domain([0, 50, 100])
.range(['#ccc', 'lightblue', 'orange', '#ccc']); thresholdScale(-10); // returns '#ccc'
thresholdScale(20); // returns 'lightblue'
thresholdScale(70); // returns 'orange'
thresholdScale(110); // returns '#ccc'

详细代码如下:

var linearScale = d3.scaleLinear()
.domain([-10, 110])
.range([0, 600]); var thresholdScale = d3.scaleThreshold()
.domain([0, 50, 100])
.range(['#ccc', 'lightblue', 'orange', '#ccc']); var myData = d3.range(-10, 110, 2); d3.select('#wrapper')
.selectAll('rect')
.data(myData)
.enter()
.append('rect')
.attr('x', function(d) {
return linearScale(d);
})
.attr('width', 9)
.attr('height', 30)
.style('fill', function(d) {
return thresholdScale(d);
});

Scales with discrete input and discrete output

scaleOrdinal

scaleOrdinal 将离散的domain values array映射为离散的range values array. domain input array指定可能的输入value,而range array则定义对应的可能的输出value.如果range array比domain array要短,则range array会重复循环

var myData = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

var ordinalScale = d3.scaleOrdinal()
.domain(myData)
.range(['black', '#ccc', '#ccc']); ordinalScale('Jan'); // returns 'black';
ordinalScale('Feb'); // returns '#ccc';
ordinalScale('Mar'); // returns '#ccc';
ordinalScale('Apr'); // returns 'black';

完整代码如下:

var myData = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

var linearScale = d3.scaleLinear()
.domain([0, 11])
.range([0, 600]); var ordinalScale = d3.scaleOrdinal()
.domain(myData)
.range(['black', '#ccc', '#ccc']); d3.select('#wrapper')
.selectAll('text')
.data(myData)
.enter()
.append('text')
.attr('x', function(d, i) {
return linearScale(i);
})
.text(function(d) {
return d;
})
.style('fill', function(d) {
return ordinalScale(d);
});

By default if a value that’s not in the domain is used as input, the scale will implicitly add the value to the domain:

默认情况下如果输入值不在domain范围内,scale会隐含地添加这个值到domain中去。

ordinalScale('Monday');  // returns 'black';

如果这不是我们想要的行为,我们可以使用.unknown()函数来设定一个unknown values

ordinalScale.unknown('Not a month');
ordinalScale('Tuesday'); // returns 'Not a month'

D3也提供一些预定义好的color scheme

var ordinalScale = d3.scaleOrdinal()
.domain(myData)
.range(d3.schemePaired);
var myData = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

var linearScale = d3.scaleLinear()
.domain([0, 11])
.range([0, 600]); var ordinalScale = d3.scaleOrdinal()
.domain(myData)
.range(d3.schemePaired); d3.select('#wrapper')
.selectAll('text')
.data(myData)
.enter()
.append('text')
.attr('x', function(d, i) {
return linearScale(i);
})
.text(function(d) {
return d;
})
.style('fill', function(d) {
return ordinalScale(d);
});

(Note that the Brewer colour schemes are defined within a separate file d3-scale-chromatic.js.)

scaleBand

当创建一个bar chart时,scaleBand可以帮助我们来决定bar的几何形状,并且已经考虑好了各个bar之间的padding值。

输入的domain通过一个数值数组来指定(每个值都对应一个band)并且range通过bands的最小和最大范围来定义(也就是bar chart的整个宽度)

scaleBand会将range划分为n个bands(n是domain数组的数值个数)并且在考虑padding的情况下计算出每个band的位置和宽度.

var bandScale = d3.scaleBand()
.domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
.range([0, 200]); bandScale('Mon'); // returns 0
bandScale('Tue'); // returns 40
bandScale('Fri'); // returns 160

每个band的宽度可以使用.bandWidth()来访问。

bandScale.bandwidth();  // returns 40

有两种padding可以被配置:

  • paddingInner which specifies (as a percentage of the band width) the amount of padding between each band
  • paddingOuter which specifies (as a percentage of the band width) the amount of padding before the first band and after the last band

我们在上面的例子中添加一点inner padding

bandScale.paddingInner(0.05);

bandScale.bandWidth();  // returns 38.38...
bandScale('Mon'); // returns 0
bandScale('Tue'); // returns 40.40...

Putting this all together we can create this bar chart:

上面加起来我们可以得到下面的图表:

var myData = [
{day : 'Mon', value: 10},
{day : 'Tue', value: 40},
{day : 'Wed', value: 30},
{day : 'Thu', value: 60},
{day : 'Fri', value: 30}
]; var bandScale = d3.scaleBand()
.domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
.range([0, 200])
.paddingInner(0.05); d3.select('#wrapper')
.selectAll('rect')
.data(myData)
.enter()
.append('rect')
.attr('y', function(d) {
return bandScale(d.day);
})
.attr('height', bandScale.bandwidth())
.attr('width', function(d) {
return d.value;
});

scalePoint

scalePoint 将离散的输入数值映射为在range内等距的点:

var pointScale = d3.scalePoint()
.domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
.range([0, 500]); pointScale('Mon'); // returns 0
pointScale('Tue'); // returns 125
pointScale('Fri'); // returns 500

完整代碼:

var myData = [
{day : 'Mon', value: 10},
{day : 'Tue', value: 40},
{day : 'Wed', value: 30},
{day : 'Thu', value: 60},
{day : 'Fri', value: 30}
]; var pointScale = d3.scalePoint()
.domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
.range([0, 600]); d3.select('#wrapper')
.selectAll('circle')
.data(myData)
.enter()
.append('circle')
.attr('cx', function(d) {
return pointScale(d.day);
})
.attr('r', 4);

点之间的距离可以通过.step()来访问:

pointScale.step();  // returns 125

outside padding可以通过和padding to point spacing的比例来指定。比如,如果希望设定outside padding为point spacing的1/4,那么可以这样设置:

pointScale.padding(0.25);

pointScale('Mon');  // returns 27.77...
pointScale.step(); // returns 111.11...

参考阅读

ColorBrewer schemes for D3

Mike Bostock on d3-scale

积小流以汇江海,细微做起

d3js scales深入理解的更多相关文章

  1. d3js layout 深入理解

    D3 layouts help you create more advanced visualisations such as treemaps: D3 layouts帮助您创造更加高级复杂的可视化图 ...

  2. d3js shape深入理解

    本文将视图了解d3js提供的帮助我们创建矢量图形的helper函数,比如下面的: http://d3indepth.com/shapes/ lines curves pie chart segment ...

  3. d3js selections深入理解

    D3 selections选择DOM元素以便可以对这些dom元素做相应的操作,比如:更改其style,修改其属性,执行data-join操作,或者插入.删除相应elements 比如,如果给定5个ci ...

  4. d3js data joins深入理解

    Data joins 给定一个数据数组和一个 D3 selection  我们就可以attach或者说是'join'数组中的每个数据到selection中的每个元素上. 这将使得我们的数据和可视化元素 ...

  5. Angular指令渗透式理解

    通过一段时间对angular指令的使用,理解了angular指令的意义,下面逐一介绍一下. ng-app:定义一个angualr模块,表示angular作用的范围,如下代码: ng-app在html标 ...

  6. d3可视化实战02:理解d3数据驱动的真正含义

    前文中已经提到,SVG从诞生之初起就可以非常方便地使用javascript脚本语言来进行其DOM对象的控制.当然,控制的方法有很多,有直接控制SVG对象的方法,例如使用原生js:有帮你封装一下图形接口 ...

  7. D3js初探及数据可视化案例设计实战

    摘要:本文以本人目前所做项目为基础,从设计的角度探讨数据可视化的设计的方法.过程和结果,起抛砖引玉之效.在技术方案上,我们采用通用web架构和d3js作为主要技术手段:考虑到项目需求,这里所做的可视化 ...

  8. d3js可视化策略

    d3js是数据驱动图形的思路.基本可以这么理解,有什么样的图形,后面基本就有类似结构的数据.大概思路步骤如下: 一.适配数据格式 这一步主要是为第二部服务,第一步的结果作为第二部的入参. 比如,画层级 ...

  9. 你可以这么理解五种I/O模型

    因为项目需要,接触和使用了Netty,Netty是高性能NIO通信框架,在业界拥有很好的口碑,但知其然不知其所以然. 所以本系列文章将从基础开始学起,深入细致的学习NIO.本文主要是介绍五种I/O模型 ...

随机推荐

  1. ArcGIS API for JavaScript 入门教程[4] 代码的骨架

    [回顾与本篇预览] 上篇简单介绍了JsAPI中的数据与视图,并告诉大家这两部分有什么用.如何有机连接在一起. 这一篇快速介绍一下前端代码的骨架.当然,假定你已经熟悉HTML5.CSS3和JavaScr ...

  2. SQLsever存储过程分页查询

    使用存储过程实现分页查询,SQL语句如下: USE [DatebaseName] --数据库名 GO /****** Object: StoredProcedure [dbo].[Pagination ...

  3. 《SQL CookBook 》笔记-第二章-查询结果排序

    目录 第二章 查询结果排序 2.1 以指定顺序返回查询结果 2.2 依据子串排序 2.3 排序时对 Null 值的处理 2.4 依据条件逻辑动态调整排序项 第二章 shanzm 第二章 查询结果排序 ...

  4. 网络I/O 工作机制

    数据从一台主机发送到网络中的另一台主机需要经过很多步骤,先得有相互沟通的意向,然后得有物理渠道(物理链路),其次双方还得有语言能够交流,且步调要一致. TCP状态转化 如图,是TCP/IP 的握手过程 ...

  5. c语言总练习题

    !4,42 ?45 1 Description 键盘输入一个双精度数据,乘以2以后输出 Input 输入一个double型数据 Output 输出它的两倍数,结果保留8位小数 Sample Input ...

  6. Taurus.MVC 2.3 开源发布:增强属性Require验证功能,自带WebAPI文档生成功能

    背景: 上周,把 Taurus.MVC 在 Linux (CentOS7) 上部署任务完成后. 也不知怎么的,忽然就想给框架集成一下WebAPI文档功能,所以就动手了. 以为一天能搞完,结果,好几天过 ...

  7. .NET Core 必备安全措施

    .NET Core大大简化了.NET应用程序的开发.它的自动配置和启动依赖大大减少了开始一个应用所需的代码和配置量,本文目的是介绍如何创建更安全的.NET Core应用程序. 1.在生产中使用HTTP ...

  8. Java实现发送手机验证码功能(短信+语音)

    利用第三方平台可以实现发送手机短信验证码和语音验证码的功能,本文使用框架是struts2+spring+hibernate,现就action层给出核心代码功能. public class Verify ...

  9. Javascript高级编程学习笔记(98)—— WebGL(4) WebGL上下文(2)

    错误 Javascript与WebGL之间的一个最大区别在于,WebGL的操作一般不会抛出错误 如果希望获取WebGL的错误信息,那么就需要手动调用  gl.getError() 方法 该方法会返回以 ...

  10. 4.2WebHost配置「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. WebHost配置 覆盖配置文件和修改启动URL 覆盖配置文件和修改启动URL是经常使用的地方,覆盖配置文件可以自 ...