cesium-examples/map/2d/build/arcgis-map-temperature.js

407 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Temperature = factory());
}(this, (function () { 'use strict';
var tool = {
merge: function merge(settings, defaults) {
Object.keys(settings).forEach(function (key) {
defaults[key] = settings[key];
});
},
//计算两点间距离
getDistance: function getDistance(p1, p2) {
return Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));
},
//判断点是否在线段上
containStroke: function containStroke(x0, y0, x1, y1, lineWidth, x, y) {
if (lineWidth === 0) {
return false;
}
var _l = lineWidth;
var _a = 0;
var _b = x0;
// Quick reject
if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) {
return false;
}
if (x0 !== x1) {
_a = (y0 - y1) / (x0 - x1);
_b = (x0 * y1 - x1 * y0) / (x0 - x1);
} else {
return Math.abs(x - x0) <= _l / 2;
}
var tmp = _a * x - y + _b;
var _s = tmp * tmp / (_a * _a + 1);
return _s <= _l / 2 * _l / 2;
},
//是否在矩形内
isPointInRect: function isPointInRect(point, bound) {
var wn = bound.wn; //西北
var es = bound.es; //东南
return point.x >= wn.x && point.x <= es.x && point.y >= wn.y && point.y <= es.y;
},
//是否在圆内
isPointInCircle: function isPointInCircle(point, center, radius) {
var dis = this.getDistanceNew(point, center);
return dis <= radius;
},
//两点间距离
getDistanceNew: function getDistanceNew(point1, point2) {
return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
}
};
var resolutionScale = function (context) {
var devicePixelRatio = window.devicePixelRatio || 1;
context.canvas.width = context.canvas.width * devicePixelRatio;
context.canvas.height = context.canvas.height * devicePixelRatio;
context.canvas.style.width = context.canvas.width / devicePixelRatio + 'px';
context.canvas.style.height = context.canvas.height / devicePixelRatio + 'px';
context.scale(devicePixelRatio, devicePixelRatio);
};
/**
* @author https://github.com/chengquan223
* @Date 2019-3-29
* 创建一个canvaswidthheight为地图的大小填充颜色并获取到imageData
* for循环width、heighti+=2;
* 判断point(x,y)是否在地图范围内,矩形或边界地图都适用
* fasle不在地图范围内将color设置为透明色rgba(0,0,0,0)且point(x,y) = point(x+1,y) = point(x,y+1) = point(x+1,y+1)
* true在地图范围内将point(x,y)转换成经纬度坐标point(lon,lat)
* 由point(lon,lat)与grid网格关系换算得出point(lon,lat)相对于grid的网格点g(x,y)
* g00 g10
* g(x,y)
* g10 g11
* 双线性插值计算出点g(x,y)的value
* 将value作为参数传入颜色带根据比例换算得出rgb
* 最终将rba回填至canvas图层的imageData
*/
var Temperature = function Temperature(map, userOptions) {
this.map = map;
this.lines = [];
this.pixelList = [];
//默认参数
var options = {
//线条宽度
lineWidth: 1
};
this.init(userOptions, options);
//全局变量
this.baseCtx = this.options.baseCanvas.getContext("2d");
this.width = map.width;
this.height = map.height;
this.clickEvent = this.clickEvent.bind(this);
this.bindEvent();
};
Temperature.prototype.init = function (settings, defaults) {
//合并参数
tool.merge(settings, defaults);
this.options = defaults;
this.legend = new Legend();
};
Temperature.prototype.createMask = function () {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d'),
width = this.width,
height = this.height;
canvas.width = width;
canvas.height = height;
context.fillStyle = "rgba(255, 0, 0, 1)";
context.fillRect(0, 0, width, height);
var imageData = context.getImageData(0, 0, width, height);
var data = imageData.data;
var mask = this.mask = {
imageData: imageData,
isVisible: function isVisible(x, y) {
var i = (y * width + x) * 4;
return data[i + 3] > 0;
},
set: function set(x, y, rgba) {
var i = (y * width + x) * 4;
data[i] = rgba[0];
data[i + 1] = rgba[1];
data[i + 2] = rgba[2];
data[i + 3] = rgba[3];
return this;
}
};
return mask;
};
Temperature.prototype.createView = function () {
var options = this.options,
extent = options.extent,
Point = options.Point,
start = map.toScreen(new Point({
x: extent[0],
y: extent[1],
spatialReference: {
wkid: 4326
}
})),
end = map.toScreen(new Point({
x: extent[2],
y: extent[3],
spatialReference: {
wkid: 4326
}
}));
return {
x: start.x,
y: start.y,
xMax: end.x,
yMax: end.y
};
};
Temperature.prototype.interpolateField = function () {
var self = this,
map = this.map,
xMax = this.width,
yMax = this.height,
opts = this.options,
view = this.createView(),
extent = opts.extent,
grid = opts.data,
legend = this.legend,
x = 0,
ScreenPoint = opts.ScreenPoint,
webMercatorUtils = opts.webMercatorUtils;
var mask = this.mask || this.createMask();
function interpolateColumn(x) {
for (var y = 0; y < yMax; y += 2) {
var color = [0, 0, 0, 0];
if (mask.isVisible(x, y)) {
//判断该点是否在矩形区域范围内true则插值计算出value得到rgba并更新imageDatafalse则设置透明
if (x >= view.x && x <= view.xMax && y >= view.y && y <= view.yMax) {
var coord = map.toMap(new ScreenPoint(x, y)),
lonlat = webMercatorUtils.xyToLngLat(coord.x, coord.y),
value = interpolate(lonlat[0], lonlat[1]),
rgb = legend.getColor(value).rgb;
color = [rgb[0], rgb[1], rgb[2], 150];
}
mask.set(x, y, color).set(x + 1, y, color).set(x, y + 1, color).set(x + 1, y + 1, color);
} else {
console.error(x, y);
}
}
}
function interpolate(lon, lat) {
var i = floorMod(Math.abs(lon - extent[0]), 360) / opts.dx;
var j = (extent[1] - lat) / opts.dy;
var fi = Math.floor(i),
ci = fi + 1,
fj = Math.floor(j),
cj = fj + 1;
var row;
if (row = grid[fj]) {
var g00 = row[fi];
var g10 = row[ci];
if (isValue(g00) && isValue(g10) && (row = grid[cj])) {
var g01 = row[fi];
var g11 = row[ci];
if (isValue(g01) && isValue(g11)) {
return bilinearInterpolateScalar(i - fi, j - fj, g00, g10, g01, g11);
}
}
}
return null;
}
function floorMod(a, n) {
var f = a - n * Math.floor(a / n);
return f === n ? 0 : f;
}
function isValue(x) {
return x !== null && x !== undefined;
}
function bilinearInterpolateScalar(x, y, g00, g10, g01, g11) {
var rx = 1 - x;
var ry = 1 - y;
return g00 * rx * ry + g10 * x * ry + g01 * rx * y + g11 * x * y;
}
(function batchInterpolate() {
var start = Date.now();
while (x < xMax) {
interpolateColumn(x);
x += 2;
if (Date.now() - start > 100) {
setTimeout(batchInterpolate, 25);
return;
}
}
self.renderBaselayer(mask);
})();
};
Temperature.prototype.renderBaselayer = function (mask) {
var context = this.baseCtx;
context.putImageData(mask.imageData, 0, 0);
};
Temperature.prototype.start = function () {
var self = this;
self.adjustSize();
//插值
self.interpolateField();
// self.renderBaselayer(); //底层canvas渲染
// (function drawFrame() {
// self.timer = setTimeout(function () {
// self.animationId = requestAnimationFrame(drawFrame);
// self.renderAnimatelayer(); //动画层canvas渲染
// }, 1000 / 10);
// }());
};
Temperature.prototype.adjustSize = function () {
var width = this.width;
var height = this.height;
this.baseCtx.canvas.width = width;
this.baseCtx.canvas.height = height;
this.baseCtx.clearRect(0, 0, width, height);
resolutionScale(this.baseCtx);
};
Temperature.prototype.bindEvent = function (e) {
var map = this.map;
if (this.options.methods) {
if (this.options.methods.mousemove) {
map.on('mouse-move', this.clickEvent);
}
}
};
Temperature.prototype.clickEvent = function (e) {
var self = this,
flag = false,
lines = self.pixelList;
if (lines.length > 0) {
lines.forEach(function (line, i) {
for (var j = 0; j < line.data.length; j++) {
var beginPt = line.data[j].pixel;
if (line.data[j + 1] == undefined) return;
var curPt = e;
var inCircle = tool.isPointInCircle(curPt, beginPt, self.options.lineWidth);
if (inCircle) {
self.options.methods.mousemove(e, line.data[j]);
flag = true;
return;
}
}
});
if (!flag) {
document.getElementById('tooltips').style.visibility = 'hidden';
}
}
};
function Legend() {
this.options = {
width: 400,
height: 15,
range: [0, 220],
gradient: {
0.1: '#96f3ff',
0.2: '#00c3ff',
0.3: '#00e68c',
0.4: '#00e600',
0.5: '#fffa00',
0.6: '#ffbe00',
0.7: '#ff7300',
0.8: '#fa1400',
0.9: '#c80091',
1.0: '#8200a0'
// gradient: {
// 0.1: '#38a702',
// 0.4: '#b0e000',
// 0.7: '#ffaa01',
// 1.0: '#fe0000'
// }
} };
this.init();
}
Legend.prototype.init = function () {
var options = this.options,
canvas = this.canvas = document.createElement('canvas'),
width = canvas.width = options.width,
height = canvas.height = options.height,
context = canvas.getContext('2d'),
grad = context.createLinearGradient(0, 0, width, height);
for (var gradient in options.gradient) {
grad.addColorStop(gradient, options.gradient[gradient]);
}
context.fillStyle = grad;
context.fillRect(0, 0, width, height);
this.imageData = context.getImageData(0, 0, width, height);
};
Legend.prototype.d2Hex = function (d) {
var hex = Number(d).toString(16);
while (hex.length < 2) {
hex = "0" + hex;
}
return hex.toUpperCase();
};
Legend.prototype.getRgbColor = function (point) {
var imageData = this.imageData;
var data = imageData.data;
var i = (point.y * this.canvas.width + point.x) * 4;
var rgb = [],
color = '#',
objRgbColor = {
"rgb": rgb,
"color": color
};
for (var j = 0; j < 3; j++) {
rgb.push(data[i + j]);
color += this.d2Hex(data[i + j]);
}
objRgbColor.color = color;
return objRgbColor;
};
Legend.prototype.getColor = function (value) {
var options = this.options,
range = options.range,
colorValue = value - range[0],
point = {
x: Math.round(colorValue * this.canvas.width / (range[range.length - 1] - range[0])),
y: 1
};
return this.getRgbColor(point);
};
return Temperature;
})));