Я использую openweather , чтобы получать плитки карты температуры (Weather Map V1).
Мне нужно преобразовать цвет пикселя температуры в значения температуры.
Я нашел легенду для карты здесь
После того, как все плитки нарисованы на холсте, я получаю цвета пикселей с помощью getImageData.
Проблема : некоторые цвета, которые я получаю, почему-то неправильны, потому что они не вписываются ни в один шаг в линейном градиенте (заданном легендой).
Например: rgb ( 34, 198, 232) не подходит нигде в данном диапазоне. Как мне с этим справиться?
Вот фрагмент, чтобы увидеть мою реализацию, после загрузки карты вы можете щелкнуть по ней и увидеть вывод в консоли.
Дополнительно я загрузил код на jsFiddle
function relief_tile(z, x, y) {
return $('<img width="256" height="256">')
.attr('crossOrigin', '')
.attr('src', `https://cartodb-basemaps-b.global.ssl.fastly.net/light_all/${z}/${x}/${y}.png`)
}
function weather_tile(z, x, y) {
return $('<img width="256" height="256">')
.attr('crossOrigin', '')
.attr('src', `https://tile.openweathermap.org/map/temp_new/${z}/${x}/${y}.png?appid=01c2dab301eeeff7e02ebf1748f65faa`);
}
function rgbToHex(rgb) {
let r = rgb[0], g = rgb[1], b = rgb[2];
if (r > 255 || g > 255 || b > 255)
throw "Invalid color component";
return ((r << 16) | (g << 8) | b).toString(16);
}
function initSquareCanvas(canvas, size) {
canvas.height = size;
canvas.width = size;
}
let zoomLevel = 3;
$(async function () {
let relief_canvas = $('#relief-map')[0];
let relief_ctx;
if (relief_canvas) {
initSquareCanvas(relief_canvas, Math.pow(2, zoomLevel) * 256)
relief_ctx = relief_canvas.getContext('2d');
relief_ctx.globalAlpha = 1;
}
let weather_canvas = $('#weather-map')[0];
initSquareCanvas(weather_canvas, Math.pow(2, zoomLevel) * 256)
let weather_ctx = weather_canvas.getContext('2d');
function loadMap() {
for (let y = 0; y < Math.pow(2, zoomLevel); y++) {
for (let x = 0; x < Math.pow(2, zoomLevel); x++) {
relief_tile(zoomLevel, x, y).on('load', function () {
relief_ctx.drawImage(this, x * 256, y * 256, 256, 256);
weather_tile(zoomLevel, x, y).on('load', function () {
weather_ctx.drawImage(this, x * 256, y * 256, 256, 256);
});
});
}
}
}
loadMap();
let values_rgb_gradient = [
[-40, [130, 22, 146, 1]],
[-30, [130, 87, 219, 1]],
[-20, [32, 140, 236, 1]],
[-10, [32, 196, 232, 1]],
[0, [35, 221, 221, 1]],
[10, [194, 255, 40, 1]],
[20, [255, 240, 40, 1]],
[25, [255, 194, 40, 1]],
[30, [252, 128, 20, 1]],
].map(function ([_value, _color]) {
return [_value, _color.slice(0, -1)];
});
function findValFromRGBColor(color, valuesGradient) {
color = Array.from(color);
for (let index = 0; index < valuesGradient.length; index++) {
let [grad_value, grad_color] = valuesGradient[index];
let next = valuesGradient[index + 1];
if (next) { // is not last
let [next_value, next_color] = next;
let grad_diff_color = grad_color.map(function (v, i) {
return next_color[i] - v;
});
let diff_color = color.map(function (v, i) {
return v - grad_color[i];
});
let is_valid_range = grad_diff_color.map(function (v, i) {
if (v > 0 && diff_color[i] > 0) {
return v >= diff_color[i]
} else if (v < 0 && diff_color[i] < 0) {
return v <= diff_color[i];
}
return v === diff_color[i];
}).every(function (v) {
return v;
});
if (is_valid_range) {
let abs_grad_diff_color = grad_diff_color.map(Math.abs);
let max_index = abs_grad_diff_color.indexOf(Math.max(...abs_grad_diff_color));
if (grad_diff_color[max_index] === 0) {
return grad_value;
}
return grad_value + diff_color[max_index] / grad_diff_color[max_index] * (next_value - grad_value);
}
} else {
return grad_value
}
}
}
function findPos(obj) {
var curleft = 0, curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return {x: curleft, y: curtop};
}
return undefined;
}
$(weather_canvas).mousedown(function (e) {
let pos = findPos(this);
let x = e.pageX - pos.x;
let y = e.pageY - pos.y;
let color = weather_ctx.getImageData(x, y, 1, 1).data;
console.log("Clicked on : x=", x, "y=", y);
console.log("Color at this point: ", color);
console.log("Temperature on clicked point: ", findValFromRGBColor(color.slice(0, -1), values_rgb_gradient))
});
})
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div class="position-relative">
<canvas id="relief-map" width="256" height="256" class="position-absolute"></canvas>
<canvas id="weather-map" width="256" height="256" class="position-absolute"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>