- <!DOCTYPE html>
- <html>
-
- <head>
- <meta charset="utf-8">
- <title>ZingSoft Demo</title>
-
- <script nonce="undefined" src="https://cdn.zingchart.com/zingchart.min.js"></script>
- <style>
- html,
- body {
- height: 100%;
- width: 100%;
- margin: 0;
- padding: 0;
- }
-
- #myChart {
- height: 100%;
- width: 100%;
- min-height: 700px;
- position: relative;
- z-index: 500;
- }
-
- #crosshair-image {
- position: absolute;
- z-index: 1000;
- left: 908px;
- height: 50px;
- width: 50px;
- background-image: transparent;
- background-repeat: no-repeat;
- }
-
- /* split up the images into 4 moon phases 25px 25px pngs. You can crop your own */
- .phase_1 {
- background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_1.png");
- }
-
- .phase_2 {
- background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_2.png");
- }
-
- .phase_3 {
- background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_3.png");
- }
-
- .phase_4 {
- background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_4.png");
- }
- </style>
- </head>
-
- <body>
- <div id="myChart">
- <div id="crosshair-image"></div>
- </div>
- <script>
- ZC.LICENSE = ["569d52cefae586f634c54f86dc99e6a9", "b55b025e438fa8a98e32482b5f768ff5"]; /* Globals */
- var MILLISECONDS_IN_A_DAY = 86400000;
- var MILLISECONDS_IN_A_HOUR = 3600000;
- var MILLISECONDS_IN_A_MINUTE = 60000;
- var MILLISECONDS_IN_A_SECOND = 1000;
- var START_OF_2016_TIMESTAMP = 1451635200000;
- //var START_OF_2017_TIMESTAMP = 1451635200;
- var currentYearTimestamp = START_OF_2016_TIMESTAMP;
- var currentStringYear = '2016';
- var DEGREES_SYMBOL = '°';
- var MONTH_LABELS = ['Jan 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Feb 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Mar 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Apr 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'May 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'June 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'July 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Aug 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Sep 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Oct 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Nov 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Dec 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']; //length is 366
- var SCALE_MARKER_COLOR = '#bdbdbd';
- var SCALE_MARKER_LINE_WIDTH = 1;
- var SCALE_MARKER_ALPHA = .7;
- var SCALE_MARKERS = [ // scale markers used for more precise vertical guidelines
- {
- type: 'line',
- range: [31],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [60],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [91],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [121],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [152],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [182],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [213],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [244],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [274],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [305],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [335],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- }
- ];
-
- var myConfig = {
- layout: '3x1',
- graphset: [{ // start sunrise/sunset graph
- id: 'sunrise_sunset_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000, // max amount of nodes to be drawn. Also applies event listeners to 1000 nodes so faster if this is off
- highlightState: { // legend hover line state
- lineWidth: 5
- },
- marker: { // turn nodes off so its just the line
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true, // hover highlight
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366, // dont allow more than this amount of items
- itemsOverlap: true, // force items to not disappear
- step: 'day',
- guide: { //hide the guide lines
- visible: false
- },
- tick: { // hide ticks
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS // these are your new guidelines
- },
- scaleY: {
- minValue: 19800000, // 05:30:00 am
- maxValue: 26100000, // 07:15:00 am
- step: (MILLISECONDS_IN_A_MINUTE * 15),
- maxItems: 8, // force 8 items
- itemsOverlap: true, // helps force 8 items
- lineColor: '#ff5722',
- tick: {
- lineColor: '#ff5722'
- },
- guide: {
- visible: false
- },
- label: {
- text: 'Sunrise Time (AM)'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- scaleY2: {
- minValue: 63000000, // 05:30:00 pm
- maxValue: 69300000, // 07:15:00 pm
- step: (MILLISECONDS_IN_A_MINUTE * 15),
- maxItems: 8, // force 8 items
- itemsOverlap: true, // helps force 8 items
- lineColor: '#ff9800',
- tick: {
- lineColor: '#ff9800'
- },
- guide: {
- visible: false
- },
- label: {
- text: 'Sunset Time (PM)'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- tooltip: {
- visible: false
- }, // turn off tooltip
- crosshairX: {
- shared: true,
- plotLabel: { // crosshair tooltip
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %vv',
- fontSize: 15,
- padding: 10,
- borderRadius: 5
- },
- scaleLabel: {
- visible: false
- }, // highlight x-axis off
- marker: { // highlight marker
- type: 'circle',
- size: 4
- }
- },
- series: []
- },
- {
- id: 'azimuth_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000,
- highlightState: {
- lineWidth: 5
- },
- marker: {
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true,
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS
- },
- scaleY: {
- values: '60:120:10',
- maxItems: 7,
- itemsOverlap: true,
- format: '%v' + DEGREES_SYMBOL,
- guide: {
- visible: false
- },
- lineColor: '#ff5722',
- tick: {
- lineColor: '#ff5722'
- },
- label: {
- text: 'Sunrise Direction'
- }
- },
- scaleY2: {
- values: '240:300:10',
- maxItems: 7,
- itemsOverlap: true,
- format: '%v' + DEGREES_SYMBOL,
- guide: {
- visible: false
- },
- lineColor: '#ff9800',
- tick: {
- lineColor: '#ff9800'
- },
- label: {
- text: 'Sunset Direction'
- }
- },
- tooltip: {
- visible: false
- },
- crosshairX: {
- shared: true,
- plotLabel: {
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %v' + DEGREES_SYMBOL,
- fontSize: 15,
- padding: 10,
- borderRadius: 5
- },
- scaleLabel: {
- visible: false
- },
- marker: {
- type: 'circle',
- size: 4
- }
- },
- series: []
- }, // end azimuth graph
- { // start sunrise/sunset graph
- id: 'moonrise_moonset_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000,
- highlightState: {
- lineWidth: 5
- },
- marker: {
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true,
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS
- },
- scaleX2: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- maxItems: 400,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- },
- scaleY: {
- minValue: 0,
- maxValue: MILLISECONDS_IN_A_DAY,
- step: MILLISECONDS_IN_A_HOUR * 2,
- maxItems: 7,
- itemsOverlap: true,
- guide: {
- visible: false
- },
- label: {
- text: 'Moonrise Time'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- scaleY2: {
- minValue: 0,
- maxValue: MILLISECONDS_IN_A_DAY,
- step: MILLISECONDS_IN_A_HOUR * 2,
- maxItems: 7,
- itemsOverlap: true,
- guide: {
- visible: false
- },
- label: {
- text: 'Moonset Time'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- tooltip: {
- visible: false
- },
- crosshairX: {
- shared: true,
- plotLabel: {
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %vv',
- fontSize: 15,
- padding: 10,
- borderRadius: 5,
- },
- scaleLabel: {
- visible: false
- },
- marker: {
- type: 'circle',
- size: 4
- }
- },
- series: []
- }
- ]
- };
-
- zingchart.render({
- id: 'myChart',
- data: myConfig,
- height: '100%',
- width: '100%'
- });
-
- /*
- *
- * Example time: "113.63°"
- */
- function parseDegrees(sDegrees) {
- return Number(sDegrees.slice(0, sDegrees.length - 1));
- }
-
- /*
- *
- * Example time: "1, 5:50:56 AM"
- * returns milliseconds value
- */
- function parseStringToTimestamp(sTime) {
- if (sTime.length <= 1) {
- return null; // null value if blank cell
- }
- /*
- * Y axis are plotted from 0 - 24hrs in milliseconds.
- * Since x-axis already plots day we don't need the exact timestamp
- * for this day of the year. Just the offset in milliseconds.
- *
- */
- var aTime = sTime.split(/\s/); // separate am/pm
- parsedTime = aTime[0]; // asign time
- parsedTime = parsedTime.split(':'); // split time
-
- if (aTime[1].toLowerCase() == 'pm') {
- if (Number(parsedTime[0]) !== 12)
- parsedTime[0] = Number(parsedTime[0]) + 12;
- } else { // if am
- if (Number(parsedTime[0]) === 12)
- parsedTime[0] = 0; // convert 12:00AM to Unix time
- }
- parsedTime[0] = Number(parsedTime[0]) * MILLISECONDS_IN_A_HOUR;
- parsedTime[1] = Number(parsedTime[1]) * MILLISECONDS_IN_A_MINUTE;
- parsedTime[2] = Number(parsedTime[2]) * MILLISECONDS_IN_A_SECOND;
- return parsedTime[0] + parsedTime[1] + parsedTime[2];
- }
-
-
- function parseDataAndRenderChart() {
- var arrayOfRows = this.responseText.split('\n');
- var azimuthSeries = [];
- var sunriseSunsetSeries = [];
- var moonriseMoonsetSeries = [];
-
- // turn rows as a string into an array
- arrayOfRows = arrayOfRows.map(function(obj) {
- return obj.split(',');
- });
-
- // initialize azimuth chart series
- azimuthSeries[0] = {
- text: 'Sunrise Direction',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#ff5722'
- };
- azimuthSeries[1] = {
- text: 'Sunset Direction',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#ff9800'
- };
-
- // initialize sunrise/sunset chart series
- sunriseSunsetSeries[0] = {
- text: 'Sunrise',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#ff5722'
- };
- sunriseSunsetSeries[1] = {
- text: 'Sunset',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#ff9800'
- };
-
- // initialize moonrise/moonset chart series
- moonriseMoonsetSeries[0] = {
- text: 'Moonrise',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#9e9e9e'
- };
- moonriseMoonsetSeries[1] = {
- text: 'Moonset',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#212121'
- };
-
-
- /*
- * ignore arrayOfRows[0] those are the titles
- * assign millisecond timestamp value and string value to float
- * [[]] array of arrays
- */
- for (var i = 1; i < arrayOfRows.length; i++) {
-
- // compile azimuth data
- azimuthSeries[0].values.push( // push to series 0
- parseDegrees(arrayOfRows[i][2])
- );
- azimuthSeries[1].values.push( // push to series 1
- parseDegrees(arrayOfRows[i][4])
- );
-
- // compile sunrise/sunset data
- sunriseSunsetSeries[0].values.push( // push to series 0
- parseStringToTimestamp(arrayOfRows[i][1])
- );
- sunriseSunsetSeries[1].values.push( // push to series 1
- parseStringToTimestamp(arrayOfRows[i][3])
- );
-
- // compile moonrise/moonset data
- moonriseMoonsetSeries[0].values.push( // push to series 0
- parseStringToTimestamp(arrayOfRows[i][5])
- );
- moonriseMoonsetSeries[1].values.push( // push to series 1
- parseStringToTimestamp(arrayOfRows[i][6])
- );
-
- }
-
-
- // load data into chart
- zingchart.exec('myChart', 'setseriesdata', {
- graphid: 'azimuth_chart',
- update: false,
- data: azimuthSeries
- });
- zingchart.exec('myChart', 'setseriesdata', {
- graphid: 'sunrise_sunset_chart',
- update: false,
- data: sunriseSunsetSeries
- });
- zingchart.exec('myChart', 'appendseriesdata', {
- graphid: 'moonrise_moonset_chart',
- update: false,
- data: moonriseMoonsetSeries
- });
- zingchart.exec('myChart', 'update');
- }
-
-
-
-
-
-
- // request data from url
- var oReq = new XMLHttpRequest();
- oReq.addEventListener("load", parseDataAndRenderChart);
- oReq.open("GET", 'https://app.zingsoft.com/api/file/GSNQC6UG/xqIP1B9ZRXiOmCCmLfCU_sun_moon_rise_azimuth.csv'); // exported google sheets to csv (thats it)
- oReq.send();
-
-
-
-
-
- /*
- * Event listener for crosshair and how to change image.
- * This will change the class (check CSS tab) on the div (positioned absolute over the chart)
- * it will update the image based on the day (nodeindex).
- *
- * eg. nodeindex 32 is february 1st
- */
- var imageContainer = null;
-
- function bindImageOnMove(e) {
- // event is fired for all 3 graphs. For speed only do this once.
- if (e.graphid === "moonrise_moonset_chart") {
- // easy way to cache the reference to the element
- imageContainer = (imageContainer != null) ? imageContainer : document.getElementById('crosshair-image');
-
- // used CSS modifications over chart modifcations for faster speed.
- imageContainer.style.left = e.guide.x + 'px';
-
- // if node index exists for at least one plot
- if (e.items[0] && e.items[0].nodeindex) {
- switch (e.items[0].nodeindex) { // nodeindex = day
- case 1:
- case 31:
- case 62:
- imageContainer.className = "phase_1";
- break;
- case 9:
- case 39:
- case 70:
- imageContainer.className = "phase_2";
- break;
- case 17:
- case 47:
- case 78:
- imageContainer.className = "phase_3";
- break;
- case 25:
- case 55:
- case 86:
- imageContainer.className = "phase_4";
- break;
- default:
- imageContainer.className = ""; // remove image
- }
- }
- }
- }
-
- zingchart.bind('myChart', 'guide_mousemove', bindImageOnMove);
- /*
- * since the height of the chart is dynamic in my example (can resize window for chart size),
- * this function is used to dynamically set the height of the moon phase image on chart load (set it once)
- */
- zingchart.bind('myChart', 'complete', function(e) {
- // assign tooltip to top of graph by getting the bottom charts info
- var graphInfo = zingchart.exec('myChart', 'getobjectinfo', {
- graphid: 'moonrise_moonset_chart',
- object: 'graph'
- });
- imageContainer = document.getElementById('crosshair-image');
- imageContainer.style.top = (graphInfo.y + 10) + 'px';
- });
- </script>
- </body>
-
- </html>
- /* Globals */
- var MILLISECONDS_IN_A_DAY = 86400000;
- var MILLISECONDS_IN_A_HOUR = 3600000;
- var MILLISECONDS_IN_A_MINUTE = 60000;
- var MILLISECONDS_IN_A_SECOND = 1000;
- var START_OF_2016_TIMESTAMP = 1451635200000;
- //var START_OF_2017_TIMESTAMP = 1451635200;
- var currentYearTimestamp = START_OF_2016_TIMESTAMP;
- var currentStringYear = '2016';
- var DEGREES_SYMBOL = '°';
- var MONTH_LABELS = ['Jan 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Feb 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Mar 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Apr 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'May 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'June 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'July 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Aug 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Sep 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Oct 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Nov 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'Dec 1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']; //length is 366
- var SCALE_MARKER_COLOR = '#bdbdbd';
- var SCALE_MARKER_LINE_WIDTH = 1;
- var SCALE_MARKER_ALPHA = .7;
- var SCALE_MARKERS = [ // scale markers used for more precise vertical guidelines
- {
- type: 'line',
- range: [31],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [60],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [91],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [121],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [152],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [182],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [213],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [244],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [274],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [305],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- },
- {
- type: 'line',
- range: [335],
- lineColor: SCALE_MARKER_COLOR,
- lineWidth: SCALE_MARKER_LINE_WIDTH,
- alpha: SCALE_MARKER_ALPHA
- }
- ];
-
- var myConfig = {
- layout: '3x1',
- graphset: [{ // start sunrise/sunset graph
- id: 'sunrise_sunset_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000, // max amount of nodes to be drawn. Also applies event listeners to 1000 nodes so faster if this is off
- highlightState: { // legend hover line state
- lineWidth: 5
- },
- marker: { // turn nodes off so its just the line
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true, // hover highlight
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366, // dont allow more than this amount of items
- itemsOverlap: true, // force items to not disappear
- step: 'day',
- guide: { //hide the guide lines
- visible: false
- },
- tick: { // hide ticks
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS // these are your new guidelines
- },
- scaleY: {
- minValue: 19800000, // 05:30:00 am
- maxValue: 26100000, // 07:15:00 am
- step: (MILLISECONDS_IN_A_MINUTE * 15),
- maxItems: 8, // force 8 items
- itemsOverlap: true, // helps force 8 items
- lineColor: '#ff5722',
- tick: {
- lineColor: '#ff5722'
- },
- guide: {
- visible: false
- },
- label: {
- text: 'Sunrise Time (AM)'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- scaleY2: {
- minValue: 63000000, // 05:30:00 pm
- maxValue: 69300000, // 07:15:00 pm
- step: (MILLISECONDS_IN_A_MINUTE * 15),
- maxItems: 8, // force 8 items
- itemsOverlap: true, // helps force 8 items
- lineColor: '#ff9800',
- tick: {
- lineColor: '#ff9800'
- },
- guide: {
- visible: false
- },
- label: {
- text: 'Sunset Time (PM)'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- tooltip: {
- visible: false
- }, // turn off tooltip
- crosshairX: {
- shared: true,
- plotLabel: { // crosshair tooltip
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %vv',
- fontSize: 15,
- padding: 10,
- borderRadius: 5
- },
- scaleLabel: {
- visible: false
- }, // highlight x-axis off
- marker: { // highlight marker
- type: 'circle',
- size: 4
- }
- },
- series: []
- },
- {
- id: 'azimuth_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000,
- highlightState: {
- lineWidth: 5
- },
- marker: {
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true,
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS
- },
- scaleY: {
- values: '60:120:10',
- maxItems: 7,
- itemsOverlap: true,
- format: '%v' + DEGREES_SYMBOL,
- guide: {
- visible: false
- },
- lineColor: '#ff5722',
- tick: {
- lineColor: '#ff5722'
- },
- label: {
- text: 'Sunrise Direction'
- }
- },
- scaleY2: {
- values: '240:300:10',
- maxItems: 7,
- itemsOverlap: true,
- format: '%v' + DEGREES_SYMBOL,
- guide: {
- visible: false
- },
- lineColor: '#ff9800',
- tick: {
- lineColor: '#ff9800'
- },
- label: {
- text: 'Sunset Direction'
- }
- },
- tooltip: {
- visible: false
- },
- crosshairX: {
- shared: true,
- plotLabel: {
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %v' + DEGREES_SYMBOL,
- fontSize: 15,
- padding: 10,
- borderRadius: 5
- },
- scaleLabel: {
- visible: false
- },
- marker: {
- type: 'circle',
- size: 4
- }
- },
- series: []
- }, // end azimuth graph
- { // start sunrise/sunset graph
- id: 'moonrise_moonset_chart',
- type: 'line',
- utc: true,
- plot: {
- maxTrackers: 1000,
- highlightState: {
- lineWidth: 5
- },
- marker: {
- visible: false
- }
- },
- plotarea: {
- margin: '10 80 60 80'
- },
- legend: {
- highlightPlot: true,
- marginBottom: 0,
- marginRight: 80,
- layout: 'h'
- },
- scaleX: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- labels: MONTH_LABELS,
- maxItems: 366,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- transform: {
- type: 'date',
- all: '%M %d'
- },
- label: {
- text: 'Days'
- },
- markers: SCALE_MARKERS
- },
- scaleX2: {
- minValue: currentYearTimestamp,
- maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
- maxItems: 400,
- itemsOverlap: true,
- step: 'day',
- guide: {
- visible: false
- },
- tick: {
- visible: false
- },
- },
- scaleY: {
- minValue: 0,
- maxValue: MILLISECONDS_IN_A_DAY,
- step: MILLISECONDS_IN_A_HOUR * 2,
- maxItems: 7,
- itemsOverlap: true,
- guide: {
- visible: false
- },
- label: {
- text: 'Moonrise Time'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- scaleY2: {
- minValue: 0,
- maxValue: MILLISECONDS_IN_A_DAY,
- step: MILLISECONDS_IN_A_HOUR * 2,
- maxItems: 7,
- itemsOverlap: true,
- guide: {
- visible: false
- },
- label: {
- text: 'Moonset Time'
- },
- transform: {
- type: 'date',
- all: '%h:%i %A'
- }
- },
- tooltip: {
- visible: false
- },
- crosshairX: {
- shared: true,
- plotLabel: {
- headerText: '%kv ' + currentStringYear,
- text: '<span style="color:%color">%t:</span> %vv',
- fontSize: 15,
- padding: 10,
- borderRadius: 5,
- },
- scaleLabel: {
- visible: false
- },
- marker: {
- type: 'circle',
- size: 4
- }
- },
- series: []
- }
- ]
- };
-
- zingchart.render({
- id: 'myChart',
- data: myConfig,
- height: '100%',
- width: '100%'
- });
-
- /*
- *
- * Example time: "113.63°"
- */
- function parseDegrees(sDegrees) {
- return Number(sDegrees.slice(0, sDegrees.length - 1));
- }
-
- /*
- *
- * Example time: "1, 5:50:56 AM"
- * returns milliseconds value
- */
- function parseStringToTimestamp(sTime) {
- if (sTime.length <= 1) {
- return null; // null value if blank cell
- }
- /*
- * Y axis are plotted from 0 - 24hrs in milliseconds.
- * Since x-axis already plots day we don't need the exact timestamp
- * for this day of the year. Just the offset in milliseconds.
- *
- */
- var aTime = sTime.split(/\s/); // separate am/pm
- parsedTime = aTime[0]; // asign time
- parsedTime = parsedTime.split(':'); // split time
-
- if (aTime[1].toLowerCase() == 'pm') {
- if (Number(parsedTime[0]) !== 12)
- parsedTime[0] = Number(parsedTime[0]) + 12;
- } else { // if am
- if (Number(parsedTime[0]) === 12)
- parsedTime[0] = 0; // convert 12:00AM to Unix time
- }
- parsedTime[0] = Number(parsedTime[0]) * MILLISECONDS_IN_A_HOUR;
- parsedTime[1] = Number(parsedTime[1]) * MILLISECONDS_IN_A_MINUTE;
- parsedTime[2] = Number(parsedTime[2]) * MILLISECONDS_IN_A_SECOND;
- return parsedTime[0] + parsedTime[1] + parsedTime[2];
- }
-
-
- function parseDataAndRenderChart() {
- var arrayOfRows = this.responseText.split('\n');
- var azimuthSeries = [];
- var sunriseSunsetSeries = [];
- var moonriseMoonsetSeries = [];
-
- // turn rows as a string into an array
- arrayOfRows = arrayOfRows.map(function(obj) {
- return obj.split(',');
- });
-
- // initialize azimuth chart series
- azimuthSeries[0] = {
- text: 'Sunrise Direction',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#ff5722'
- };
- azimuthSeries[1] = {
- text: 'Sunset Direction',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#ff9800'
- };
-
- // initialize sunrise/sunset chart series
- sunriseSunsetSeries[0] = {
- text: 'Sunrise',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#ff5722'
- };
- sunriseSunsetSeries[1] = {
- text: 'Sunset',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#ff9800'
- };
-
- // initialize moonrise/moonset chart series
- moonriseMoonsetSeries[0] = {
- text: 'Moonrise',
- values: [],
- scales: 'scale-x, scale-y',
- lineColor: '#9e9e9e'
- };
- moonriseMoonsetSeries[1] = {
- text: 'Moonset',
- values: [],
- scales: 'scale-x, scale-y-2',
- lineColor: '#212121'
- };
-
-
- /*
- * ignore arrayOfRows[0] those are the titles
- * assign millisecond timestamp value and string value to float
- * [[]] array of arrays
- */
- for (var i = 1; i < arrayOfRows.length; i++) {
-
- // compile azimuth data
- azimuthSeries[0].values.push( // push to series 0
- parseDegrees(arrayOfRows[i][2])
- );
- azimuthSeries[1].values.push( // push to series 1
- parseDegrees(arrayOfRows[i][4])
- );
-
- // compile sunrise/sunset data
- sunriseSunsetSeries[0].values.push( // push to series 0
- parseStringToTimestamp(arrayOfRows[i][1])
- );
- sunriseSunsetSeries[1].values.push( // push to series 1
- parseStringToTimestamp(arrayOfRows[i][3])
- );
-
- // compile moonrise/moonset data
- moonriseMoonsetSeries[0].values.push( // push to series 0
- parseStringToTimestamp(arrayOfRows[i][5])
- );
- moonriseMoonsetSeries[1].values.push( // push to series 1
- parseStringToTimestamp(arrayOfRows[i][6])
- );
-
- }
-
-
- // load data into chart
- zingchart.exec('myChart', 'setseriesdata', {
- graphid: 'azimuth_chart',
- update: false,
- data: azimuthSeries
- });
- zingchart.exec('myChart', 'setseriesdata', {
- graphid: 'sunrise_sunset_chart',
- update: false,
- data: sunriseSunsetSeries
- });
- zingchart.exec('myChart', 'appendseriesdata', {
- graphid: 'moonrise_moonset_chart',
- update: false,
- data: moonriseMoonsetSeries
- });
- zingchart.exec('myChart', 'update');
- }
-
-
-
-
-
-
- // request data from url
- var oReq = new XMLHttpRequest();
- oReq.addEventListener("load", parseDataAndRenderChart);
- oReq.open("GET", 'https://app.zingsoft.com/api/file/GSNQC6UG/xqIP1B9ZRXiOmCCmLfCU_sun_moon_rise_azimuth.csv'); // exported google sheets to csv (thats it)
- oReq.send();
-
-
-
-
-
- /*
- * Event listener for crosshair and how to change image.
- * This will change the class (check CSS tab) on the div (positioned absolute over the chart)
- * it will update the image based on the day (nodeindex).
- *
- * eg. nodeindex 32 is february 1st
- */
- var imageContainer = null;
-
- function bindImageOnMove(e) {
- // event is fired for all 3 graphs. For speed only do this once.
- if (e.graphid === "moonrise_moonset_chart") {
- // easy way to cache the reference to the element
- imageContainer = (imageContainer != null) ? imageContainer : document.getElementById('crosshair-image');
-
- // used CSS modifications over chart modifcations for faster speed.
- imageContainer.style.left = e.guide.x + 'px';
-
- // if node index exists for at least one plot
- if (e.items[0] && e.items[0].nodeindex) {
- switch (e.items[0].nodeindex) { // nodeindex = day
- case 1:
- case 31:
- case 62:
- imageContainer.className = "phase_1";
- break;
- case 9:
- case 39:
- case 70:
- imageContainer.className = "phase_2";
- break;
- case 17:
- case 47:
- case 78:
- imageContainer.className = "phase_3";
- break;
- case 25:
- case 55:
- case 86:
- imageContainer.className = "phase_4";
- break;
- default:
- imageContainer.className = ""; // remove image
- }
- }
- }
- }
-
- zingchart.bind('myChart', 'guide_mousemove', bindImageOnMove);
- /*
- * since the height of the chart is dynamic in my example (can resize window for chart size),
- * this function is used to dynamically set the height of the moon phase image on chart load (set it once)
- */
- zingchart.bind('myChart', 'complete', function(e) {
- // assign tooltip to top of graph by getting the bottom charts info
- var graphInfo = zingchart.exec('myChart', 'getobjectinfo', {
- graphid: 'moonrise_moonset_chart',
- object: 'graph'
- });
- imageContainer = document.getElementById('crosshair-image');
- imageContainer.style.top = (graphInfo.y + 10) + 'px';
- });