admin管理员组文章数量:1306628
So I am trying to draw a sun in a arc path (Pref a circle path) to simulate a sunrise / sunset and I am running into issues.
Canvas Width = 800; Canvas Height = 100;
if(getTime() - sunTime > 100){
angle++;
sunTime = getTime();
}
sun.x = 400 * Math.sin(angle * (Math.PI/180));//Convert to degrees
sun.y = 100 * Math.sin(angle * (Math.PI/180));
That is the code that I am trying to make it arc correctly and it seems to give me the wrong type of arc.
The weird thing about the HTML canvas is that (0,0) is at the top left of the screen so things are a little weird. I tried finding a decent website that explained how to find it but everything I find does not seem to work the way I want it to.
I did this conversion based on what I know with math.... Soooo if This approach is way off please let me know!
So I am trying to draw a sun in a arc path (Pref a circle path) to simulate a sunrise / sunset and I am running into issues.
Canvas Width = 800; Canvas Height = 100;
if(getTime() - sunTime > 100){
angle++;
sunTime = getTime();
}
sun.x = 400 * Math.sin(angle * (Math.PI/180));//Convert to degrees
sun.y = 100 * Math.sin(angle * (Math.PI/180));
That is the code that I am trying to make it arc correctly and it seems to give me the wrong type of arc.
The weird thing about the HTML canvas is that (0,0) is at the top left of the screen so things are a little weird. I tried finding a decent website that explained how to find it but everything I find does not seem to work the way I want it to.
I did this conversion based on what I know with math.... Soooo if This approach is way off please let me know!
Share Improve this question edited Jun 2, 2015 at 3:50 user1693593 asked Jun 1, 2015 at 15:32 JustinJustin 8861 gold badge13 silver badges29 bronze badges1 Answer
Reset to default 13The error is due to sinus being used for both x and y. As canvas is oriented with 0° heading right it should be:
sun.x = 400 * Math.cos(angle * (Math.PI/180)); // cos for x
sun.y = 100 * Math.sin(angle * (Math.PI/180));
Note that 400,100 are radius here so to define a center you would also need a center point:
sun.x = centerX + radiusX * Math.cos(angle * (Math.PI/180));
sun.y = centerY + radiusY * Math.sin(angle * (Math.PI/180));
Just a few points to consider -
What is interpreted as a realistic sunrise/sunset will depend largely on where you are in the world (in relation to latitude, or φ).
For example, if you live in Ecuador, or φ = 0, the sun will basically go straight up and straight down. If you are above the arctic circle (or antarctic circle for that matter) you will have a pretty steep angle. Additionally the sun will never set in summer time (midnight sun), and never rise in the winter (polar night) at these latitudes.
If you're just after an approximation however, you can define baseline (sunrise) at angle 0, and sunset at angle 180, going in an arc from left to right (or east to west, if you are in the southern hemisphere you'd probably prefer the opposite).
Canvas' coordinate system will have 0° pointing to right, 90° will point down, so we will know that 180 - 360° will be an arc with zenith (highest point) at 270°.
This would draw an arc like this using a dummy sun and arbitrary steps:
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>
The next step is to normalize the input and output values so we can just plug a normalized value from time into the sun-renderer.
To normalize time you can define sunrise and sunset times. Then divide current time on that range. If the value is within [0, 1] range we have sun and can plug that value into the "renderer".
A generic formula (not considering extreme cases as f.ex. (ant)arctic circles):
var normTime = (currentTime - sunriseTime) / (sunsetTime - sunrisetime);
The renderer will take a normalized value and apply it to the [180, 360] range by using simple interpolation:
var currentAngle = Math.PI + (Math.PI * 2 - Math.PI) * normTime;
or simplified to:
var currentAngle = Math.PI + Math.PI * normTime;
You can even plug the normalized time value into a gradient value as well do draw a background representing the sky color.
For simplicity, lets simulate a 24 hour clock that runs very fast:
var ctx = document.querySelector("canvas").getContext("2d"),
gr = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height),
sky = new Image();
sky.onload = go;
sky.src = "https://i.sstatic/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>
What's left now is to find horizon line and radius for width and height depending on latitude. Zenith/azimuth are also factors to consider as well as that the sun-path's center will probably not lay on horizon so the angle-range to normalize must be reduced or increased depending on location and time of year.
See also Yahoo's Weather channel API which provides surise/sunset times for where you are. Also check out NOAA's page for hints and formulas to correctly calculate angles in relation to view point etc. (NASA has some good resources as well)
You could also limit the sun-drawing when it's outside [0, 1] range depending on how your final render will go (in the demo above canvas will clip it for us).
本文标签: mathSun Arc Path in JavascriptStack Overflow
版权声明:本文标题:math - Sun Arc Path in Javascript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741727434a2394686.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论