├── LICENSE ├── README.md ├── planet_phase.html └── planet_phase.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rob Dawson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-planet-phase 2 | 3 | This JavaScript library can be used to draw somewhat realistic lunar or planetary discs, complete with phase shadows: 4 | 5 |  6 | 7 | The library requires that browsers support the CSS `border-radius` and `box-shadow` properties, which means it [should work everywhere except IE8 (and earlier)](http://caniuse.com/#feat=css-boxshadow). 8 | 9 | To use the library, just include the [planet_phase.js](https://github.com/codebox/js-planet-phase/blob/master/planet_phase.js) file somewhere in your page, and call the `drawPlanetPhase` function once for each disc that you want to draw. 10 | 11 | The simplest way to call the function is like this: 12 | 13 |
drawPlanetPhase(document.getElementById('container'), 0.15, true); 14 |15 | 16 | * The first argument is the HTML element that you want to contain the disc. 17 | * The second argument must be a value between 0 and 1, indicating how large the shadow should be: 18 | * 0 = new moon 19 | * 0.25 = crescent 20 | * 0.50 = quarter 21 | * 0.75 = gibbous 22 | * 1.00 = full moon 23 | * The third argument is a boolean value indicating whether the disc should be waxing or waning (i.e. which side of the disc the shadow should be on): 24 | * true = waxing - shadow on the left 25 | * false = waning - shadow on the right 26 | * The function also accepts an optional fourth argument, containing configuration values which change the size, colour and appearance of the disc: 27 | * `shadowColour` - CSS background-colour value for the shaded part of the disc 28 | * `lightColour` - CSS background-colour value for the illuminated part of the disc 29 | * `diameter` - diameter of the disc in pixels 30 | * `earthshine` - a number between 0 and 1, specifying the amount of light falling on the shaded part of the disc (0 = none, 1 = full illumination) 31 | * `blur` - amount of blur on the terminator in pixels (0 = no blur) 32 | -------------------------------------------------------------------------------- /planet_phase.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /planet_phase.js: -------------------------------------------------------------------------------- 1 | /* 2 | Defines the function 'drawPlanetPhase' which will render a 'kind of' realistic lunar or planetary disc with 3 | shadow. 4 | 5 | The simplest way to call the function is like this: 6 | 7 | drawPlanetPhase(document.getElementById('container'), 0.15, true) 8 | 9 | the first argument is the HTML element that you want to contain the disc 10 | 11 | the second argument must be a value between 0 and 1, indicating how large the shadow should be: 12 | 0 = new moon 13 | 0.25 = crescent 14 | 0.50 = quarter 15 | 0.75 = gibbous 16 | 1.00 = full moon 17 | 18 | the third argument is a boolean value indicating whether the disc should be waxing or waning (ie which 19 | side of the disc the shadow should be on): 20 | true = waxing - shadow on the left 21 | false = waning - shadow on the right 22 | 23 | the function accepts an optional fourth argument, containing configuration values which change the 24 | size, colour and appearance of the disc - see the comments on the 'defaultConfig' object for details. 25 | 26 | Copyright 2014 Rob Dawson 27 | http://codebox.org.uk/pages/planet-phase 28 | */ 29 | 30 | var drawPlanetPhase = (function(){ 31 | "use strict"; 32 | /*jslint browser: true, forin: true, white: true */ 33 | 34 | function calcInner(outerDiameter, semiPhase){ 35 | var innerRadius, 36 | absPhase = Math.abs(semiPhase), 37 | n = ((1-absPhase) * outerDiameter/2) || 0.01; 38 | 39 | innerRadius = n/2 + outerDiameter * outerDiameter/ (8 * n); 40 | 41 | return { 42 | d : innerRadius * 2, 43 | o : semiPhase > 0 ? (outerDiameter/2 - n) : (-2 * innerRadius + outerDiameter/2 + n) 44 | }; 45 | } 46 | 47 | function setCss(el, props){ 48 | var p; 49 | for (p in props){ 50 | el.style[p] = props[p]; 51 | } 52 | } 53 | function drawDiscs(outer, inner, blurSize){ 54 | var blurredDiameter, blurredOffset; 55 | setCss(outer.box, { 56 | 'position': 'absolute', 57 | 'height': outer.diameter + 'px', 58 | 'width': outer.diameter + 'px', 59 | 'border': '1px solid black', 60 | 'backgroundColor': outer.colour, 61 | 'borderRadius': (outer.diameter/2) + 'px', 62 | 'overflow': 'hidden' 63 | }); 64 | 65 | blurredDiameter = inner.diameter - blurSize; 66 | blurredOffset = inner.offset + blurSize/2; 67 | 68 | setCss(inner.box, { 69 | 'position': 'absolute', 70 | 'backgroundColor': inner.colour, 71 | 'borderRadius': (blurredDiameter/2) + 'px', 72 | 'height': blurredDiameter + 'px', 73 | 'width': blurredDiameter + 'px', 74 | 'left': blurredOffset + 'px', 75 | 'top': ((outer.diameter-blurredDiameter)/2) + 'px', 76 | 'boxShadow': '0px 0px ' + blurSize + 'px ' + blurSize + 'px ' + inner.colour, 77 | 'opacity' : inner.opacity 78 | }); 79 | } 80 | function makeDiv(container){ 81 | var div = document.createElement('div'); 82 | container.appendChild(div); 83 | return div; 84 | } 85 | function setPhase(outerBox, phase, isWaxing, config){ 86 | var innerBox = makeDiv(outerBox), 87 | outerColour, 88 | innerColour, 89 | innerVals; 90 | 91 | if (phase < 0.5){ 92 | outerColour = config.lightColour; 93 | innerColour = config.shadowColour; 94 | if (isWaxing){ 95 | phase *= -1; 96 | } 97 | } else { 98 | outerColour = config.shadowColour; 99 | innerColour = config.lightColour; 100 | phase = 1 - phase; 101 | if (!isWaxing){ 102 | phase *= -1; 103 | } 104 | } 105 | 106 | innerVals = calcInner(config.diameter, phase * 2); 107 | 108 | drawDiscs({ 109 | box : outerBox, 110 | diameter : config.diameter, 111 | colour: outerColour 112 | }, { 113 | box : innerBox, 114 | diameter : innerVals.d, 115 | colour: innerColour, 116 | offset: innerVals.o, 117 | opacity : 1 - config.earthshine 118 | }, config.blur); 119 | } 120 | 121 | var defaultConfig = { 122 | shadowColour: 'black', // CSS background-colour value for the shaded part of the disc 123 | lightColour: 'white', // CSS background-colour value for the illuminated part of the disc 124 | diameter: 100, // diameter of the moon/planets disc in pixels 125 | earthshine : 0.1, // between 0 and 1, the amount of light falling on the shaded part of the disc 0=none, 1=full illumination 126 | blur: 3 // amount of blur on the terminator in pixels, 0=no blur 127 | }; 128 | 129 | function populateMissingConfigValues(config){ 130 | var p; 131 | for(p in defaultConfig) { 132 | config[p] = (config[p] === undefined) ? defaultConfig[p] : config[p]; 133 | } 134 | return config; 135 | } 136 | 137 | return function(containerEl, phase, isWaxing, config){ 138 | config = populateMissingConfigValues(Object.create(config || {})); 139 | var el = makeDiv(containerEl); 140 | setPhase(el, phase, isWaxing, config); 141 | }; 142 | 143 | }()); 144 | --------------------------------------------------------------------------------