市长热线演示版

index.htm 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <title>Highcharts Example</title>
  6. <script type="text/javascript" src="http://cdn.hcharts.cn/jquery/jquery-1.8.3.min.js"></script>
  7. <script type="text/javascript">
  8. /**
  9. * This is a complex demo of how to set up a Highcharts chart, coupled to a
  10. * dynamic source and extended by drawing image sprites, wind arrow paths
  11. * and a second grid on top of the chart. The purpose of the demo is to inpire
  12. * developers to go beyond the basic chart types and show how the library can
  13. * be extended programmatically. This is what the demo does:
  14. *
  15. * - Loads weather forecast from www.yr.no in form of an XML service. The XML
  16. * is translated on the Higcharts website into JSONP for the sake of the demo
  17. * being shown on both our website and JSFiddle.
  18. * - When the data arrives async, a Meteogram instance is created. We have
  19. * created the Meteogram prototype to provide an organized structure of the different
  20. * methods and subroutines associated with the demo.
  21. * - The parseYrData method parses the data from www.yr.no into several parallel arrays. These
  22. * arrays are used directly as the data option for temperature, precipitation
  23. * and air pressure. As the temperature data gives only full degrees, we apply
  24. * some smoothing on the graph, but keep the original data in the tooltip.
  25. * - After this, the options structure is build, and the chart generated with the
  26. * parsed data.
  27. * - In the callback (on chart load), we weather icons on top of the temperature series.
  28. * The icons are sprites from a single PNG image, placed inside a clipped 30x30
  29. * SVG <g> element. VML interprets this as HTML images inside a clipped div.
  30. * - Lastly, the wind arrows are built and added below the plot area, and a grid is
  31. * drawn around them. The wind arrows are basically drawn north-south, then rotated
  32. * as per the wind direction.
  33. */
  34. function Meteogram(xml, container) {
  35. // Parallel arrays for the chart data, these are populated as the XML/JSON file
  36. // is loaded
  37. this.symbols = [];
  38. this.symbolNames = [];
  39. this.precipitations = [];
  40. this.windDirections = [];
  41. this.windDirectionNames = [];
  42. this.windSpeeds = [];
  43. this.windSpeedNames = [];
  44. this.temperatures = [];
  45. this.pressures = [];
  46. // Initialize
  47. this.xml = xml;
  48. this.container = container;
  49. // Run
  50. this.parseYrData();
  51. }
  52. /**
  53. * Return weather symbol sprites as laid out at http://om.yr.no/forklaring/symbol/
  54. */
  55. Meteogram.prototype.getSymbolSprites = function (symbolSize) {
  56. return {
  57. '01d': {
  58. x: 0,
  59. y: 0
  60. },
  61. '01n': {
  62. x: symbolSize,
  63. y: 0
  64. },
  65. '16': {
  66. x: 2 * symbolSize,
  67. y: 0
  68. },
  69. '02d': {
  70. x: 0,
  71. y: symbolSize
  72. },
  73. '02n': {
  74. x: symbolSize,
  75. y: symbolSize
  76. },
  77. '03d': {
  78. x: 0,
  79. y: 2 * symbolSize
  80. },
  81. '03n': {
  82. x: symbolSize,
  83. y: 2 * symbolSize
  84. },
  85. '17': {
  86. x: 2 * symbolSize,
  87. y: 2 * symbolSize
  88. },
  89. '04': {
  90. x: 0,
  91. y: 3 * symbolSize
  92. },
  93. '05d': {
  94. x: 0,
  95. y: 4 * symbolSize
  96. },
  97. '05n': {
  98. x: symbolSize,
  99. y: 4 * symbolSize
  100. },
  101. '18': {
  102. x: 2 * symbolSize,
  103. y: 4 * symbolSize
  104. },
  105. '06d': {
  106. x: 0,
  107. y: 5 * symbolSize
  108. },
  109. '06n': {
  110. x: symbolSize,
  111. y: 5 * symbolSize
  112. },
  113. '07d': {
  114. x: 0,
  115. y: 6 * symbolSize
  116. },
  117. '07n': {
  118. x: symbolSize,
  119. y: 6 * symbolSize
  120. },
  121. '08d': {
  122. x: 0,
  123. y: 7 * symbolSize
  124. },
  125. '08n': {
  126. x: symbolSize,
  127. y: 7 * symbolSize
  128. },
  129. '19': {
  130. x: 2 * symbolSize,
  131. y: 7 * symbolSize
  132. },
  133. '09': {
  134. x: 0,
  135. y: 8 * symbolSize
  136. },
  137. '10': {
  138. x: 0,
  139. y: 9 * symbolSize
  140. },
  141. '11': {
  142. x: 0,
  143. y: 10 * symbolSize
  144. },
  145. '12': {
  146. x: 0,
  147. y: 11 * symbolSize
  148. },
  149. '13': {
  150. x: 0,
  151. y: 12 * symbolSize
  152. },
  153. '14': {
  154. x: 0,
  155. y: 13 * symbolSize
  156. },
  157. '15': {
  158. x: 0,
  159. y: 14 * symbolSize
  160. },
  161. '20d': {
  162. x: 0,
  163. y: 15 * symbolSize
  164. },
  165. '20n': {
  166. x: symbolSize,
  167. y: 15 * symbolSize
  168. },
  169. '20m': {
  170. x: 2 * symbolSize,
  171. y: 15 * symbolSize
  172. },
  173. '21d': {
  174. x: 0,
  175. y: 16 * symbolSize
  176. },
  177. '21n': {
  178. x: symbolSize,
  179. y: 16 * symbolSize
  180. },
  181. '21m': {
  182. x: 2 * symbolSize,
  183. y: 16 * symbolSize
  184. },
  185. '22': {
  186. x: 0,
  187. y: 17 * symbolSize
  188. },
  189. '23': {
  190. x: 0,
  191. y: 18 * symbolSize
  192. }
  193. };
  194. };
  195. /**
  196. * Function to smooth the temperature line. The original data provides only whole degrees,
  197. * which makes the line graph look jagged. So we apply a running mean on it, but preserve
  198. * the unaltered value in the tooltip.
  199. */
  200. Meteogram.prototype.smoothLine = function (data) {
  201. var i = data.length,
  202. sum,
  203. value;
  204. while (i--) {
  205. data[i].value = value = data[i].y; // preserve value for tooltip
  206. // Set the smoothed value to the average of the closest points, but don't allow
  207. // it to differ more than 0.5 degrees from the given value
  208. sum = (data[i - 1] || data[i]).y + value + (data[i + 1] || data[i]).y;
  209. data[i].y = Math.max(value - 0.5, Math.min(sum / 3, value + 0.5));
  210. }
  211. };
  212. /**
  213. * Callback function that is called from Highcharts on hovering each point and returns
  214. * HTML for the tooltip.
  215. */
  216. Meteogram.prototype.tooltipFormatter = function (tooltip) {
  217. // Create the header with reference to the time interval
  218. var index = tooltip.points[0].point.index,
  219. ret = '<small>' + Highcharts.dateFormat('%A, %b %e, %H:%M', tooltip.x) + '-' +
  220. Highcharts.dateFormat('%H:%M', tooltip.points[0].point.to) + '</small><br>';
  221. // Symbol text
  222. ret += '<b>' + this.symbolNames[index] + '</b>';
  223. ret += '<table>';
  224. // Add all series
  225. Highcharts.each(tooltip.points, function (point) {
  226. var series = point.series;
  227. ret += '<tr><td><span style="color:' + series.color + '">\u25CF</span> ' + series.name +
  228. ': </td><td style="white-space:nowrap">' + Highcharts.pick(point.point.value, point.y) +
  229. series.options.tooltip.valueSuffix + '</td></tr>';
  230. });
  231. // Add wind
  232. ret += '<tr><td style="vertical-align: top">\u25CF Wind</td><td style="white-space:nowrap">' + this.windDirectionNames[index] +
  233. '<br>' + this.windSpeedNames[index] + ' (' +
  234. Highcharts.numberFormat(this.windSpeeds[index], 1) + ' m/s)</td></tr>';
  235. // Close
  236. ret += '</table>';
  237. return ret;
  238. };
  239. /**
  240. * Draw the weather symbols on top of the temperature series. The symbols are sprites of a single
  241. * file, defined in the getSymbolSprites function above.
  242. */
  243. Meteogram.prototype.drawWeatherSymbols = function (chart) {
  244. var meteogram = this,
  245. symbolSprites = this.getSymbolSprites(30);
  246. $.each(chart.series[0].data, function(i, point) {
  247. var sprite,
  248. group;
  249. if (meteogram.resolution > 36e5 || i % 2 === 0) {
  250. sprite = symbolSprites[meteogram.symbols[i]];
  251. if (sprite) {
  252. // Create a group element that is positioned and clipped at 30 pixels width and height
  253. group = chart.renderer.g()
  254. .attr({
  255. translateX: point.plotX + chart.plotLeft - 15,
  256. translateY: point.plotY + chart.plotTop - 30,
  257. zIndex: 5
  258. })
  259. .clip(chart.renderer.clipRect(0, 0, 30, 30))
  260. .add();
  261. // Position the image inside it at the sprite position
  262. chart.renderer.image(
  263. 'http://www.highcharts.com/samples/graphics/meteogram-symbols-30px.png',
  264. -sprite.x,
  265. -sprite.y,
  266. 90,
  267. 570
  268. )
  269. .add(group);
  270. }
  271. }
  272. });
  273. };
  274. /**
  275. * Create wind speed symbols for the Beaufort wind scale. The symbols are rotated
  276. * around the zero centerpoint.
  277. */
  278. Meteogram.prototype.windArrow = function (name) {
  279. var level,
  280. path;
  281. // The stem and the arrow head
  282. path = [
  283. 'M', 0, 7, // base of arrow
  284. 'L', -1.5, 7,
  285. 0, 10,
  286. 1.5, 7,
  287. 0, 7,
  288. 0, -10 // top
  289. ];
  290. level = $.inArray(name, ['Calm', 'Light air', 'Light breeze', 'Gentle breeze', 'Moderate breeze',
  291. 'Fresh breeze', 'Strong breeze', 'Near gale', 'Gale', 'Strong gale', 'Storm',
  292. 'Violent storm', 'Hurricane']);
  293. if (level === 0) {
  294. path = [];
  295. }
  296. if (level === 2) {
  297. path.push('M', 0, -8, 'L', 4, -8); // short line
  298. } else if (level >= 3) {
  299. path.push(0, -10, 7, -10); // long line
  300. }
  301. if (level === 4) {
  302. path.push('M', 0, -7, 'L', 4, -7);
  303. } else if (level >= 5) {
  304. path.push('M', 0, -7, 'L', 7, -7);
  305. }
  306. if (level === 5) {
  307. path.push('M', 0, -4, 'L', 4, -4);
  308. } else if (level >= 6) {
  309. path.push('M', 0, -4, 'L', 7, -4);
  310. }
  311. if (level === 7) {
  312. path.push('M', 0, -1, 'L', 4, -1);
  313. } else if (level >= 8) {
  314. path.push('M', 0, -1, 'L', 7, -1);
  315. }
  316. return path;
  317. };
  318. /**
  319. * Draw the wind arrows. Each arrow path is generated by the windArrow function above.
  320. */
  321. Meteogram.prototype.drawWindArrows = function (chart) {
  322. var meteogram = this;
  323. $.each(chart.series[0].data, function(i, point) {
  324. var sprite, arrow, x, y;
  325. if (meteogram.resolution > 36e5 || i % 2 === 0) {
  326. // Draw the wind arrows
  327. x = point.plotX + chart.plotLeft + 7;
  328. y = 255;
  329. if (meteogram.windSpeedNames[i] === 'Calm') {
  330. arrow = chart.renderer.circle(x, y, 10).attr({
  331. fill: 'none'
  332. });
  333. } else {
  334. arrow = chart.renderer.path(
  335. meteogram.windArrow(meteogram.windSpeedNames[i])
  336. ).attr({
  337. rotation: parseInt(meteogram.windDirections[i], 10),
  338. translateX: x, // rotation center
  339. translateY: y // rotation center
  340. });
  341. }
  342. arrow.attr({
  343. stroke: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black',
  344. 'stroke-width': 1.5,
  345. zIndex: 5
  346. })
  347. .add();
  348. }
  349. });
  350. };
  351. /**
  352. * Draw blocks around wind arrows, below the plot area
  353. */
  354. Meteogram.prototype.drawBlocksForWindArrows = function (chart) {
  355. var xAxis = chart.xAxis[0],
  356. x,
  357. pos,
  358. max,
  359. isLong,
  360. isLast,
  361. i;
  362. for (pos = xAxis.min, max = xAxis.max, i = 0; pos <= max + 36e5; pos += 36e5, i ++) {
  363. // Get the X position
  364. isLast = pos === max + 36e5;
  365. x = Math.round(xAxis.toPixels(pos)) + (isLast ? 0.5 : -0.5);
  366. // Draw the vertical dividers and ticks
  367. if (this.resolution > 36e5) {
  368. isLong = pos % this.resolution === 0;
  369. } else {
  370. isLong = i % 2 === 0;
  371. }
  372. chart.renderer.path(['M', x, chart.plotTop + chart.plotHeight + (isLong ? 0 : 28),
  373. 'L', x, chart.plotTop + chart.plotHeight + 32, 'Z'])
  374. .attr({
  375. 'stroke': chart.options.chart.plotBorderColor,
  376. 'stroke-width': 1
  377. })
  378. .add();
  379. }
  380. };
  381. /**
  382. * Get the title based on the XML data
  383. */
  384. Meteogram.prototype.getTitle = function () {
  385. return 'Meteogram for '+ this.xml.location.name +', '+ this.xml.location.country;
  386. };
  387. /**
  388. * Build and return the Highcharts options structure
  389. */
  390. Meteogram.prototype.getChartOptions = function () {
  391. var meteogram = this;
  392. return {
  393. chart: {
  394. renderTo: this.container,
  395. marginBottom: 70,
  396. marginRight: 40,
  397. marginTop: 50,
  398. plotBorderWidth: 1,
  399. width: 800,
  400. height: 310
  401. },
  402. title: {
  403. text: this.getTitle(),
  404. align: 'left'
  405. },
  406. credits: {
  407. text: 'Forecast from <a href="http://yr.no">yr.no</a>',
  408. href: this.xml.credit.link['@attributes'].url,
  409. position: {
  410. x: -40
  411. }
  412. },
  413. tooltip: {
  414. shared: true,
  415. useHTML: true,
  416. formatter: function () {
  417. return meteogram.tooltipFormatter(this);
  418. }
  419. },
  420. xAxis: [{ // Bottom X axis
  421. type: 'datetime',
  422. tickInterval: 2 * 36e5, // two hours
  423. minorTickInterval: 36e5, // one hour
  424. tickLength: 0,
  425. gridLineWidth: 1,
  426. gridLineColor: (Highcharts.theme && Highcharts.theme.background2) || '#F0F0F0',
  427. startOnTick: false,
  428. endOnTick: false,
  429. minPadding: 0,
  430. maxPadding: 0,
  431. offset: 30,
  432. showLastLabel: true,
  433. labels: {
  434. format: '{value:%H}'
  435. }
  436. }, { // Top X axis
  437. linkedTo: 0,
  438. type: 'datetime',
  439. tickInterval: 24 * 3600 * 1000,
  440. labels: {
  441. format: '{value:<span style="font-size: 12px; font-weight: bold">%a</span> %b %e}',
  442. align: 'left',
  443. x: 3,
  444. y: -5
  445. },
  446. opposite: true,
  447. tickLength: 20,
  448. gridLineWidth: 1
  449. }],
  450. yAxis: [{ // temperature axis
  451. title: {
  452. text: null
  453. },
  454. labels: {
  455. format: '{value}°',
  456. style: {
  457. fontSize: '10px'
  458. },
  459. x: -3
  460. },
  461. plotLines: [{ // zero plane
  462. value: 0,
  463. color: '#BBBBBB',
  464. width: 1,
  465. zIndex: 2
  466. }],
  467. // Custom positioner to provide even temperature ticks from top down
  468. tickPositioner: function () {
  469. var max = Math.ceil(this.max) + 1,
  470. pos = max - 12, // start
  471. ret;
  472. if (pos < this.min) {
  473. ret = [];
  474. while (pos <= max) {
  475. ret.push(pos++);
  476. }
  477. } // else return undefined and go auto
  478. return ret;
  479. },
  480. maxPadding: 0.3,
  481. tickInterval: 1,
  482. gridLineColor: (Highcharts.theme && Highcharts.theme.background2) || '#F0F0F0'
  483. }, { // precipitation axis
  484. title: {
  485. text: null
  486. },
  487. labels: {
  488. enabled: false
  489. },
  490. gridLineWidth: 0,
  491. tickLength: 0
  492. }, { // Air pressure
  493. allowDecimals: false,
  494. title: { // Title on top of axis
  495. text: 'hPa',
  496. offset: 0,
  497. align: 'high',
  498. rotation: 0,
  499. style: {
  500. fontSize: '10px',
  501. color: Highcharts.getOptions().colors[2]
  502. },
  503. textAlign: 'left',
  504. x: 3
  505. },
  506. labels: {
  507. style: {
  508. fontSize: '8px',
  509. color: Highcharts.getOptions().colors[2]
  510. },
  511. y: 2,
  512. x: 3
  513. },
  514. gridLineWidth: 0,
  515. opposite: true,
  516. showLastLabel: false
  517. }],
  518. legend: {
  519. enabled: false
  520. },
  521. plotOptions: {
  522. series: {
  523. pointPlacement: 'between'
  524. }
  525. },
  526. series: [{
  527. name: 'Temperature',
  528. data: this.temperatures,
  529. type: 'spline',
  530. marker: {
  531. enabled: false,
  532. states: {
  533. hover: {
  534. enabled: true
  535. }
  536. }
  537. },
  538. tooltip: {
  539. valueSuffix: '°C'
  540. },
  541. zIndex: 1,
  542. color: '#FF3333',
  543. negativeColor: '#48AFE8'
  544. }, {
  545. name: 'Precipitation',
  546. data: this.precipitations,
  547. type: 'column',
  548. color: '#68CFE8',
  549. yAxis: 1,
  550. groupPadding: 0,
  551. pointPadding: 0,
  552. borderWidth: 0,
  553. shadow: false,
  554. dataLabels: {
  555. enabled: true,
  556. formatter: function () {
  557. if (this.y > 0) {
  558. return this.y;
  559. }
  560. },
  561. style: {
  562. fontSize: '8px'
  563. }
  564. },
  565. tooltip: {
  566. valueSuffix: 'mm'
  567. }
  568. }, {
  569. name: 'Air pressure',
  570. color: Highcharts.getOptions().colors[2],
  571. data: this.pressures,
  572. marker: {
  573. enabled: false
  574. },
  575. shadow: false,
  576. tooltip: {
  577. valueSuffix: ' hPa'
  578. },
  579. dashStyle: 'shortdot',
  580. yAxis: 2
  581. }]
  582. }
  583. };
  584. /**
  585. * Post-process the chart from the callback function, the second argument to Highcharts.Chart.
  586. */
  587. Meteogram.prototype.onChartLoad = function (chart) {
  588. this.drawWeatherSymbols(chart);
  589. this.drawWindArrows(chart);
  590. this.drawBlocksForWindArrows(chart);
  591. };
  592. /**
  593. * Create the chart. This function is called async when the data file is loaded and parsed.
  594. */
  595. Meteogram.prototype.createChart = function () {
  596. var meteogram = this;
  597. this.chart = new Highcharts.Chart(this.getChartOptions(), function (chart) {
  598. meteogram.onChartLoad(chart);
  599. });
  600. };
  601. /**
  602. * Handle the data. This part of the code is not Highcharts specific, but deals with yr.no's
  603. * specific data format
  604. */
  605. Meteogram.prototype.parseYrData = function () {
  606. var meteogram = this,
  607. xml = this.xml,
  608. pointStart;
  609. if (!xml || !xml.forecast) {
  610. $('#loading').html('<i class="fa fa-frown-o"></i> Failed loading data, please try again later');
  611. return;
  612. }
  613. // The returned xml variable is a JavaScript representation of the provided XML,
  614. // generated on the server by running PHP simple_load_xml and converting it to
  615. // JavaScript by json_encode.
  616. $.each(xml.forecast.tabular.time, function(i, time) {
  617. // Get the times - only Safari can't parse ISO8601 so we need to do some replacements
  618. var from = time['@attributes'].from +' UTC',
  619. to = time['@attributes'].to +' UTC';
  620. from = from.replace(/-/g, '/').replace('T', ' ');
  621. from = Date.parse(from);
  622. to = to.replace(/-/g, '/').replace('T', ' ');
  623. to = Date.parse(to);
  624. if (to > pointStart + 4 * 24 * 36e5) {
  625. return;
  626. }
  627. // If it is more than an hour between points, show all symbols
  628. if (i === 0) {
  629. meteogram.resolution = to - from;
  630. }
  631. // Populate the parallel arrays
  632. meteogram.symbols.push(time.symbol['@attributes']['var'].match(/[0-9]{2}[dnm]?/)[0]);
  633. meteogram.symbolNames.push(time.symbol['@attributes'].name);
  634. meteogram.temperatures.push({
  635. x: from,
  636. y: parseInt(time.temperature['@attributes'].value),
  637. // custom options used in the tooltip formatter
  638. to: to,
  639. index: i
  640. });
  641. meteogram.precipitations.push({
  642. x: from,
  643. y: parseFloat(time.precipitation['@attributes'].value)
  644. });
  645. meteogram.windDirections.push(parseFloat(time.windDirection['@attributes'].deg));
  646. meteogram.windDirectionNames.push(time.windDirection['@attributes'].name);
  647. meteogram.windSpeeds.push(parseFloat(time.windSpeed['@attributes'].mps));
  648. meteogram.windSpeedNames.push(time.windSpeed['@attributes'].name);
  649. meteogram.pressures.push({
  650. x: from,
  651. y: parseFloat(time.pressure['@attributes'].value)
  652. });
  653. if (i == 0) {
  654. pointStart = (from + to) / 2;
  655. }
  656. });
  657. // Smooth the line
  658. this.smoothLine(this.temperatures);
  659. // Create the chart when the data is loaded
  660. this.createChart();
  661. };
  662. // End of the Meteogram protype
  663. $(function() { // On DOM ready...
  664. // Set the hash to the yr.no URL we want to parse
  665. if (!location.hash) {
  666. var place = 'United_Kingdom/England/London';
  667. //place = 'France/Rhône-Alpes/Val_d\'Isère~2971074';
  668. //place = 'Norway/Sogn_og_Fjordane/Vik/Målset';
  669. //place = 'United_States/California/San_Francisco';
  670. //place = 'United_States/Minnesota/Minneapolis';
  671. location.hash = 'http://www.yr.no/place/' + place + '/forecast_hour_by_hour.xml';
  672. }
  673. // Then get the XML file through Highcharts' jsonp provider, see
  674. // https://github.com/highslide-software/highcharts.com/blob/master/samples/data/jsonp.php
  675. // for source code.
  676. $.getJSON(
  677. 'http://www.highcharts.com/samples/data/jsonp.php?url=' + location.hash.substr(1) + '&callback=?',
  678. function (xml) {
  679. var meteogram = new Meteogram(xml, 'container');
  680. }
  681. );
  682. });
  683. </script>
  684. </head>
  685. <body>
  686. <script src="../../js/highcharts.js"></script>
  687. <script src="../../js/modules/exporting.js"></script>
  688. <link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
  689. <div id="container" style="width: 800px; height: 310px; margin: 0 auto">
  690. <div style="margin-top: 100px; text-align: center" id="loading">
  691. <i class="fa fa-spinner fa-spin"></i> Loading data from external source
  692. </div>
  693. </div>
  694. <!--
  695. <div style="width: 800px; margin: 0 auto">
  696. <a href="#http://www.yr.no/place/United_Kingdom/England/London/forecast_hour_by_hour.xml">London</a>,
  697. <a href="#http://www.yr.no/place/France/Rhône-Alpes/Val_d\'Isère~2971074/forecast_hour_by_hour.xml">Val d'Isère</a>,
  698. <a href="#http://www.yr.no/place/United_States/California/San_Francisco/forecast_hour_by_hour.xml">San Francisco</a>,
  699. <a href="#http://www.yr.no/place/Norway/Vik/Vikafjell/forecast_hour_by_hour.xml">Vikjafjellet</a>
  700. </div>
  701. -->
  702. </body>
  703. </html>