• Edit
  • Download
    1. <!DOCTYPE html>
    2. <html>
    3.  
    4. <head>
    5. <meta charset="utf-8">
    6. <title>ZingSoft Demo</title>
    7.  
    8. <script nonce="undefined" src="https://cdn.zingchart.com/zingchart.min.js"></script>
    9. <style>
    10. html,
    11. body {
    12. height: 100%;
    13. width: 100%;
    14. margin: 0;
    15. padding: 0;
    16. }
    17.  
    18. #myChart {
    19. height: 100%;
    20. width: 100%;
    21. min-height: 700px;
    22. position: relative;
    23. z-index: 500;
    24. }
    25.  
    26. #crosshair-image {
    27. position: absolute;
    28. z-index: 1000;
    29. left: 908px;
    30. height: 50px;
    31. width: 50px;
    32. background-image: transparent;
    33. background-repeat: no-repeat;
    34. }
    35.  
    36. /* split up the images into 4 moon phases 25px 25px pngs. You can crop your own */
    37. .phase_1 {
    38. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_1.png");
    39. }
    40.  
    41. .phase_2 {
    42. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_2.png");
    43. }
    44.  
    45. .phase_3 {
    46. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_3.png");
    47. }
    48.  
    49. .phase_4 {
    50. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_4.png");
    51. }
    52. </style>
    53. </head>
    54.  
    55. <body>
    56. <div id="myChart">
    57. <div id="crosshair-image"></div>
    58. </div>
    59. <script>
    60. ZC.LICENSE = ["569d52cefae586f634c54f86dc99e6a9", "b55b025e438fa8a98e32482b5f768ff5"]; /* Globals */
    61. var MILLISECONDS_IN_A_DAY = 86400000;
    62. var MILLISECONDS_IN_A_HOUR = 3600000;
    63. var MILLISECONDS_IN_A_MINUTE = 60000;
    64. var MILLISECONDS_IN_A_SECOND = 1000;
    65. var START_OF_2016_TIMESTAMP = 1451635200000;
    66. //var START_OF_2017_TIMESTAMP = 1451635200;
    67. var currentYearTimestamp = START_OF_2016_TIMESTAMP;
    68. var currentStringYear = '2016';
    69. var DEGREES_SYMBOL = '°';
    70. 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
    71. var SCALE_MARKER_COLOR = '#bdbdbd';
    72. var SCALE_MARKER_LINE_WIDTH = 1;
    73. var SCALE_MARKER_ALPHA = .7;
    74. var SCALE_MARKERS = [ // scale markers used for more precise vertical guidelines
    75. {
    76. type: 'line',
    77. range: [31],
    78. lineColor: SCALE_MARKER_COLOR,
    79. lineWidth: SCALE_MARKER_LINE_WIDTH,
    80. alpha: SCALE_MARKER_ALPHA
    81. },
    82. {
    83. type: 'line',
    84. range: [60],
    85. lineColor: SCALE_MARKER_COLOR,
    86. lineWidth: SCALE_MARKER_LINE_WIDTH,
    87. alpha: SCALE_MARKER_ALPHA
    88. },
    89. {
    90. type: 'line',
    91. range: [91],
    92. lineColor: SCALE_MARKER_COLOR,
    93. lineWidth: SCALE_MARKER_LINE_WIDTH,
    94. alpha: SCALE_MARKER_ALPHA
    95. },
    96. {
    97. type: 'line',
    98. range: [121],
    99. lineColor: SCALE_MARKER_COLOR,
    100. lineWidth: SCALE_MARKER_LINE_WIDTH,
    101. alpha: SCALE_MARKER_ALPHA
    102. },
    103. {
    104. type: 'line',
    105. range: [152],
    106. lineColor: SCALE_MARKER_COLOR,
    107. lineWidth: SCALE_MARKER_LINE_WIDTH,
    108. alpha: SCALE_MARKER_ALPHA
    109. },
    110. {
    111. type: 'line',
    112. range: [182],
    113. lineColor: SCALE_MARKER_COLOR,
    114. lineWidth: SCALE_MARKER_LINE_WIDTH,
    115. alpha: SCALE_MARKER_ALPHA
    116. },
    117. {
    118. type: 'line',
    119. range: [213],
    120. lineColor: SCALE_MARKER_COLOR,
    121. lineWidth: SCALE_MARKER_LINE_WIDTH,
    122. alpha: SCALE_MARKER_ALPHA
    123. },
    124. {
    125. type: 'line',
    126. range: [244],
    127. lineColor: SCALE_MARKER_COLOR,
    128. lineWidth: SCALE_MARKER_LINE_WIDTH,
    129. alpha: SCALE_MARKER_ALPHA
    130. },
    131. {
    132. type: 'line',
    133. range: [274],
    134. lineColor: SCALE_MARKER_COLOR,
    135. lineWidth: SCALE_MARKER_LINE_WIDTH,
    136. alpha: SCALE_MARKER_ALPHA
    137. },
    138. {
    139. type: 'line',
    140. range: [305],
    141. lineColor: SCALE_MARKER_COLOR,
    142. lineWidth: SCALE_MARKER_LINE_WIDTH,
    143. alpha: SCALE_MARKER_ALPHA
    144. },
    145. {
    146. type: 'line',
    147. range: [335],
    148. lineColor: SCALE_MARKER_COLOR,
    149. lineWidth: SCALE_MARKER_LINE_WIDTH,
    150. alpha: SCALE_MARKER_ALPHA
    151. }
    152. ];
    153.  
    154. var myConfig = {
    155. layout: '3x1',
    156. graphset: [{ // start sunrise/sunset graph
    157. id: 'sunrise_sunset_chart',
    158. type: 'line',
    159. utc: true,
    160. plot: {
    161. maxTrackers: 1000, // max amount of nodes to be drawn. Also applies event listeners to 1000 nodes so faster if this is off
    162. highlightState: { // legend hover line state
    163. lineWidth: 5
    164. },
    165. marker: { // turn nodes off so its just the line
    166. visible: false
    167. }
    168. },
    169. plotarea: {
    170. margin: '10 80 60 80'
    171. },
    172. legend: {
    173. highlightPlot: true, // hover highlight
    174. marginBottom: 0,
    175. marginRight: 80,
    176. layout: 'h'
    177. },
    178. scaleX: {
    179. minValue: currentYearTimestamp,
    180. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    181. labels: MONTH_LABELS,
    182. maxItems: 366, // dont allow more than this amount of items
    183. itemsOverlap: true, // force items to not disappear
    184. step: 'day',
    185. guide: { //hide the guide lines
    186. visible: false
    187. },
    188. tick: { // hide ticks
    189. visible: false
    190. },
    191. transform: {
    192. type: 'date',
    193. all: '%M %d'
    194. },
    195. label: {
    196. text: 'Days'
    197. },
    198. markers: SCALE_MARKERS // these are your new guidelines
    199. },
    200. scaleY: {
    201. minValue: 19800000, // 05:30:00 am
    202. maxValue: 26100000, // 07:15:00 am
    203. step: (MILLISECONDS_IN_A_MINUTE * 15),
    204. maxItems: 8, // force 8 items
    205. itemsOverlap: true, // helps force 8 items
    206. lineColor: '#ff5722',
    207. tick: {
    208. lineColor: '#ff5722'
    209. },
    210. guide: {
    211. visible: false
    212. },
    213. label: {
    214. text: 'Sunrise Time (AM)'
    215. },
    216. transform: {
    217. type: 'date',
    218. all: '%h:%i %A'
    219. }
    220. },
    221. scaleY2: {
    222. minValue: 63000000, // 05:30:00 pm
    223. maxValue: 69300000, // 07:15:00 pm
    224. step: (MILLISECONDS_IN_A_MINUTE * 15),
    225. maxItems: 8, // force 8 items
    226. itemsOverlap: true, // helps force 8 items
    227. lineColor: '#ff9800',
    228. tick: {
    229. lineColor: '#ff9800'
    230. },
    231. guide: {
    232. visible: false
    233. },
    234. label: {
    235. text: 'Sunset Time (PM)'
    236. },
    237. transform: {
    238. type: 'date',
    239. all: '%h:%i %A'
    240. }
    241. },
    242. tooltip: {
    243. visible: false
    244. }, // turn off tooltip
    245. crosshairX: {
    246. shared: true,
    247. plotLabel: { // crosshair tooltip
    248. headerText: '%kv ' + currentStringYear,
    249. text: '<span style="color:%color">%t:</span> %vv',
    250. fontSize: 15,
    251. padding: 10,
    252. borderRadius: 5
    253. },
    254. scaleLabel: {
    255. visible: false
    256. }, // highlight x-axis off
    257. marker: { // highlight marker
    258. type: 'circle',
    259. size: 4
    260. }
    261. },
    262. series: []
    263. },
    264. {
    265. id: 'azimuth_chart',
    266. type: 'line',
    267. utc: true,
    268. plot: {
    269. maxTrackers: 1000,
    270. highlightState: {
    271. lineWidth: 5
    272. },
    273. marker: {
    274. visible: false
    275. }
    276. },
    277. plotarea: {
    278. margin: '10 80 60 80'
    279. },
    280. legend: {
    281. highlightPlot: true,
    282. marginBottom: 0,
    283. marginRight: 80,
    284. layout: 'h'
    285. },
    286. scaleX: {
    287. minValue: currentYearTimestamp,
    288. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    289. labels: MONTH_LABELS,
    290. maxItems: 366,
    291. itemsOverlap: true,
    292. step: 'day',
    293. guide: {
    294. visible: false
    295. },
    296. tick: {
    297. visible: false
    298. },
    299. transform: {
    300. type: 'date',
    301. all: '%M %d'
    302. },
    303. label: {
    304. text: 'Days'
    305. },
    306. markers: SCALE_MARKERS
    307. },
    308. scaleY: {
    309. values: '60:120:10',
    310. maxItems: 7,
    311. itemsOverlap: true,
    312. format: '%v' + DEGREES_SYMBOL,
    313. guide: {
    314. visible: false
    315. },
    316. lineColor: '#ff5722',
    317. tick: {
    318. lineColor: '#ff5722'
    319. },
    320. label: {
    321. text: 'Sunrise Direction'
    322. }
    323. },
    324. scaleY2: {
    325. values: '240:300:10',
    326. maxItems: 7,
    327. itemsOverlap: true,
    328. format: '%v' + DEGREES_SYMBOL,
    329. guide: {
    330. visible: false
    331. },
    332. lineColor: '#ff9800',
    333. tick: {
    334. lineColor: '#ff9800'
    335. },
    336. label: {
    337. text: 'Sunset Direction'
    338. }
    339. },
    340. tooltip: {
    341. visible: false
    342. },
    343. crosshairX: {
    344. shared: true,
    345. plotLabel: {
    346. headerText: '%kv ' + currentStringYear,
    347. text: '<span style="color:%color">%t:</span> %v' + DEGREES_SYMBOL,
    348. fontSize: 15,
    349. padding: 10,
    350. borderRadius: 5
    351. },
    352. scaleLabel: {
    353. visible: false
    354. },
    355. marker: {
    356. type: 'circle',
    357. size: 4
    358. }
    359. },
    360. series: []
    361. }, // end azimuth graph
    362. { // start sunrise/sunset graph
    363. id: 'moonrise_moonset_chart',
    364. type: 'line',
    365. utc: true,
    366. plot: {
    367. maxTrackers: 1000,
    368. highlightState: {
    369. lineWidth: 5
    370. },
    371. marker: {
    372. visible: false
    373. }
    374. },
    375. plotarea: {
    376. margin: '10 80 60 80'
    377. },
    378. legend: {
    379. highlightPlot: true,
    380. marginBottom: 0,
    381. marginRight: 80,
    382. layout: 'h'
    383. },
    384. scaleX: {
    385. minValue: currentYearTimestamp,
    386. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    387. labels: MONTH_LABELS,
    388. maxItems: 366,
    389. itemsOverlap: true,
    390. step: 'day',
    391. guide: {
    392. visible: false
    393. },
    394. tick: {
    395. visible: false
    396. },
    397. transform: {
    398. type: 'date',
    399. all: '%M %d'
    400. },
    401. label: {
    402. text: 'Days'
    403. },
    404. markers: SCALE_MARKERS
    405. },
    406. scaleX2: {
    407. minValue: currentYearTimestamp,
    408. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    409. maxItems: 400,
    410. itemsOverlap: true,
    411. step: 'day',
    412. guide: {
    413. visible: false
    414. },
    415. tick: {
    416. visible: false
    417. },
    418. },
    419. scaleY: {
    420. minValue: 0,
    421. maxValue: MILLISECONDS_IN_A_DAY,
    422. step: MILLISECONDS_IN_A_HOUR * 2,
    423. maxItems: 7,
    424. itemsOverlap: true,
    425. guide: {
    426. visible: false
    427. },
    428. label: {
    429. text: 'Moonrise Time'
    430. },
    431. transform: {
    432. type: 'date',
    433. all: '%h:%i %A'
    434. }
    435. },
    436. scaleY2: {
    437. minValue: 0,
    438. maxValue: MILLISECONDS_IN_A_DAY,
    439. step: MILLISECONDS_IN_A_HOUR * 2,
    440. maxItems: 7,
    441. itemsOverlap: true,
    442. guide: {
    443. visible: false
    444. },
    445. label: {
    446. text: 'Moonset Time'
    447. },
    448. transform: {
    449. type: 'date',
    450. all: '%h:%i %A'
    451. }
    452. },
    453. tooltip: {
    454. visible: false
    455. },
    456. crosshairX: {
    457. shared: true,
    458. plotLabel: {
    459. headerText: '%kv ' + currentStringYear,
    460. text: '<span style="color:%color">%t:</span> %vv',
    461. fontSize: 15,
    462. padding: 10,
    463. borderRadius: 5,
    464. },
    465. scaleLabel: {
    466. visible: false
    467. },
    468. marker: {
    469. type: 'circle',
    470. size: 4
    471. }
    472. },
    473. series: []
    474. }
    475. ]
    476. };
    477.  
    478. zingchart.render({
    479. id: 'myChart',
    480. data: myConfig,
    481. height: '100%',
    482. width: '100%'
    483. });
    484.  
    485. /*
    486. *
    487. * Example time: "113.63°"
    488. */
    489. function parseDegrees(sDegrees) {
    490. return Number(sDegrees.slice(0, sDegrees.length - 1));
    491. }
    492.  
    493. /*
    494. *
    495. * Example time: "1, 5:50:56 AM"
    496. * returns milliseconds value
    497. */
    498. function parseStringToTimestamp(sTime) {
    499. if (sTime.length <= 1) {
    500. return null; // null value if blank cell
    501. }
    502. /*
    503. * Y axis are plotted from 0 - 24hrs in milliseconds.
    504. * Since x-axis already plots day we don't need the exact timestamp
    505. * for this day of the year. Just the offset in milliseconds.
    506. *
    507. */
    508. var aTime = sTime.split(/\s/); // separate am/pm
    509. parsedTime = aTime[0]; // asign time
    510. parsedTime = parsedTime.split(':'); // split time
    511.  
    512. if (aTime[1].toLowerCase() == 'pm') {
    513. if (Number(parsedTime[0]) !== 12)
    514. parsedTime[0] = Number(parsedTime[0]) + 12;
    515. } else { // if am
    516. if (Number(parsedTime[0]) === 12)
    517. parsedTime[0] = 0; // convert 12:00AM to Unix time
    518. }
    519. parsedTime[0] = Number(parsedTime[0]) * MILLISECONDS_IN_A_HOUR;
    520. parsedTime[1] = Number(parsedTime[1]) * MILLISECONDS_IN_A_MINUTE;
    521. parsedTime[2] = Number(parsedTime[2]) * MILLISECONDS_IN_A_SECOND;
    522. return parsedTime[0] + parsedTime[1] + parsedTime[2];
    523. }
    524.  
    525.  
    526. function parseDataAndRenderChart() {
    527. var arrayOfRows = this.responseText.split('\n');
    528. var azimuthSeries = [];
    529. var sunriseSunsetSeries = [];
    530. var moonriseMoonsetSeries = [];
    531.  
    532. // turn rows as a string into an array
    533. arrayOfRows = arrayOfRows.map(function(obj) {
    534. return obj.split(',');
    535. });
    536.  
    537. // initialize azimuth chart series
    538. azimuthSeries[0] = {
    539. text: 'Sunrise Direction',
    540. values: [],
    541. scales: 'scale-x, scale-y',
    542. lineColor: '#ff5722'
    543. };
    544. azimuthSeries[1] = {
    545. text: 'Sunset Direction',
    546. values: [],
    547. scales: 'scale-x, scale-y-2',
    548. lineColor: '#ff9800'
    549. };
    550.  
    551. // initialize sunrise/sunset chart series
    552. sunriseSunsetSeries[0] = {
    553. text: 'Sunrise',
    554. values: [],
    555. scales: 'scale-x, scale-y',
    556. lineColor: '#ff5722'
    557. };
    558. sunriseSunsetSeries[1] = {
    559. text: 'Sunset',
    560. values: [],
    561. scales: 'scale-x, scale-y-2',
    562. lineColor: '#ff9800'
    563. };
    564.  
    565. // initialize moonrise/moonset chart series
    566. moonriseMoonsetSeries[0] = {
    567. text: 'Moonrise',
    568. values: [],
    569. scales: 'scale-x, scale-y',
    570. lineColor: '#9e9e9e'
    571. };
    572. moonriseMoonsetSeries[1] = {
    573. text: 'Moonset',
    574. values: [],
    575. scales: 'scale-x, scale-y-2',
    576. lineColor: '#212121'
    577. };
    578.  
    579.  
    580. /*
    581. * ignore arrayOfRows[0] those are the titles
    582. * assign millisecond timestamp value and string value to float
    583. * [[]] array of arrays
    584. */
    585. for (var i = 1; i < arrayOfRows.length; i++) {
    586.  
    587. // compile azimuth data
    588. azimuthSeries[0].values.push( // push to series 0
    589. parseDegrees(arrayOfRows[i][2])
    590. );
    591. azimuthSeries[1].values.push( // push to series 1
    592. parseDegrees(arrayOfRows[i][4])
    593. );
    594.  
    595. // compile sunrise/sunset data
    596. sunriseSunsetSeries[0].values.push( // push to series 0
    597. parseStringToTimestamp(arrayOfRows[i][1])
    598. );
    599. sunriseSunsetSeries[1].values.push( // push to series 1
    600. parseStringToTimestamp(arrayOfRows[i][3])
    601. );
    602.  
    603. // compile moonrise/moonset data
    604. moonriseMoonsetSeries[0].values.push( // push to series 0
    605. parseStringToTimestamp(arrayOfRows[i][5])
    606. );
    607. moonriseMoonsetSeries[1].values.push( // push to series 1
    608. parseStringToTimestamp(arrayOfRows[i][6])
    609. );
    610.  
    611. }
    612.  
    613.  
    614. // load data into chart
    615. zingchart.exec('myChart', 'setseriesdata', {
    616. graphid: 'azimuth_chart',
    617. update: false,
    618. data: azimuthSeries
    619. });
    620. zingchart.exec('myChart', 'setseriesdata', {
    621. graphid: 'sunrise_sunset_chart',
    622. update: false,
    623. data: sunriseSunsetSeries
    624. });
    625. zingchart.exec('myChart', 'appendseriesdata', {
    626. graphid: 'moonrise_moonset_chart',
    627. update: false,
    628. data: moonriseMoonsetSeries
    629. });
    630. zingchart.exec('myChart', 'update');
    631. }
    632.  
    633.  
    634.  
    635.  
    636.  
    637.  
    638. // request data from url
    639. var oReq = new XMLHttpRequest();
    640. oReq.addEventListener("load", parseDataAndRenderChart);
    641. oReq.open("GET", 'https://app.zingsoft.com/api/file/GSNQC6UG/xqIP1B9ZRXiOmCCmLfCU_sun_moon_rise_azimuth.csv'); // exported google sheets to csv (thats it)
    642. oReq.send();
    643.  
    644.  
    645.  
    646.  
    647.  
    648. /*
    649. * Event listener for crosshair and how to change image.
    650. * This will change the class (check CSS tab) on the div (positioned absolute over the chart)
    651. * it will update the image based on the day (nodeindex).
    652. *
    653. * eg. nodeindex 32 is february 1st
    654. */
    655. var imageContainer = null;
    656.  
    657. function bindImageOnMove(e) {
    658. // event is fired for all 3 graphs. For speed only do this once.
    659. if (e.graphid === "moonrise_moonset_chart") {
    660. // easy way to cache the reference to the element
    661. imageContainer = (imageContainer != null) ? imageContainer : document.getElementById('crosshair-image');
    662.  
    663. // used CSS modifications over chart modifcations for faster speed.
    664. imageContainer.style.left = e.guide.x + 'px';
    665.  
    666. // if node index exists for at least one plot
    667. if (e.items[0] && e.items[0].nodeindex) {
    668. switch (e.items[0].nodeindex) { // nodeindex = day
    669. case 1:
    670. case 31:
    671. case 62:
    672. imageContainer.className = "phase_1";
    673. break;
    674. case 9:
    675. case 39:
    676. case 70:
    677. imageContainer.className = "phase_2";
    678. break;
    679. case 17:
    680. case 47:
    681. case 78:
    682. imageContainer.className = "phase_3";
    683. break;
    684. case 25:
    685. case 55:
    686. case 86:
    687. imageContainer.className = "phase_4";
    688. break;
    689. default:
    690. imageContainer.className = ""; // remove image
    691. }
    692. }
    693. }
    694. }
    695.  
    696. zingchart.bind('myChart', 'guide_mousemove', bindImageOnMove);
    697. /*
    698. * since the height of the chart is dynamic in my example (can resize window for chart size),
    699. * this function is used to dynamically set the height of the moon phase image on chart load (set it once)
    700. */
    701. zingchart.bind('myChart', 'complete', function(e) {
    702. // assign tooltip to top of graph by getting the bottom charts info
    703. var graphInfo = zingchart.exec('myChart', 'getobjectinfo', {
    704. graphid: 'moonrise_moonset_chart',
    705. object: 'graph'
    706. });
    707. imageContainer = document.getElementById('crosshair-image');
    708. imageContainer.style.top = (graphInfo.y + 10) + 'px';
    709. });
    710. </script>
    711. </body>
    712.  
    713. </html>
    1. <!DOCTYPE html>
    2. <html>
    3.  
    4. <head>
    5. <meta charset="utf-8">
    6. <title>ZingSoft Demo</title>
    7.  
    8. <script src="https://cdn.zingchart.com/zingchart.min.js"></script>
    9. </head>
    10.  
    11. <body>
    12. <div id="myChart">
    13. <div id="crosshair-image"></div>
    14. </div>
    15. </body>
    16.  
    17. </html>
    1. html,
    2. body {
    3. height: 100%;
    4. width: 100%;
    5. margin: 0;
    6. padding: 0;
    7. }
    8.  
    9. #myChart {
    10. height: 100%;
    11. width: 100%;
    12. min-height: 700px;
    13. position: relative;
    14. z-index: 500;
    15. }
    16.  
    17. #crosshair-image {
    18. position: absolute;
    19. z-index: 1000;
    20. left: 908px;
    21. height: 50px;
    22. width: 50px;
    23. background-image: transparent;
    24. background-repeat: no-repeat;
    25. }
    26.  
    27. /* split up the images into 4 moon phases 25px 25px pngs. You can crop your own */
    28. .phase_1 {
    29. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_1.png");
    30. }
    31.  
    32. .phase_2 {
    33. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_2.png");
    34. }
    35.  
    36. .phase_3 {
    37. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_3.png");
    38. }
    39.  
    40. .phase_4 {
    41. background-image: url("//demos.zingchart.com/view/67J40ZDF/moon_phase_4.png");
    42. }
    1. /* Globals */
    2. var MILLISECONDS_IN_A_DAY = 86400000;
    3. var MILLISECONDS_IN_A_HOUR = 3600000;
    4. var MILLISECONDS_IN_A_MINUTE = 60000;
    5. var MILLISECONDS_IN_A_SECOND = 1000;
    6. var START_OF_2016_TIMESTAMP = 1451635200000;
    7. //var START_OF_2017_TIMESTAMP = 1451635200;
    8. var currentYearTimestamp = START_OF_2016_TIMESTAMP;
    9. var currentStringYear = '2016';
    10. var DEGREES_SYMBOL = '°';
    11. 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
    12. var SCALE_MARKER_COLOR = '#bdbdbd';
    13. var SCALE_MARKER_LINE_WIDTH = 1;
    14. var SCALE_MARKER_ALPHA = .7;
    15. var SCALE_MARKERS = [ // scale markers used for more precise vertical guidelines
    16. {
    17. type: 'line',
    18. range: [31],
    19. lineColor: SCALE_MARKER_COLOR,
    20. lineWidth: SCALE_MARKER_LINE_WIDTH,
    21. alpha: SCALE_MARKER_ALPHA
    22. },
    23. {
    24. type: 'line',
    25. range: [60],
    26. lineColor: SCALE_MARKER_COLOR,
    27. lineWidth: SCALE_MARKER_LINE_WIDTH,
    28. alpha: SCALE_MARKER_ALPHA
    29. },
    30. {
    31. type: 'line',
    32. range: [91],
    33. lineColor: SCALE_MARKER_COLOR,
    34. lineWidth: SCALE_MARKER_LINE_WIDTH,
    35. alpha: SCALE_MARKER_ALPHA
    36. },
    37. {
    38. type: 'line',
    39. range: [121],
    40. lineColor: SCALE_MARKER_COLOR,
    41. lineWidth: SCALE_MARKER_LINE_WIDTH,
    42. alpha: SCALE_MARKER_ALPHA
    43. },
    44. {
    45. type: 'line',
    46. range: [152],
    47. lineColor: SCALE_MARKER_COLOR,
    48. lineWidth: SCALE_MARKER_LINE_WIDTH,
    49. alpha: SCALE_MARKER_ALPHA
    50. },
    51. {
    52. type: 'line',
    53. range: [182],
    54. lineColor: SCALE_MARKER_COLOR,
    55. lineWidth: SCALE_MARKER_LINE_WIDTH,
    56. alpha: SCALE_MARKER_ALPHA
    57. },
    58. {
    59. type: 'line',
    60. range: [213],
    61. lineColor: SCALE_MARKER_COLOR,
    62. lineWidth: SCALE_MARKER_LINE_WIDTH,
    63. alpha: SCALE_MARKER_ALPHA
    64. },
    65. {
    66. type: 'line',
    67. range: [244],
    68. lineColor: SCALE_MARKER_COLOR,
    69. lineWidth: SCALE_MARKER_LINE_WIDTH,
    70. alpha: SCALE_MARKER_ALPHA
    71. },
    72. {
    73. type: 'line',
    74. range: [274],
    75. lineColor: SCALE_MARKER_COLOR,
    76. lineWidth: SCALE_MARKER_LINE_WIDTH,
    77. alpha: SCALE_MARKER_ALPHA
    78. },
    79. {
    80. type: 'line',
    81. range: [305],
    82. lineColor: SCALE_MARKER_COLOR,
    83. lineWidth: SCALE_MARKER_LINE_WIDTH,
    84. alpha: SCALE_MARKER_ALPHA
    85. },
    86. {
    87. type: 'line',
    88. range: [335],
    89. lineColor: SCALE_MARKER_COLOR,
    90. lineWidth: SCALE_MARKER_LINE_WIDTH,
    91. alpha: SCALE_MARKER_ALPHA
    92. }
    93. ];
    94.  
    95. var myConfig = {
    96. layout: '3x1',
    97. graphset: [{ // start sunrise/sunset graph
    98. id: 'sunrise_sunset_chart',
    99. type: 'line',
    100. utc: true,
    101. plot: {
    102. maxTrackers: 1000, // max amount of nodes to be drawn. Also applies event listeners to 1000 nodes so faster if this is off
    103. highlightState: { // legend hover line state
    104. lineWidth: 5
    105. },
    106. marker: { // turn nodes off so its just the line
    107. visible: false
    108. }
    109. },
    110. plotarea: {
    111. margin: '10 80 60 80'
    112. },
    113. legend: {
    114. highlightPlot: true, // hover highlight
    115. marginBottom: 0,
    116. marginRight: 80,
    117. layout: 'h'
    118. },
    119. scaleX: {
    120. minValue: currentYearTimestamp,
    121. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    122. labels: MONTH_LABELS,
    123. maxItems: 366, // dont allow more than this amount of items
    124. itemsOverlap: true, // force items to not disappear
    125. step: 'day',
    126. guide: { //hide the guide lines
    127. visible: false
    128. },
    129. tick: { // hide ticks
    130. visible: false
    131. },
    132. transform: {
    133. type: 'date',
    134. all: '%M %d'
    135. },
    136. label: {
    137. text: 'Days'
    138. },
    139. markers: SCALE_MARKERS // these are your new guidelines
    140. },
    141. scaleY: {
    142. minValue: 19800000, // 05:30:00 am
    143. maxValue: 26100000, // 07:15:00 am
    144. step: (MILLISECONDS_IN_A_MINUTE * 15),
    145. maxItems: 8, // force 8 items
    146. itemsOverlap: true, // helps force 8 items
    147. lineColor: '#ff5722',
    148. tick: {
    149. lineColor: '#ff5722'
    150. },
    151. guide: {
    152. visible: false
    153. },
    154. label: {
    155. text: 'Sunrise Time (AM)'
    156. },
    157. transform: {
    158. type: 'date',
    159. all: '%h:%i %A'
    160. }
    161. },
    162. scaleY2: {
    163. minValue: 63000000, // 05:30:00 pm
    164. maxValue: 69300000, // 07:15:00 pm
    165. step: (MILLISECONDS_IN_A_MINUTE * 15),
    166. maxItems: 8, // force 8 items
    167. itemsOverlap: true, // helps force 8 items
    168. lineColor: '#ff9800',
    169. tick: {
    170. lineColor: '#ff9800'
    171. },
    172. guide: {
    173. visible: false
    174. },
    175. label: {
    176. text: 'Sunset Time (PM)'
    177. },
    178. transform: {
    179. type: 'date',
    180. all: '%h:%i %A'
    181. }
    182. },
    183. tooltip: {
    184. visible: false
    185. }, // turn off tooltip
    186. crosshairX: {
    187. shared: true,
    188. plotLabel: { // crosshair tooltip
    189. headerText: '%kv ' + currentStringYear,
    190. text: '<span style="color:%color">%t:</span> %vv',
    191. fontSize: 15,
    192. padding: 10,
    193. borderRadius: 5
    194. },
    195. scaleLabel: {
    196. visible: false
    197. }, // highlight x-axis off
    198. marker: { // highlight marker
    199. type: 'circle',
    200. size: 4
    201. }
    202. },
    203. series: []
    204. },
    205. {
    206. id: 'azimuth_chart',
    207. type: 'line',
    208. utc: true,
    209. plot: {
    210. maxTrackers: 1000,
    211. highlightState: {
    212. lineWidth: 5
    213. },
    214. marker: {
    215. visible: false
    216. }
    217. },
    218. plotarea: {
    219. margin: '10 80 60 80'
    220. },
    221. legend: {
    222. highlightPlot: true,
    223. marginBottom: 0,
    224. marginRight: 80,
    225. layout: 'h'
    226. },
    227. scaleX: {
    228. minValue: currentYearTimestamp,
    229. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    230. labels: MONTH_LABELS,
    231. maxItems: 366,
    232. itemsOverlap: true,
    233. step: 'day',
    234. guide: {
    235. visible: false
    236. },
    237. tick: {
    238. visible: false
    239. },
    240. transform: {
    241. type: 'date',
    242. all: '%M %d'
    243. },
    244. label: {
    245. text: 'Days'
    246. },
    247. markers: SCALE_MARKERS
    248. },
    249. scaleY: {
    250. values: '60:120:10',
    251. maxItems: 7,
    252. itemsOverlap: true,
    253. format: '%v' + DEGREES_SYMBOL,
    254. guide: {
    255. visible: false
    256. },
    257. lineColor: '#ff5722',
    258. tick: {
    259. lineColor: '#ff5722'
    260. },
    261. label: {
    262. text: 'Sunrise Direction'
    263. }
    264. },
    265. scaleY2: {
    266. values: '240:300:10',
    267. maxItems: 7,
    268. itemsOverlap: true,
    269. format: '%v' + DEGREES_SYMBOL,
    270. guide: {
    271. visible: false
    272. },
    273. lineColor: '#ff9800',
    274. tick: {
    275. lineColor: '#ff9800'
    276. },
    277. label: {
    278. text: 'Sunset Direction'
    279. }
    280. },
    281. tooltip: {
    282. visible: false
    283. },
    284. crosshairX: {
    285. shared: true,
    286. plotLabel: {
    287. headerText: '%kv ' + currentStringYear,
    288. text: '<span style="color:%color">%t:</span> %v' + DEGREES_SYMBOL,
    289. fontSize: 15,
    290. padding: 10,
    291. borderRadius: 5
    292. },
    293. scaleLabel: {
    294. visible: false
    295. },
    296. marker: {
    297. type: 'circle',
    298. size: 4
    299. }
    300. },
    301. series: []
    302. }, // end azimuth graph
    303. { // start sunrise/sunset graph
    304. id: 'moonrise_moonset_chart',
    305. type: 'line',
    306. utc: true,
    307. plot: {
    308. maxTrackers: 1000,
    309. highlightState: {
    310. lineWidth: 5
    311. },
    312. marker: {
    313. visible: false
    314. }
    315. },
    316. plotarea: {
    317. margin: '10 80 60 80'
    318. },
    319. legend: {
    320. highlightPlot: true,
    321. marginBottom: 0,
    322. marginRight: 80,
    323. layout: 'h'
    324. },
    325. scaleX: {
    326. minValue: currentYearTimestamp,
    327. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    328. labels: MONTH_LABELS,
    329. maxItems: 366,
    330. itemsOverlap: true,
    331. step: 'day',
    332. guide: {
    333. visible: false
    334. },
    335. tick: {
    336. visible: false
    337. },
    338. transform: {
    339. type: 'date',
    340. all: '%M %d'
    341. },
    342. label: {
    343. text: 'Days'
    344. },
    345. markers: SCALE_MARKERS
    346. },
    347. scaleX2: {
    348. minValue: currentYearTimestamp,
    349. maxValue: currentYearTimestamp + (MILLISECONDS_IN_A_DAY * 365),
    350. maxItems: 400,
    351. itemsOverlap: true,
    352. step: 'day',
    353. guide: {
    354. visible: false
    355. },
    356. tick: {
    357. visible: false
    358. },
    359. },
    360. scaleY: {
    361. minValue: 0,
    362. maxValue: MILLISECONDS_IN_A_DAY,
    363. step: MILLISECONDS_IN_A_HOUR * 2,
    364. maxItems: 7,
    365. itemsOverlap: true,
    366. guide: {
    367. visible: false
    368. },
    369. label: {
    370. text: 'Moonrise Time'
    371. },
    372. transform: {
    373. type: 'date',
    374. all: '%h:%i %A'
    375. }
    376. },
    377. scaleY2: {
    378. minValue: 0,
    379. maxValue: MILLISECONDS_IN_A_DAY,
    380. step: MILLISECONDS_IN_A_HOUR * 2,
    381. maxItems: 7,
    382. itemsOverlap: true,
    383. guide: {
    384. visible: false
    385. },
    386. label: {
    387. text: 'Moonset Time'
    388. },
    389. transform: {
    390. type: 'date',
    391. all: '%h:%i %A'
    392. }
    393. },
    394. tooltip: {
    395. visible: false
    396. },
    397. crosshairX: {
    398. shared: true,
    399. plotLabel: {
    400. headerText: '%kv ' + currentStringYear,
    401. text: '<span style="color:%color">%t:</span> %vv',
    402. fontSize: 15,
    403. padding: 10,
    404. borderRadius: 5,
    405. },
    406. scaleLabel: {
    407. visible: false
    408. },
    409. marker: {
    410. type: 'circle',
    411. size: 4
    412. }
    413. },
    414. series: []
    415. }
    416. ]
    417. };
    418.  
    419. zingchart.render({
    420. id: 'myChart',
    421. data: myConfig,
    422. height: '100%',
    423. width: '100%'
    424. });
    425.  
    426. /*
    427. *
    428. * Example time: "113.63°"
    429. */
    430. function parseDegrees(sDegrees) {
    431. return Number(sDegrees.slice(0, sDegrees.length - 1));
    432. }
    433.  
    434. /*
    435. *
    436. * Example time: "1, 5:50:56 AM"
    437. * returns milliseconds value
    438. */
    439. function parseStringToTimestamp(sTime) {
    440. if (sTime.length <= 1) {
    441. return null; // null value if blank cell
    442. }
    443. /*
    444. * Y axis are plotted from 0 - 24hrs in milliseconds.
    445. * Since x-axis already plots day we don't need the exact timestamp
    446. * for this day of the year. Just the offset in milliseconds.
    447. *
    448. */
    449. var aTime = sTime.split(/\s/); // separate am/pm
    450. parsedTime = aTime[0]; // asign time
    451. parsedTime = parsedTime.split(':'); // split time
    452.  
    453. if (aTime[1].toLowerCase() == 'pm') {
    454. if (Number(parsedTime[0]) !== 12)
    455. parsedTime[0] = Number(parsedTime[0]) + 12;
    456. } else { // if am
    457. if (Number(parsedTime[0]) === 12)
    458. parsedTime[0] = 0; // convert 12:00AM to Unix time
    459. }
    460. parsedTime[0] = Number(parsedTime[0]) * MILLISECONDS_IN_A_HOUR;
    461. parsedTime[1] = Number(parsedTime[1]) * MILLISECONDS_IN_A_MINUTE;
    462. parsedTime[2] = Number(parsedTime[2]) * MILLISECONDS_IN_A_SECOND;
    463. return parsedTime[0] + parsedTime[1] + parsedTime[2];
    464. }
    465.  
    466.  
    467. function parseDataAndRenderChart() {
    468. var arrayOfRows = this.responseText.split('\n');
    469. var azimuthSeries = [];
    470. var sunriseSunsetSeries = [];
    471. var moonriseMoonsetSeries = [];
    472.  
    473. // turn rows as a string into an array
    474. arrayOfRows = arrayOfRows.map(function(obj) {
    475. return obj.split(',');
    476. });
    477.  
    478. // initialize azimuth chart series
    479. azimuthSeries[0] = {
    480. text: 'Sunrise Direction',
    481. values: [],
    482. scales: 'scale-x, scale-y',
    483. lineColor: '#ff5722'
    484. };
    485. azimuthSeries[1] = {
    486. text: 'Sunset Direction',
    487. values: [],
    488. scales: 'scale-x, scale-y-2',
    489. lineColor: '#ff9800'
    490. };
    491.  
    492. // initialize sunrise/sunset chart series
    493. sunriseSunsetSeries[0] = {
    494. text: 'Sunrise',
    495. values: [],
    496. scales: 'scale-x, scale-y',
    497. lineColor: '#ff5722'
    498. };
    499. sunriseSunsetSeries[1] = {
    500. text: 'Sunset',
    501. values: [],
    502. scales: 'scale-x, scale-y-2',
    503. lineColor: '#ff9800'
    504. };
    505.  
    506. // initialize moonrise/moonset chart series
    507. moonriseMoonsetSeries[0] = {
    508. text: 'Moonrise',
    509. values: [],
    510. scales: 'scale-x, scale-y',
    511. lineColor: '#9e9e9e'
    512. };
    513. moonriseMoonsetSeries[1] = {
    514. text: 'Moonset',
    515. values: [],
    516. scales: 'scale-x, scale-y-2',
    517. lineColor: '#212121'
    518. };
    519.  
    520.  
    521. /*
    522. * ignore arrayOfRows[0] those are the titles
    523. * assign millisecond timestamp value and string value to float
    524. * [[]] array of arrays
    525. */
    526. for (var i = 1; i < arrayOfRows.length; i++) {
    527.  
    528. // compile azimuth data
    529. azimuthSeries[0].values.push( // push to series 0
    530. parseDegrees(arrayOfRows[i][2])
    531. );
    532. azimuthSeries[1].values.push( // push to series 1
    533. parseDegrees(arrayOfRows[i][4])
    534. );
    535.  
    536. // compile sunrise/sunset data
    537. sunriseSunsetSeries[0].values.push( // push to series 0
    538. parseStringToTimestamp(arrayOfRows[i][1])
    539. );
    540. sunriseSunsetSeries[1].values.push( // push to series 1
    541. parseStringToTimestamp(arrayOfRows[i][3])
    542. );
    543.  
    544. // compile moonrise/moonset data
    545. moonriseMoonsetSeries[0].values.push( // push to series 0
    546. parseStringToTimestamp(arrayOfRows[i][5])
    547. );
    548. moonriseMoonsetSeries[1].values.push( // push to series 1
    549. parseStringToTimestamp(arrayOfRows[i][6])
    550. );
    551.  
    552. }
    553.  
    554.  
    555. // load data into chart
    556. zingchart.exec('myChart', 'setseriesdata', {
    557. graphid: 'azimuth_chart',
    558. update: false,
    559. data: azimuthSeries
    560. });
    561. zingchart.exec('myChart', 'setseriesdata', {
    562. graphid: 'sunrise_sunset_chart',
    563. update: false,
    564. data: sunriseSunsetSeries
    565. });
    566. zingchart.exec('myChart', 'appendseriesdata', {
    567. graphid: 'moonrise_moonset_chart',
    568. update: false,
    569. data: moonriseMoonsetSeries
    570. });
    571. zingchart.exec('myChart', 'update');
    572. }
    573.  
    574.  
    575.  
    576.  
    577.  
    578.  
    579. // request data from url
    580. var oReq = new XMLHttpRequest();
    581. oReq.addEventListener("load", parseDataAndRenderChart);
    582. oReq.open("GET", 'https://app.zingsoft.com/api/file/GSNQC6UG/xqIP1B9ZRXiOmCCmLfCU_sun_moon_rise_azimuth.csv'); // exported google sheets to csv (thats it)
    583. oReq.send();
    584.  
    585.  
    586.  
    587.  
    588.  
    589. /*
    590. * Event listener for crosshair and how to change image.
    591. * This will change the class (check CSS tab) on the div (positioned absolute over the chart)
    592. * it will update the image based on the day (nodeindex).
    593. *
    594. * eg. nodeindex 32 is february 1st
    595. */
    596. var imageContainer = null;
    597.  
    598. function bindImageOnMove(e) {
    599. // event is fired for all 3 graphs. For speed only do this once.
    600. if (e.graphid === "moonrise_moonset_chart") {
    601. // easy way to cache the reference to the element
    602. imageContainer = (imageContainer != null) ? imageContainer : document.getElementById('crosshair-image');
    603.  
    604. // used CSS modifications over chart modifcations for faster speed.
    605. imageContainer.style.left = e.guide.x + 'px';
    606.  
    607. // if node index exists for at least one plot
    608. if (e.items[0] && e.items[0].nodeindex) {
    609. switch (e.items[0].nodeindex) { // nodeindex = day
    610. case 1:
    611. case 31:
    612. case 62:
    613. imageContainer.className = "phase_1";
    614. break;
    615. case 9:
    616. case 39:
    617. case 70:
    618. imageContainer.className = "phase_2";
    619. break;
    620. case 17:
    621. case 47:
    622. case 78:
    623. imageContainer.className = "phase_3";
    624. break;
    625. case 25:
    626. case 55:
    627. case 86:
    628. imageContainer.className = "phase_4";
    629. break;
    630. default:
    631. imageContainer.className = ""; // remove image
    632. }
    633. }
    634. }
    635. }
    636.  
    637. zingchart.bind('myChart', 'guide_mousemove', bindImageOnMove);
    638. /*
    639. * since the height of the chart is dynamic in my example (can resize window for chart size),
    640. * this function is used to dynamically set the height of the moon phase image on chart load (set it once)
    641. */
    642. zingchart.bind('myChart', 'complete', function(e) {
    643. // assign tooltip to top of graph by getting the bottom charts info
    644. var graphInfo = zingchart.exec('myChart', 'getobjectinfo', {
    645. graphid: 'moonrise_moonset_chart',
    646. object: 'graph'
    647. });
    648. imageContainer = document.getElementById('crosshair-image');
    649. imageContainer.style.top = (graphInfo.y + 10) + 'px';
    650. });