Ошибка связана с тем, что синус используется как для x, так и для y. Как холст ориентируют 0 ° направляется прямо должно быть:
sun.x = 400 * Math.cos(angle * (Math.PI/180)); // cos for x
sun.y = 100 * Math.sin(angle * (Math.PI/180));
Обратите внимание, что 400100 имеют радиус здесь так, чтобы определить центр вы также должны были бы центральную точку:
sun.x = centerX + radiusX * Math.cos(angle * (Math.PI/180));
sun.y = centerY + radiusY * Math.sin(angle * (Math.PI/180));
Всего несколько точек рассмотреть -
То, что интерпретируется как реалистичный восход/закат, будет во многом зависеть от того, где вы находитесь в мире (относительно широты или φ).
Например, если вы живете в Эквадоре, или φ = 0, солнце будет в основном идти прямо вверх и вниз. Если вы находитесь выше арктического круга (или антарктического круга, если на то пошло), у вас будет довольно крутой угол. Кроме того, солнце никогда не будет устанавливаться в летнее время (midnight sun) и никогда не подниматься зимой (polar night) на этих широтах.
Если вы только после приближения, вы можете определить базовый уровень (восход солнца) под углом 0 и заход солнца под углом 180, идущий дугой слева направо (или с востока на запад, если вы находитесь в южное полушарие, вы, вероятно, предпочтете противоположное).
Система координат холста будет иметь 0 °, направленную вправо, 90 ° укажет вниз, поэтому мы узнаем, что 180 - 360 ° будет дугой с зенитом (высшая точка) при 270 °.
Это нарисовать дугу, как это, используя фиктивный солнце и произвольные шаги:
var ctx = document.querySelector("canvas").getContext("2d");
var angle = Math.PI, // we'll use radians here, 0 to Math.PI (=180)
centerX = ctx.canvas.width * 0.5, // center of arc
bottomY = ctx.canvas.height,
radiusX = ctx.canvas.width * 0.8, // radius, 80% of width in this example
radiusY = ctx.canvas.height * 0.9; // radius, 90% of height in this example
// goes 180 to 360°, in radians PI to 2xPI
for(; angle < Math.PI*2; angle += 0.1) {
var x = centerX + radiusX * Math.cos(angle);
var y = bottomY + radiusY * Math.sin(angle);
ctx.fillRect(x - 2, y - 2, 4, 4); // dummy sun for now
}
<canvas></canvas>
Следующий шаг заключается в нормализации значений входных и выходных, поэтому мы может просто подключить нормированное значение от времени к солнечному рендерингу.
Для нормализации времени вы можете определить время восхода и захода солнца. Затем разделите текущее время на этом диапазоне. Если значение находится в пределах диапазона [0, 1], мы имеем солнце и можем подключить это значение к «визуализатору».
Общая формула (не считая крайних случаев как f.ex.(ANT) арктические кружки):
var normTime = (currentTime - sunriseTime)/(sunsetTime - sunrisetime);
Отображатель примет нормализованное значение и применить его к [180, 360] диапазону с помощью простой интерполяции:
var currentAngle = Math.PI + (Math.PI * 2 - Math.PI) * normTime;
или упрощенного:
var currentAngle = Math.PI + Math.PI * normTime;
Вы можете даже включить нормированное значение времени в значение градиента, а также нарисовать фон, представляющий цвет неба.
Для простоты, позволяет моделировать 24-часовые часы, которая работает очень быстро:
var ctx = document.querySelector("canvas").getContext("2d"),
gr = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height),
sky = new Image();
sky.onload = go;
sky.src = "http://i.stack.imgur.com/qhQhQ.jpg";
function go() {
// some style setup
ctx.font = "bold 16px sans-serif";
gr.addColorStop(0, "#ffc");
gr.addColorStop(0.75, "gold");
gr.addColorStop(1, "orange");
ctx.shadowColor = "#ffa";
var centerX = ctx.canvas.width * 0.5, // center of arc
bottomY = ctx.canvas.height + 16, // let center be a bit below horizon
radiusX = ctx.canvas.width * 0.52, // radius, 80% of width in this example
radiusY = ctx.canvas.height * 0.8; // radius, 90% of height in this example
// define sunrise and sunset times (in 24-hour clock, can be fractional)
var time = 7, sunrise = 7, sunset = 19;
(function loop() {
var normTime = getTime(); // get normalized time
var angle = getAngle(normTime); // get angle in radians
var x = centerX + radiusX * Math.cos(angle); // calcuate point
var y = bottomY + radiusY * Math.sin(angle);
drawSky(normTime); // draw sky gradient
drawSun(x, y); // draw sun at point
drawTime(); // render time
requestAnimationFrame(loop) // loop
})();
function getTime() {
// produces a normalized pseduo-time
time += 0.033;
if (time > 23) time = 0;
return (time - sunrise)/(sunset - sunrise);
}
function getAngle(normTime) {
return Math.PI + Math.PI * normTime
}
function drawSun(x, y) {
ctx.beginPath();
ctx.moveTo(x + 16, y);
ctx.arc(x, y, 16, 0, 6.28);
ctx.fillStyle = gr;
ctx.shadowBlur = 20;
ctx.fill();
}
function drawTime() {
ctx.fillStyle = "#fff";
ctx.shadowBlur = 0;
ctx.fillText("Time: " + time.toFixed(1) + "h", 10, 20);
}
function drawSky(t) {
t = Math.max(0, Math.min(1, t));
var iw = sky.width,
w = ctx.canvas.width,
x = 60 + (iw - 120) * t;
ctx.drawImage(sky, x, 0, 1, sky.height, 0, 0, w, ctx.canvas.height);
}
}
canvas {background:#acf}
<canvas width=400 height=180></canvas>
То, что осталось теперь найти линию горизонта и радиус для ширины и высоты в зависимости от широты. Зенит/азимут также являются факторами, которые следует учитывать, а также то, что центр солнечного пути, вероятно, не будет лежать на горизонте, поэтому диапазон углов для нормализации должен быть уменьшен или увеличен в зависимости от местоположения и времени года.
См. Также Yahoo's Weather channel API, который обеспечивает время засыпания/захода солнца, где вы находитесь. Также проверьте NOAA's page для подсказок и формул, чтобы правильно вычислить углы относительно точки обзора и т.д. (НАСА имеет некоторые хорошие ресурсы, а)
Вы также можете ограничить солнечный рисунок, когда он вне [0, 1] в зависимости от того, как будет проходить ваш окончательный рендеринг (в демонстрационной надписи холст будет закрепить его для нас).
Я признаю, что это один из лучших ответов, которые я когда-либо получал. Так что большое спасибо за то, что нашли время, чтобы помочь мне! Это заставило его работать отлично :). – Justin
@ user3585563 без проблем, рад, что я мог бы помочь! :) Удачи с вашим проектом. – K3N