JSFiddle - React, Tailwind, and code Playground
by rew222
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/suncalc/1.8.0/suncalc.min.js"></script>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moon Phases SVG</title>
</head>
<body>
<div>
<svg id="moon" width="100%" height="100%" viewBox="0 0 200 200">
<defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<pattern id="moonTexture" patternUnits="objectBoundingBox" width="1" height="1">
<image xlink:href="https://i.imgur.com/H38CJMA.jpg" x="-7" y="-7" width="200" height="200" preserveAspectRatio="xMidYMid slice" />
<!-- <image width="200" height="200" preserveAspectRatio="xMidYMid slice" xlink:href="https://i.imgur.com/XIwmPPk.jpg"></image> -->
</pattern>
</defs>
<g id="moonGroup" transform="rotate(0 100 100)">
<circle cx="100" cy="100" r="80" />
<path id="arcPath" class="shadow" d="" />
</g>
</svg>
</div>
<div class="date-input">
<input type="date" id="dateInput">
</div>
</body>
</html>
CSS
@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,900|Dosis:300,400,600,700,800|Finlandica:400|Droid+Sans:400,700|Lato:300,400,700,900|PT+Sans:400,700|Ubuntu:300,400,500,700|Open+Sans:400,300,600,700|Roboto:400,300,500,700,900|Roboto+Condensed:400,300,700|Atkinson+Hyperlegible:400|Open+Sans+Condensed:300,700|Mohave:400|Play:400,700|Maven+Pro:400,500,700,900&subset=latin,latin-ext);
#moon{
height: 300px;
width: 300px;
background-image: url("https://i.imgur.com/Rg4CeGt.jpg");
}
svg {
border: 5px solid green;
}
circle {
fill: url(#moonTexture);
stroke: darkgrey;
stroke-width: 2;
}
path.shadow {
fill: black;
filter: url(#blur);
}
body{
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-image: url("https://i.imgur.com/k7SRgZ4.jpg");
}
.date-input input[type="date"] {
height: 30px;
width: 150px;
background-color: black;
color: white;
font-family: Finlandica;
font-size: 1em;
border: none;
padding: 8px;
border-radius: 4px;
}
JavaScript
const moon = document.getElementById('moon');
let arcPath = document.getElementById('arcPath');
let moonGroup = document.getElementById('moonGroup');
const dateSelect = document.querySelector('input')
//Washington DC
const lat = 38.889805;
const lon = -77.009056;
const moonDate = new Date();
//Southern Hemisphere is Opposite
const phases = [
{f1: "1 0", f2: "0 0", o: 0}, // Waxing Crescent
{f1: "1 0", f2: "1 1", o: 0},// Waxing Gibbous
{f1: "1 0", f2: "1 1", o: 270}, // Waning Gibbous
{f1: "1 1", f2: "0 1", o: 90}, // Waning Crescent
];
// Function to calculate a custom path based on the moon's illumination fraction
function getCustomMoonPath(illuminationFraction, phase) {
const r = 80; // Radius
const cx = 100; // Center x
const cy = 100; // Center y
const angle = 2 * Math.PI * illuminationFraction;
const x = cx + r * Math.cos(angle);
const y = cy - r * Math.sin(angle);
const flag1 = phases[phase].f1;
const flag2 = phases[phase].f2;
return `M ${cx},${cy - r} A ${r},${r} 0 ${flag1} ${cx},${cy + r} A ${r * (illuminationFraction * 2 - 1)},${r} 0 ${flag2} ${cx},${cy - r} Z`;
}
// Update the moon path based on the current illumination fraction
function updateMoonPath(mD) {
let mC = SunCalc.getMoonIllumination(mD);
let mP = SunCalc.getMoonPosition(mD, lat, lon);
let mZ = SunCalc.getMoonTimes(mD, lat, lon); // Just For Console Log
let mT = ((mC.angle - mP.parallacticAngle) * (180/Math.PI)).toFixed(3);
let illumination = mC.fraction;
let phase = Math.min(Math.floor((mC.phase) / .25), 3);
let displayTilt = mT<0?phases[phase].o-Math.abs(mT):phases[phase].o-mT;
let cP = getCustomMoonPath(illumination, phase);
//console.log((mZ.set) ? (mZ.set).toLocaleTimeString('en-US') : "" );
console.log("Date: "+ mD, "Phase: " + phase, "Illumination: " + mC.fraction , "Angle: " + mC.angle, "Parallactic Angle: " + mP.parallacticAngle, "Tilt: " + mT, "Display Tilt: " + displayTilt);
console.log("Moon Rise: " +...