(3.1)角度转换:将所述风向角度值中大于360°的转换为360°以内的值。
(3.2)极坐标转换为笛卡尔坐标:将风向角度值以及风速值的极坐标转换为笛卡尔坐标;
(3.3)绘制热力图:将步骤(1)中得到的被测量污染物的浓度值的离散点数据,经过IDW算法计算后,得到离散数据点,在canvas中画出矩阵图;
(3.4)将绘制的热力图添加到笛卡尔坐标系中;
(3.5)凸包计算:根据步骤(3.2)转换的坐标,在步骤(3.3)绘制的热力图中画出凸包各个点,从而限定凸包范围;
(3.6)绘制最终图形:根据凸包范围判定步骤(3.3)得到的离散数据点,是否在凸包范围内,取两者交集,并形成最终图形。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.frame {
fill: none;
stroke: #000;
}
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis circle {
fill: none;
stroke: #000;
stroke-dasharray: 4;
}
.axis:last-of-type circle {
stroke: #000;
stroke-dasharray: none;
}
.line {
fill: none;
stroke: #000;
stroke-width: 3px;
}
svg {
opacity: 1;
filter: alpha(opacity=100);
}
</style>
</head>
<body>
<div class="zuobiao">
<canvas id="canvas" style="z-index: -1; opacity:1; position: absolute; "> </canvas>
<canvas id="canvas1" height="400px" width="600px" style=" z-index: -1; position: absolute; "> </canvas>
</div>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script>
var width = 380, //图形的宽度
height = 300; //图形的高度
</script>
<script src="js/weathermapIDW.js"></script>
<script>
var colorarray = ["#0000FF", "#006EFF", "#00DDFF", "#2AFFFF", "#68FFFF", "#8BFFE8", "#06FF0B", "#49FF7A", "#49FF00", "#9BFF00", "#D2FF00", "#E3FF00", "#F3FF00", "#FFF200", "#FFCB00", "#FFA300", "#FF7D00", "#FF5300", "#FF5300", "#FF0000"];
//var colorarray = ["#eeeeee", "#e0e0e0", "#C8C8C8", "#C0C0C0", "#B8B8B8", "#B0B0B0", "#A8A8A8", "#A0A0A0", "#989898", "#909090", "#888888", "#808080", "#787878", "#707070", "#686868", "#606060", "#666666", "#444444", "#222222", "#000000"];
var namearray = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000];
var table = [{
"WS": [1.0, 4.0, 2.0, 1.0, 3.0, 3.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 2.0, 5.0, 4.0, 6.0, 4.0, 2.0, 1.0, 2.0, 3.0, 3.0, 3.0, 4.0, 3.0, 3.0, 7.0, 6.0, 7.0, 4.0, 8.0, 6.0, 6.0, 7.0, 7.0, 6.0, 8.0, 8.0, 8.0, 7.0, 5.0, 4.0, 3.0, 3.0, 1.0, 2.0, 2.0, 2.0, 2.0],
"WD": [335.0, 350.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 170.0, 135.0, 135.0, 135.0, 90.0, 90.0, 90.0, 90.0, 100.0, 80.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 20.0, 30.0, 45.0, 45.0, 45.0, 80.0, 45.0, 45.0, 75.0, 45.0, 45.0, 45.0, 60.0, 45.0, 70.0, 80.0, 90.0, 225.0, 270.0, 260.0, 225.0],
"PM10": [183.2, 173.4, 194.0, 175.75, 203.6, 161.2, 142.0, 163.0, 175.5, 208.4, 205.0, 171.2, 143.6, 116.0, 110.6, 93.2, 98.2, 91.8, 83.6, 88.4, 81.4, 77.0, 81.8, 89.4, 115.8, 131.2, 166.4, 174.0, 170.2, 152.4, 184.4, 203.8, 212.6, 627.8, 1290.4, 1581.25, 1711.525, 1841.8, 2128.4, 2406.8, 2576.8, 2035.6, 1615.0, 1286.8, 1202.4, 1015.2, 733.8, 635.6, 339.2, 331.4, 303.2, 282.6]
}]
// var table = [{
// "WS": [1.0, 4.0, 2.0, 6.0, 3.0, 3.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 4.0, 6.0, 7.0, 6.0, 4.0, 2.0, 3.0, 2.0, 3.0, 5.0, 3.0, 4.0, 3.0, 3.0, 7.0, 6.0, 7.0, 4.0, 8.0, 6.0, 6.0, 7.0, 7.0, 6.0, 8.0, 8.0, 8.0, 7.0, 5.0, 4.0, 9.0, 3.0, 9.0, 2.0, 6.0, 5.0, 8.0],
// "WD": [335.0, 350.0, 70.0, 80.0, 1050.0, 206.0, 80.0, 90.0, 120.0, 250.0, 170.0, 250.0, 170.0, 135.0, 135.0, 135.0, 90.0, 90.0, 90.0, 90.0, 100.0, 80.0, 60.0, 50.0, 20.0, 300.0, 230.0, 180.0, 150.0, 10.0, 50.0, 20.0, 30.0, 45.0, 45.0, 45.0, 80.0, 45.0, 45.0, 75.0, 45.0, 45.0, 45.0, 60.0, 45.0, 70.0, 80.0, 90.0, 225.0, 270.0, 260.0, 225.0],
// "PM10": [183.2, 173.4, 194.0, 175.75, 203.6, 161.2, 142.0, 163.0, 175.5, 208.4, 205.0, 171.2, 143.6, 116.0, 110.6, 93.2, 98.2, 91.8, 83.6, 88.4, 81.4, 77.0, 81.8, 89.4, 115.8, 131.2, 166.4, 174.0, 170.2, 152.4, 184.4, 203.8, 212.6, 627.8, 1290.4, 1581.25, 1711.525, 1841.8, 2128.4, 2406.8, 2576.8, 2035.6, 1615.0, 1286.8, 1202.4, 1015.2, 733.8, 635.6, 339.2, 331.4, 303.2, 282.6]
// }]
//
//
// var table = [{
// "WS": [1.0, 4.0, 2.0, 6.0, 3.0, 3.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 4.0, 6.0, 7.0, 6.0, 4.0, 2.0, 3.0, 2.0, 3.0, 5.0, 3.0, 4.0, 3.0, 3.0, 7.0, 6.0, 7.0, 4.0, 8.0, 6.0, 6.0, 7.0, 7.0, 6.0, 8.0, 8.0, 8.0, 7.0, 5.0, 4.0, 9.0, 3.0, 9.0, 2.0, 6.0, 5.0, 8.0],
// "WD": [335.0, 350.0, 70.0, 80.0, 1050.0, 206.0, 80.0, 90.0, 120.0, 250.0, 170.0, 250.0, 170.0, 135.0, 135.0, 135.0, 90.0, 90.0, 90.0, 90.0, 100.0, 80.0, 60.0, 50.0, 20.0, 300.0, 230.0, 180.0, 150.0, 10.0, 50.0, 20.0, 30.0, 45.0, 45.0, 45.0, 80.0, 45.0, 45.0, 75.0, 45.0, 45.0, 45.0, 60.0, 45.0, 70.0, 80.0, 90.0, 225.0, 270.0, 260.0, 225.0],
// "PM10": [1083.2, 1073.4, 1294.0, 1375.75, 1203.6, 1161.2, 1402.0, 1603.0, 1705.5, 208.4, 205.0, 171.2, 143.6, 116.0, 110.6, 93.2, 98.2, 91.8, 183.6, 188.4, 81.4, 77.0, 81.8, 89.4, 215.8, 131.2, 166.4, 174.0, 170.2, 152.4, 184.4, 203.8, 212.6, 1627.8, 2290.4, 2581.25, 2711.525, 2841.8, 2128.4, 2406.8, 2576.8, 2035.6, 1615.0, 1286.8, 1202.4, 1015.2, 733.8, 635.6, 339.2, 331.4, 303.2, 282.6]
// }]
// var mydata = {"para0":["28","28","28","28","30","34","37","39","41","38","36","36","35","35","33","28","27","29","29","30","30","29","29","32","35","39","45","51","55","59","64","67","69","69","70","69","72","73","73","74","70","67","67","67","70","74","76","81","85","86","89","92","89","91","93","96","99","98","103","112","110","105","102","85","73","69","54","43","39","40","43","43","45","48","49","50","50","52","52","54","53","60","61","61","61","54","46","41","36","38","42","48","55","57","58","62","63","66","71","75","77","78","78","77","76","76","71","65","59","53","48","43","41","42","44","43","49","57","69","92","106","113","119","120","116","112","105","99","93","89","78","67","57","48","45","44","44","45","47","52","55","60","67","75","88","88","84","82","77","69","64","64","64","62","63","61","56","48","46","51","53","60","68","75","72","78","88","83","84","86","81","81","79","72","67","64","56","49","48","43","37","33","33","42","49","60","76","77","79","83","85","88","90","91","93","93","91","83","81","81","77","68","59","54","45","37","36","39","46"],"ws0":["0.53","0.42","0.52","0.39","0.67","0.25","0.37","0.45","0.46","0.58","0.41","0.37","0.72","0.77","0.84","0.92","1.22","0.99","0.87","0.8","0.4","0.51","0.62","0.81","0.53","0.49","0.5","0.78","0.52","0.76","0.86","0.9","0.59","1.07","0.93","1.39","1.45","1.23","1.07","1.3","1.25","1.55","1.24","0.85","0.76","0.49","0.69","0.71","0.89","0.66","0.56","0.42","0.39","0.38","0.38","0.4","0.38","0.38","0.65","0.86","0.93","1.02","1.38","0.97","0.8","0.56","0.69","0.45","0.38","0.44","0.43","0.3","1.02","0.46","0.29","0.34","0.27","0.54","0.66","0.72","0.8","1.31","1.62","1.45","1.01","0.92","1.45","1.54","0.59","0.71","0.64","0.63","0.63","1.34","1.26","1.12","1.04","0.78","1.07","1.33","1.26","0.89","0.39","0.53","1.19","1.72","0.85","0.69","1.29","0.84","0.83","0.95","0.61","0.68","1.11","1.14","0.67","1.13","1.07","0.7","0.76","0.86","1.03","0.61","0.42","0.42","0.37","0.25","0.6","0.61","0.65","0.9","0.57","0.65","0.67","0.46","0.32","0.58","0.24","0.26","0.1","0.2","0.28","0.13","0.44","0.69","0.93","0.86","0.7","0.88","0.38","0.4","0.55","0.64","0.67","0.56","0.38","0.46","0.27","0.31","0.39","0.34","0.2","0.65","0.91","0.74","0.83","0.42","0.78","0.55","1.04","0.51","0.68","0.78","0.9","0.62","0.71","0.73","1.12","0.99","1.01","0.64","0.53","0.48","0.55","0.72","0.58","0.45","0.52","0.85","0.59","0.47","0.23","0.5","0.62","0.34","0.34","0.38","0.4","0.8","0.67","0.64","0.64","0.7","0.58","0.43","0.45","0.31","0.35"],"wd0":["253.75","230.35","209.54","267.06","310.55","250.92","270.62","221.66","231.33","128.52","214.07","234.57","325.88","326.78","255.82","251.7","277.37","272.44","307.33","289.75","259.71","238.57","268.54","258.55","248.59","235.43","231.92","233.24","222.1","232.21","231.11","230.63","216.01","233.37","226.19","234.18","241.87","242.69","238.61","236.46","240.05","242.87","241.67","235.3","250.16","250.58","243.79","230.42","261.72","250.51","236.76","244.82","228.75","244.83","232.21","231.24","229.36","187.17","235.99","238.61","223.78","231.38","240.51","231.32","223.91","234.14","247.47","271.57","244.36","254.04","197.86","202.5","133.88","180.52","207.98","88.47","132.75","87.7","134.58","134.19","151.39","129.65","141.35","140.97","153.68","156.46","113.74","90.99","116.69","150.21","104.56","166.99","222.68","138.64","134.63","135.62","101.22","79.37","91.79","87.43","198.96","142.76","92.34","148.11","214.6","265.27","247.23","238.31","255.45","239.89","234.04","280.99","255.81","240.52","236.33","250.66","238.98","239.87","220.55","218.99","222.1","226.71","261.74","244.86","259.01","242.03","231.42","244.25","243.89","240.59","235.6","247.68","239.28","240.42","240.59","223.08","271.45","297.7","284.2","311.06","315","271.45","270","270","260.1","290.93","337.5","315.87","337.5","308.27","195.9","182.86","210.19","167.27","203.89","213.81","154.47","209.54","220.17","290.59","173.25","244.85","225","266.75","252.83","286.4","292.22","116.31","264.54","210.54","284.27","198.79","284.13","284.37","254.95","163.48","192.46","156.45","258.29","232.56","260.98","233.78","252.59","242.85","243.87","235.56","298.26","270.13","272.2","232.5","258.11","234.89","190.41","230.07","337.5","205.32","206.44","151.27","109.23","131.26","148.17","169.35","168.95","165.14","173.76","198.75","239.82","247.71","216.74"],"unit":"ug/m3"};
//
// table[0].WS = mydata.ws0;
// table[0].WD = mydata.wd0;
// table[0].PM10 = mydata.para0;
$(document).ready(function() {
parm("canvas", width, height);
wwDrawpolygon(table);
var Legend = {
"DistanceLeft": width,
"With": 20,
"Height": height,
"Colorarray": colorarray,
"Namearray": namearray
};
zzb("canvas1", Legend);
//纵坐标
/**
* Name:纵坐标的名称
* DistanceTop:距离顶部距离
* DistanceLeft:距离左边距距离
*/
var OrdinateName = {
"Name": "风速(m/s)",
"DistanceTop": 30,
"DistanceLeft": 10
};
/**Scale对象纵坐标标线与刻度
* Min:最小值
* Max:最大值
* Stepnumber:取多少个刻度(步数)
* height:圆的高度
* DistanceTop:坐标轴距离顶部的距离
* DistanceLeft:坐标轴距离左边的距离
* FontLeft:坐标轴的字体与纵坐标标线的距离
*/
var Scale = {
"Min": -maxvalue,
"Max": maxvalue,
"Stepnumber": 10,
"height": height,
"DistanceTop": 30,
"DistanceLeft": 40,
"FontLeft": 10
};
xzb("canvas1", OrdinateName, Scale);
});
</script>
</body>
</html>
引入js文件
var radius = Math.min(width, height) / 2 - 30;
var canvas;
var canvasID;
var width;
var height;
var maxvalue = 0;
function parm(id, w, h) {
canvas = document.getElementById(id);
canvasID = id;
// var context = canvas.getContext("2d");
width = w;
height = h;
//radius = Math.min(width, height) / 2 - 30;
// $("#" + id).height(Math.sqrt(((h - 60) / 2) * ((h - 60) / 2) * 2));
// $("#" + id).width(Math.sqrt(((h - 60) / 2) * ((h - 60) / 2) * 2));
// var w = ((h - 60) - Math.sqrt(((h - 60) / 2) * ((h - 60) / 2) * 2)) / 2 + 30;
// $("#" + id).css({
// "margin-top": w + "px"
// });
// var w = (width - Math.sqrt(((h - 60) / 2) * ((h - 60) / 2) * 2)) / 2;
// $("#" + id).css({
// "margin-left": w + "px"
// });
$("#" + id).height(h - 60);
$("#" + id).width(h - 60);
$("#" + id).css({
"margin-top": 30 + "px"
});
var w = (width - (h - 60)) / 2;
$("#" + id).css({
"margin-left": w + "px"
});
}
/**
* canvas1:canvas的id
* @param {Object} Legend
* DistanceLeft:距离左边的距离
* With:单位图例高度
* Height:单位图例高度
* Colorarray:颜色设定值 数据类型 -数组(Array)
* Namearray:颜色块儿对应的名称 数据类型 -数组(Array)
*/
function zzb(canvas1, Legend) {
Legend.Height = (Legend.Height / (Legend.Colorarray.length + 2));
Legend.DistanceLeft = Legend.DistanceLeft - 30
var canvas1 = document.getElementById(canvas1);
var canvasWidth1 = canvas1.width;
var canvasHeight1 = canvas1.height;
var context1 = canvas1.getContext("2d");
for(var i = 0; i < Legend.Colorarray.length; i++) {
var my_gradient = context1.createLinearGradient(0, 0, 0, Legend.Height);
if(i != 0) {
my_gradient.addColorStop(0, Legend.Colorarray[Legend.Colorarray.length - i]);
my_gradient.addColorStop(1, Legend.Colorarray[Legend.Colorarray.length - i - 1]);
context1.fillStyle = my_gradient;
context1.fillRect(Legend.DistanceLeft * 1, Legend.Height * (i + 1), Legend.With, Legend.Height);
context1.strokeStyle = "#000000";
context1.strokeRect(Legend.DistanceLeft * 1, Legend.Height * (i + 1), Legend.With, Legend.Height);
context1.fillStyle = "#000000";
context1.font = "11px Arial";
context1.fillText(Legend.Namearray[Legend.Namearray.length - i - 1], Legend.DistanceLeft + Legend.With + 5, Legend.Height * (i + 1) + Legend.Height * 2 / 3);
} else {
my_gradient.addColorStop(0, Legend.Colorarray[Legend.Colorarray.length - i - 1]);
my_gradient.addColorStop(1, Legend.Colorarray[Legend.Colorarray.length - i - 1]);
context1.fillStyle = my_gradient;
context1.fillRect(Legend.DistanceLeft, Legend.Height * (i + 1), Legend.With, Legend.Height);
context1.strokeStyle = "#000000";
context1.lineHeight = Legend.Height;
context1.strokeRect(Legend.DistanceLeft, Legend.Height * (i + 1), Legend.With, Legend.Height);
context1.fillStyle = "#000000";
context1.font = "11px Arial";
context1.fillText(Legend.Namearray[Legend.Namearray.length - 1], Legend.DistanceLeft + Legend.With + 5, Legend.Height * (i + 1) + Legend.Height * 2 / 3);
}
}
}
/**
* @param {Object} OrdinateName 纵坐标标题
* Name:纵坐标的名称
* DistanceTop:距离顶部距离
* DistanceLeft:距离左边距距离
* @param {Object} Scale 纵坐标刻度
* Min:最小值
* Max:最大值
* Stepnumber:取多少个刻度(步数)
* Step:单位刻度的长度(步长)
* DistanceTop:坐标轴距离顶部的距离
* DistanceLeft:坐标轴距离左边的距离
* DistanceLeft:坐标轴距离左边的距离
*/
function xzb(canvas1, OrdinateName, Scale) {
var Step = (Scale.height - 60) / Scale.Stepnumber;
var canvas1 = document.getElementById(canvas1);
var canvasWidth1 = canvas1.width;
var canvasHeight1 = canvas1.height;
var context1 = canvas1.getContext("2d");
if((OrdinateName == "") && (OrdinateName == null))
OrdinateName = {
"Name": "风速(m/s)",
"DistanceTop": 200,
"DistanceLeft": 10
};
if((Scale == "") && (Scale == null))
Scale = {
"Min": -10,
"Max": 10,
"Stepnumber": 20,
"Step": 17,
"DistanceTop": 30,
"DistanceLeft": 40,
"FontLeft": 10
};
var Stepname = ((Scale.Max - Scale.Min) / Scale.Stepnumber).toFixed();
context1.fillStyle = "#000000";
for(var i = 0; i < (Scale.Stepnumber + 1); i++) {
if(i != 0) {
context1.fillRect(Scale.DistanceLeft, Step * (i + 1) + (Scale.DistanceTop - Step), 7, 1);
context1.font = "11px Arial";
context1.textAlign = "right";
context1.fillText(Scale.Min + (Scale.Stepnumber - i) * Stepname, Scale.DistanceLeft - Scale.FontLeft, Step * (i + 1) + (Scale.DistanceTop + 5 - Step));
} else {
context1.fillRect(Scale.DistanceLeft, Step * (i + 1) + (Scale.DistanceTop - Step), 7, 1);
context1.font = "11px Arial";
context1.textAlign = "right";
context1.fillText(Scale.Min + (Scale.Stepnumber - i) * Stepname, Scale.DistanceLeft - Scale.FontLeft, Step * (i + 1) + (Scale.DistanceTop + 5 - Step));
}
}
context1.fillRect(Scale.DistanceLeft, Scale.DistanceTop, 1, Step * Scale.Stepnumber);
context1.font = "12px Arial";
context1.textAlign = "center";
var DistanceTop = (Scale.height - 60) / 2;
context1.translate(OrdinateName.DistanceLeft, DistanceTop + OrdinateName.DistanceTop);
context1.rotate(270 * Math.PI / 180)
context1.fillText(OrdinateName.Name, 0, 0);
}
var zuobiaoname = ['北', '东北', '东', '东南', '南', '西南', '西', '西北', ]
// console.log($(".zuobiao").Width))
var data = [
[24, 100]
]
var y = _.map(data, _.last);
var max = Math.max.apply(null, y);
max = Math.ceil(max * 10) / 10;
var angle = d3.scale.linear()
.domain([0, 24])
.range([0, 2 * Math.PI]);
var r = d3.scale.linear()
.domain([0, max])
.range([0, radius]);
var svg = d3.select(".zuobiao").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var gr = svg.append("g")
.attr("class", "r axis")
.selectAll("g")
.data(r.ticks(max * 0.1).slice(1))
.enter().append("g");
gr.append("circle")
.attr("r", r);
gr.append("text")
.attr("y", function(d) {
return -r(d) - 4;
})
.attr("transform", "rotate(20)")
.style("text-anchor", "middle")
.text(function(d) {
return d + "%";
});
var ga = svg.append("g")
.attr("class", "a axis")
.selectAll("g")
.data(d3.range(-90, 270, 45))
.enter().append("g")
.attr("transform", function(d) {
return "rotate(" + d + ")";
});
ga.append("line")
.attr("x2", radius);
ga.append("text")
.attr("x", radius + 6)
.attr("dy", ".35em")
.style("text-anchor", function(d) {
return d < 270 && d > 90 ? "end" : null;
})
.attr("transform", function(d) {
//console.log(d)
if(d < 270 && d > 90)
return d < 270 && d > 90 ? "rotate(180 " + (radius + 6) + ",0)" : null;
if(d == 90)
return "rotate(270 " + (radius + 6) + ",5)";
if(d == -90)
return "rotate(90 " + (radius + 6) + ",-5)";
})
.attr("y", function(d) {
if(d == 90)
return "12";
if(d == -90)
return "-12";
})
.text(function(d, i) {
return zuobiaoname[i]
});
var color = d3.scale.category20();
function windrose2polar(a) {
var d = [];
for(var i = 0; i < a.length; i++) {
var r = 360 - a[i] + 90;
if(r > 360) {
r = r - 360;
}
d.push(r)
}
return d;
}
function linspace(a, b, c) { //生成等差数列
var d = (b - a) / (c - 1);
var e = ((b - a) / d) + 1;
var f = [];
for(var i = 0; i < e; i++) {
f.push(a + (d * i));
}
return f;
}
function radians(a) { //将角度转换为弧度
var d = [];
for(var i = 0; i < a.length; i++) {
var rwd = (a[i] * Math.PI) / 180;
d.push(rwd)
}
return d;
}
function degrees(a) {
var d = [];
for(var i = 0; i < a.length; i++) {
var dwdbins = (a[i] * 180) / Math.PI;
d.push(dwdbins)
}
return d;
}
function histogram(a, wdbins) {
var numarry = [];
for(var i = 0; i < wdbins.length - 1; i++) {
var num = 0;
for(var y = 0; y < a.length; y++) {
if((a[y] > wdbins[i]) && (a[y] < wdbins[i + 1])) {
num++;
}
}
numarry.push(num);
}
return numarry;
}
function pol2cartcos(rwd, ws) {
var cos = [];
for(var i = 0; i < rwd.length; i++) {
cos.push(ws[i] * Math.cos(rwd[i]))
// cos.push(Math.sqrt(rwd[i]*rwd[i] + ws[i]*ws[i] ));
}
return cos;
}
function pol2cartsin(rwd, ws) {
var sin = [];
for(var i = 0; i < rwd.length; i++) {
sin.push(ws[i] * Math.sin(rwd[i]))
}
return sin;
}
// 可以借助cos a 在0-180之间,单调递减!!!
// 这里用的是叉积,正弦的判断
function multiply(p0, p1, p2) {
return((p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y));
}
function distance_no_sqrt(p1, p2) {
//return(sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
return((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
function Graham_scan(pointSet, ch, n) {
var i, j, k = 0,
top = 2;
var tmp = new Object();
for(i = 1; i < n; i++) {
if((pointSet[i].y < pointSet[k].y) || ((pointSet[i].y == pointSet[k].y) && (pointSet[i].x < pointSet[k].x))) {
k = i;
}
}
tmp = pointSet[0];
pointSet[0] = pointSet[k];
pointSet[k] = tmp;
var use = n;
for(i = 1; i < use - 1; i++) {
k = i;
for(j = i + 1; j < use; j++) {
var direct = multiply(pointSet[0], pointSet[k], pointSet[j]);
if(direct > 0) {
k = j;
} else if(direct == 0) {
// k j 同方向
var dis = distance_no_sqrt(pointSet[0], pointSet[j]) - distance_no_sqrt(pointSet[0], pointSet[k]);
use--; // 也就是不要了
if(dis > 0) {
// 保留j
// 把 k 就不要了
pointSet[k] = pointSet[j];
pointSet[j] = pointSet[use];
j--;
} else {
tmp = pointSet[use];
pointSet[use] = pointSet[j];
pointSet[j] = tmp;
}
}
}
tmp = pointSet[i];
pointSet[i] = pointSet[k];
pointSet[k] = tmp;
}
ch.push(pointSet[0]);
ch.push(pointSet[1]);
ch.push(pointSet[2]);
for(i = 3; i < use; i++) {
while(!(multiply(pointSet[i], ch[top - 1], ch[top]) < 0)) {
top--;
ch.pop();
}
top++;
ch.push(pointSet[i]);
}
}
function drawCities(p) {
for(var i = 0; i < p.length; i++) {
// console.log(p[i].x + "-----" + p[i].y)
}
}
function convexhull(rwdc, wsc) {
var n = rwdc.length;
var p = new Array(n);
for(var i = 0; i < rwdc.length; i++) {
p[i] = new Object();
p[i].x = rwdc[i];
p[i].y = wsc[i];
}
var res = new Array();
Graham_scan(p, res, n);
drawCities(res);
return res;
}
function sortNumber(a, b) {
return a - b
}
var ws = [];
var wd = [];
var pm10 = [];
var N = 0;
function wwDrawpolygon(table) {
ws = table[0].WS;
wd = table[0].WD;
pm10 = table[0].PM10;
N = ws.length;
var rwd = windrose2polar(wd); //从风玫瑰坐标转换为极坐标
rwd = radians(rwd) //将角度转换为弧度
var wdbins = linspace(0.0, Math.PI * 2, 9); //生成等差数列
var dwdbins = degrees(wdbins) // 将弧度转换成角度
dwdbins = windrose2polar(dwdbins);
var rwdbins = radians(dwdbins);
var wdN = wdbins.length - 1;
var theta = [];
theta = rwdbins;
theta[wdN] = theta[0];
for(var i = 0; i < wd.length; i++) {
wd[i] = wd[i] + (360 / wdN) / 2;
}
for(var i = 0; i < wd.length; i++) {
if(wd[i] > 360) {
wd[i] = wd[i] - 360;
}
}
var wdhist = histogram(radians(wd), wdbins);
for(var i = 0; i < wdhist.length; i++) {
wdhist[i] = wdhist[i] / N ;
}
var nwdhist = wdhist;
nwdhist.push(nwdhist[0]);
var rwdc = pol2cartcos(rwd, ws); //极坐标转换为笛卡尔坐标
var wwrwdc = rwdc;
var wsc = pol2cartsin(rwd, ws);
var wwwsc = wsc;
var poly = convexhull(rwdc, wsc) //计算凸包
var dd = 0.5;
var minX = 0,
maxX = 0,
minY = 0,
maxY = 0;
for(var i = 0; i < rwdc.length; i++) {
if(minX > rwdc[i]) {
minX = rwdc[i];
}
if(maxX < rwdc[i]) {
maxX = rwdc[i];
}
}
for(var i = 0; i < wsc.length; i++) {
if(minY > wsc[i]) {
minY = wsc[i];
}
if(maxY < wsc[i]) {
maxY = wsc[i];
}
}
var fn = new MapIDW();
var datas = [];
for(var i = 0; i < rwdc.length; i++) {
datas.push({
"x": wwrwdc[i] * 1,
"y": wwwsc[i] * 1,
"v": pm10[i],
})
}
if(maxvalue < Math.abs(minX)) {
maxvalue = Math.abs(minX);
}
if(maxvalue < Math.abs(minY)) {
maxvalue = Math.abs(minY);
}
if(maxvalue < Math.abs(maxX)) {
maxvalue = Math.abs(maxX);
}
if(maxvalue < Math.abs(maxY)) {
maxvalue = Math.abs(maxY);
}
var num = parseInt(maxvalue / 5);
var numol = maxvalue % 5;
if(numol > 0) {
maxvalue = num * 5 + 5;
} else {
maxvalue = num * 5;
}
console.log(maxvalue);
$("#" + canvasID).height((height - 60) * ((maxY - minY) / (maxvalue * 2)));
$("#" + canvasID).width((height - 60) * ((maxX - minX) / (maxvalue * 2)));
var top = (height - 60) / 2 * ((maxvalue - maxY) / maxvalue)
alert( "maxvalue----------"+maxvalue+ "---height-"+height+"-----maxY-"+maxY)
$("#" + canvasID).css({
"margin-top": (30+top) + "px"
});
var w = (width - (height - 60)) / 2;
var left = (height - 60) / 2 * ((minX + maxvalue) / maxvalue)
$("#" + canvasID).css({
"margin-left": (w + left) + "px"
});
var points = fn.getTrainPonits(datas, 1, minX, maxX, minY, maxY, 25000, poly);
fn.draw(canvas, points, colorarray, namearray, function(v) {
for(var i = 0; i < colorarray.length; i++) {
if(i == 0) {
if(v < namearray[i]) {
return colorarray[i];
}
} else if((i < (colorarray.length - 2)) && (i != 0)) {
if((v > namearray[i - 1]) && (v < namearray[i])) {
return colorarray[i];
}
} else if(i == (colorarray.length - 1)) {
if((v > namearray[i])) {
return colorarray[i];
}
}
};
});
}
//worker 内容
function MapIDW() {
/**
* 反向距离权重法模拟点位
* @param {Object} datas 原始数据
* @param {Object} minlon 经度边界
* @param {Object} maxlon 经度边界
* @param {Object} minlat 纬度边界
* @param {Object} maxlat 纬度边界
* @param {Object} num 生成点数
* @param {Object} isRange 判断点是否在范围内,在则显示,否则抛弃
*/
this.getTrainPonits = function(datas, weight, minlon, maxlon, minlat, maxlat, num, polygon) {
var deltx = maxlon - minlon;
var delty = maxlat - minlat;
var b = deltx / delty;
var numy = Math.floor(Math.sqrt(num / b), 0)
var numx = Math.floor(b * Math.sqrt(num / b), 0)
var wx = deltx / numx;
var wy = delty / numy;
var result = [];
for(var j = 0; j < numy; j++) {
for(var i = 0; i < numx; i++) {
var tempx = minlon + i * wx;
var tempy = minlat + j * wy;
if(!isRange(tempx, tempy, polygon)) {
continue;
}
result.push({
x: tempx,
y: tempy,
v: 0,
id: i + ":" + j
})
}
}
var isallOffline = true; //站点如果全部离线,值都置为-1,地图用灰色显示
datas.forEach(function(d, index) {
if(!d.v) {
return;
}
isallOffline = false;
})
if(isallOffline) {
console.log("无值!");
}
var maxdis = Math.sqrt(Math.pow(Math.abs(maxlon - minlon), 2) + Math.pow(Math.abs(maxlat - minlat), 2));
result = result.map(function(r) {
if(isallOffline) {
r.v = -1
return r;
}
var v = 0;
var n = 0;
var disLimit = maxdis / (20 );
var blog = false; // r.id == "6:4";
if(blog) {
// console.log(r)
}
var fenmu = 0;
datas.forEach(function(d, index) {
if(!d.v) { //站点无值,则不参与运算
return;
}
var dis = Math.sqrt(Math.pow(Math.abs(r.x - d.x) , 2 ) + Math.pow(Math.abs(d.y - r.y) , 2));
d.dis = dis;
fenmu += Math.pow((1 / dis), 2 * weight);
})
r.v = 0;
for(var i = 0; i < datas.length; i++) {
var d = datas[i]
if(!d.v) {
continue;
}
d.weight = Math.pow((1 / d.dis), 2 * weight) / fenmu;
r.v += d.v * d.weight;
// console.log(r.v);
}
if(blog) {
console.log(r);
}
return r
})
this.numy = numy;
this.numx = numx;
this.deltx = deltx;
this.delty = delty;
this.minlon = minlon;
this.minlat = minlat;
this.maxlon = maxlon;
this.maxlat = maxlat;
this.resultPoints = result;
return result;
}
this.draw = function(canvas, points, Colorarray, Namearray, getColorFuc) {
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalAlpha = 1;
var wx = canvas.width / this.numx;
var wy = canvas.height / this.numy;
for(var i = 0; i < points.length; i++) {
var x = (points[i].x - this.minlon) * canvas.width / this.deltx;
var y = canvas.height - (points[i].y - this.minlat) * canvas.height / this.delty;
var temp = points[i].v;
ctx.fillStyle = getColorFuc(temp);
ctx.fillRect(x - wx / 2, y - wy / 2, wx, wy);
}
}
this.drawSelf = function(canvas, getColorFuc) {
this.draw(canvas, this.resultPoints, getColorFuc);
}
this.getDataUrlSelf = function(getColorFuc) {
var canvas = document.createElement("canvas");
canvas.style.background = "transparent";
canvas.width = 500;
canvas.height = 500 * (this.maxlat - this.minlat) / (this.maxlon - this.minlon) * 1.13;
this.drawSelf(canvas, getColorFuc);
//图片展示的 data URI
var dataUrl = canvas.toDataURL();
return dataUrl;
}
this.getDataUrl = function(points, getColorFuc) {
var canvas = document.createElement("canvas");
canvas.style.background = "transparent";
canvas.width = 500;
canvas.height = 500 * (this.maxlat - this.minlat) / (this.maxlon - this.minlon) * 1.13;
this.draw(canvas, points, getColorFuc);
//图片展示的 data URI
var dataUrl = canvas.toDataURL();
return dataUrl;
}
//定义点的结构体
function Point(x, y) {
this.y = y;
this.x = x;
}
//计算一个点是否在多边形里,参数:点,多边形数组
function PointInPoly(pt, poly) {
console.log(2)
for( var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
// ((poly[i].x <= pt.x && pt.x < poly[j].x) || (poly[j].x <= pt.x && pt.x < poly[i].x))&&
// (pt.y < (poly[j].y - poly[i].y) * (pt.x - poly[i].x) / (poly[j].x - poly[i].x) + poly[i].y)&&
// (c = !c);
// return c;
for( var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
{
if((poly[i].x <= pt.x && pt.x < poly[j].x) || (poly[j].x <= pt.x && pt.x < poly[i].x)){
if(pt.y < (poly[j].y - poly[i].y) * (pt.x - poly[i].x) / (poly[j].x - poly[i].x) + poly[i].y){
(c = !c)
}
}
}
return c;
}
function isRange(x, y, polygon) {
var p = new Point(x, y)
return PointInPoly(p, polygon);
}
}
var colorArray = ["#00e400", "#ffff00", "#ff7e00", "#ff0000", "#99004c", "#7e0023"];
var colorchild = {
"1": ['#2be900', '#55ed00', '#80f200', '#aaf600', '#d5fb00', "#ffff00"],
"2": ['#ffea00', '#ffd400', '#ffbf00', '#ffa900', '#ff9400', "#ff7e00"],
"3": ['#ff6900', '#ff5400', '#ff3f00', '#ff2a00', '#ff1500', "#ff0000"],
"4": ['#ee000d', '#dd0019', '#cc0026', '#bb0033', '#aa003f', "#99004c"],
"5": ['#950045', '#90003e', '#8c0038', '#870031', '#83002a', "#7e0023"]
}
var paraLevelRange = {
'PM25': [0, 35, 75, 115, 150, 250, 500],
'PM10': [0, 50, 150, 250, 350, 420, 600],
'PM2.5': [0, 35, 75, 115, 150, 250, 500],
'SO2': [0, 150, 500, 650, 800],
'NO2': [0, 100, 200, 700, 1200, 2340, 3840],
'CO': [0, 5, 10, 35, 60, 90, 150],
'O3': [0, 160, 200, 300, 400, 800, 1200],
'AQI': [0, 50, 100, 150, 200, 300, 500],
'AQI': [0, 50, 100, 150, 200, 300, 500],
'TVOC': [0, 60, 100, 200, 300, 500]
};
function getColorFuc(value) {
if(value < 0) {
return "gray";
}
let id = 0;
var paraname = "NO2"
for(let i = 1; i < paraLevelRange[paraname].length; i++) {
if(value < paraLevelRange[paraname][i]) {
id = i - 1;
break;
}
if(i == paraLevelRange[paraname].length - 1) {
id = i - 1;
}
}
if(id > 0) {
let max = paraLevelRange[paraname][id + 1];
let min = paraLevelRange[paraname][id];
let childColor = colorchild['' + id];
let ci = Math.floor((value - min) * 6 / (max - min));
return childColor[ci];
}
return colorArray[id];
}
var idw = new MapIDW();