Ero sivun ”Widget:Ol3CurObsMapICE” versioiden välillä
Järvi-meriwikistä
Rivi 1: | Rivi 1: | ||
− | <includeonly> | + | <includeonly> |
− | + | <script type="text/javascript"> | |
− | + | (function() { | |
− | |||
− | |||
− | |||
− | + | // globals | |
+ | var today = new Date(); | ||
− | + | function <!--{$id|default:TheGraph|escape:'html'}-->_jQueryTest() { | |
− | + | if ( typeof window.jQuery == 'undefined' ) { | |
− | + | setTimeout( function(){ <!--{$id|default:TheGraph|escape:'html'}-->_jQueryTest() }, 300); | |
− | + | } else { | |
+ | <!--{$id|default:TheGraph|escape:'html'}-->_func(); | ||
+ | } | ||
+ | } | ||
+ | setTimeout( function(){ <!--{$id|default:TheGraph|escape:'html'}-->_jQueryTest() }, 300); | ||
− | + | function <!--{$id|default:TheGraph|escape:'html'}-->_func() { | |
− | + | css_link = jQuery( "<link>", { rel: "stylesheet", type: "text/css", href: "//www.jarviwiki.fi/embed/css/obschart.css?ver=1" }); | |
− | + | css_link.appendTo('head'); | |
− | + | jQuery.getScript( "//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js", function() { | |
− | + | jQuery.getScript( "//www.jarviwiki.fi/citobsjs/jwapi.js", function() { | |
+ | jQuery.getScript( '//www.gstatic.com/charts/loader.js', function() { | ||
+ | google.charts.load( 'current', { 'packages':[ 'corechart' ] } ); | ||
+ | google.charts.setOnLoadCallback( loadObservations ); | ||
+ | }); | ||
+ | }); | ||
+ | }); | ||
+ | } | ||
− | + | function loadObservations() { | |
− | |||
− | + | jQuery( '.jwChartWidget' ).each( function() { | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | var memo = {}; | |
− | + | memo.widgetEl = jQuery( this ); | |
− | + | memo.lang = memo.widgetEl.attr( 'data-lang' ); if (typeof memo.lang == 'undefined') { memo.lang = 'fi'; } | |
− | + | memo.height = memo.widgetEl.attr( 'data-height' ); if (typeof memo.height == 'undefined') { memo.height = 450; } | |
− | |||
− | + | memo.siteid = jQuery( this ).attr( 'data-jw-siteid' ); | |
− | + | memo.obscode = jQuery( this ).attr( 'data-jw-obscode' ); | |
− | + | memo.obscodeParts = memo.obscode.split('_'); | |
− | + | memo.service = jQuery( this ).attr( 'data-coo311-service_code' ); | |
− | + | memo.graphType = jQuery( this ).attr( 'data-graph-type' ); | |
− | + | memo.editUrl = jQuery( this ).attr( 'data-edit-url' ); if (typeof memo.editUrl == 'undefined') { memo.editUrl = '-'; } | |
+ | memo.csvfile = jQuery( this ).attr( 'data-csv-filename' ); if (typeof memo.csvfile == 'undefined') { memo.csvfile = i18n[ memo.obscode ].title[ memo.lang ] + '_SiteID-' + memo.siteid + '_Downloaded-' + today.toISOString().split( 'T' )[0] + '.csv'; } | ||
+ | if ( typeof jQuery( this ).attr( 'data-maintainer' ) == 'undefined' ) { memo.maintainerShow = false; } | ||
+ | else { memo.maintainerShow = ( jQuery( this ).attr( 'data-maintainer' ).toLowerCase() == 'true' ); } | ||
+ | memo.id = jQuery( this ).attr( 'id' ); if (typeof memo.id == 'undefined') { memo.id = 'jwsitegraph_' + Math.random() + '_container'; jQuery( this ).attr( 'id', memo.id ); } | ||
− | + | memo.widgetEl.css( 'position', 'relative' ); | |
− | + | ||
− | + | // add loader animation | |
− | + | //memo.widgetEl.append( '<div style="display: none;" class="jwloading"></div>' ); | |
− | + | //memo.loaderEl = jQuery( this ).find( '.jwloading' ); | |
− | + | //memo.loaderEl.fadeIn( "slow" ); | |
− | + | ||
− | + | // add chart container | |
− | + | //memo.widgetEl.append( '<div class="card JwCard mb-2" style="position: relative; width: 100%; height: 100%;"><div class="card-header">Otsikko</div><div class="card-body" style="position: relative; width: 100%; height: 350px;"><div class="chart-container" style="position: relative; z-index: 110; width: 100%; height: 100%;"></div></div><div class="card-footer">footer</div></div>' ); | |
− | ' | + | memo.widgetEl.append( '<div class="card JwCard mb-2" style="position: relative; width: 100%; height: 100%;"><div class="card-header"></div><div class="card-body p-2" style="position: relative; width: 100%; height: 350px;"><div class="chart-container" style="position: relative; z-index: 110; width: 100%; height: 100%;"></div></div></div>' ); |
− | + | //memo.widgetEl.append( '<div class="chart-container" style="position: absolute; z-index: 110; width: 100%; height: 100%;"></div>' ); | |
− | + | memo.chartEl = jQuery( this ).find( '.chart-container' ); | |
− | + | memo.headerEl = jQuery( this ).find( '.card-header' ); | |
− | + | ||
− | + | // add title | |
− | ' | + | memo.headerEl.append( '<div class="obscharttitle" style="Xdisplay: none; float: left;"></div>' ); |
− | + | memo.titleEl = jQuery( this ).find( '.obscharttitle' ); | |
− | + | ||
− | + | // add fullscreen button | |
− | ' | + | memo.headerEl.append( '<div class="obschartbutton fullscreen-button" style="display: none; margin-left: 10px; float: right; Xbackground-color: rgba( 255, 255, 255, 1 ); border-radius: 50%; Xborder: 1px solid rgba( 0, 0, 0, 0.5 ); Xpadding: 1px;"><button title="' + i18n['fullscreen'][memo.lang] + '" style="width: 24px; height: 24px; padding: 0; margin: 0; color: #1B599B; background: none; border: none; "><i class="fas fa-expand"></i></button></div>' ); |
− | + | memo.fullscreenEl = jQuery( this ).find( '.fullscreen-button' ); | |
− | + | ||
+ | // add edit button | ||
+ | if ( memo.editUrl != '-' ) { | ||
+ | memo.headerEl.append( '<div class="obschartbutton edit-button" style="Xdisplay: none; margin-left: 10px; float: right; Xbackground-color: rgba( 255, 255, 255, 1 ); border-radius: 50%; Xborder: 1px solid rgba( 0, 0, 0, 0.5 ); Xpadding: 1px;"><button title="' + i18n['edit'][memo.lang] + '" style="width: 24px; height: 24px; padding: 0; margin: 0; color: #1B599B; background: none; border: none;"><i class="fas fa-edit"></i></button></div>' ); | ||
+ | memo.editEl = jQuery( this ).find( '.edit-button' ); | ||
+ | } | ||
+ | |||
+ | // add download data button | ||
+ | memo.headerEl.append( '<div class="obschartbutton download-button" style="display: none; margin-left: 10px; float: right; Xbackground-color: rgba( 255, 255, 255, 1 ); border-radius: 50%; Xborder: 1px solid rgba( 0, 0, 0, 0.5 ); Xpadding: 1px;"><button title="' + i18n['download'][memo.lang] + '" style="width: 24px; height: 24px; padding: 0; margin: 0; color: #1B599B; background: none; border: none;"><i class="fas fa-download"></i></button></div>' ); | ||
+ | memo.downloadEl = jQuery( this ).find( '.download-button' ); | ||
+ | |||
+ | memo.loadStarts = 0; | ||
+ | memo.obses = {}; | ||
+ | memo.seriesO = {}; | ||
+ | memo.trendlinesO = {}; | ||
+ | |||
+ | memo.vaxisdir = 1; if (memo.obscode == 'secchi') { memo.vaxisdir = -1; } | ||
+ | |||
+ | memo.showAverage = ( jQuery( this ).attr( 'data-show-average' ) != 'false' ); | ||
+ | memo.showTrend = ( jQuery( this ).attr( 'data-show-trend' ) != 'false' ); | ||
+ | |||
+ | memo.trendType = jQuery( this ).attr( 'data-trend-type' ); if (typeof memo.trendType == 'undefined') { memo.trendType = i18n[memo.obscode]['trend']['type']; } | ||
+ | |||
+ | //memo.titleEl.html( i18n[ memo.obscode ].title[ memo.lang ] ); | ||
+ | |||
+ | //getJWobses(memo); | ||
+ | //getCOO311obses(memo); | ||
+ | |||
+ | memo.jw = new jwApi(); | ||
+ | |||
+ | var custom = ''; | ||
+ | if ( typeof memo.obscodeParts[1] != 'undefined' ) { | ||
+ | if ( typeof memo.obscodeParts[2] != 'undefined' ) { | ||
+ | custom += '[[' + i18n[memo.obscodeParts[0]].catName + '::' + memo.obscodeParts[2].split(',').join('||') +']]'; | ||
+ | } else { | ||
+ | custom += '[[' + i18n[memo.obscode].catName + '::>0]]'; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | memo.jw.loadObses( { 'obscode': memo.obscodeParts[0], 'siteid': memo.siteid, 'custom': custom }, function( o ) { | ||
+ | memo.obses = memo.jw.obs; | ||
+ | drawVisualization(memo); | ||
+ | }); | ||
+ | |||
+ | //https://www.jarviwiki.fi/wiki/Toiminnot:Lomakemuokkaus/ObsICE/V%C3%A4lij%C3%A4rvi_(74.021.1.051)/Luikonsaari | ||
+ | |||
+ | }); | ||
+ | } | ||
+ | |||
+ | function drawVisualization( memo ) { | ||
+ | |||
+ | if ( typeof i18n[ memo.obscode ].direction != 'undefined' ) { memo.vaxisdir = i18n[ memo.obscode ].direction; } else { memo.vaxisdir = 1; } | ||
+ | |||
+ | // defaults for all charts | ||
+ | memo.options = { | ||
+ | backgroundColor: 'transparent', | ||
+ | chartArea: { backgroundColor: { fill: '#ffffff', 'd': '#daf0fa', stroke: '#ccc', strokeWidth: 6 }}, | ||
+ | legend: { position: 'bottom' }, | ||
+ | crosshair: { trigger: 'both' }, | ||
+ | tooltip: { isHtml: true }, | ||
+ | seriesType: 'scatter', | ||
+ | interpolateNulls: true, | ||
+ | vAxis: { | ||
+ | title: i18n[memo.obscode]['axisTitleV'][memo.lang], | ||
+ | titleTextStyle: { bold: true }, | ||
+ | slantedText: false, | ||
+ | maxAlternation: 1, | ||
+ | direction: memo.vaxisdir, | ||
+ | gridlines: { color: '#eee', count: -1 }, | ||
+ | minorGridlines: { count: 0 }, | ||
+ | viewWindow: { } | ||
+ | }, | ||
+ | hAxis: { | ||
+ | title: '', | ||
+ | slantedText: false, | ||
+ | maxAlternation: 1, | ||
+ | gridlines: { color: '#eee' }, | ||
+ | minorGridlines: { count: 0 }, | ||
+ | viewWindow: { } | ||
+ | }, | ||
+ | series: [ ], | ||
+ | trendlines: [ ] | ||
+ | }; | ||
+ | |||
+ | memo.obsesTotal = 0; | ||
+ | |||
+ | memo.obsMinValue = Infinity; | ||
+ | memo.obsMaxValue = -Infinity; | ||
+ | memo.obsMinDateMs = Infinity; | ||
+ | memo.obsMaxDateMs = -Infinity; | ||
+ | memo.obsMinCompDateMs = Infinity; | ||
+ | memo.obsMaxCompDateMs = -Infinity; | ||
+ | |||
+ | memo.season = i18n[memo.obscode]['season']; | ||
+ | if ( memo.season == 'summer' || today.getMonth() > 7 ) { | ||
+ | memo.curSeason = today.getFullYear(); | ||
+ | } else { | ||
+ | memo.curSeason = today.getFullYear()-1; | ||
+ | } | ||
+ | |||
+ | // first loop | ||
+ | for ( var o in memo.obses ) { | ||
+ | |||
+ | obs = memo.obses[o]; | ||
+ | |||
+ | memo.obsesTotal++; | ||
+ | |||
+ | // create data | ||
+ | obs.data = JSON.parse( obs.printouts.DataJSON ); | ||
+ | |||
+ | // add season | ||
+ | if ( memo.season == 'winter' && obs.obsdatetime.getMonth() > -1 && obs.obsdatetime.getMonth() < 8 ) { | ||
+ | obs.season = obs.obsdatetime.getFullYear()-1; | ||
+ | } else { | ||
+ | obs.season = obs.obsdatetime.getFullYear(); | ||
+ | } | ||
+ | if ( memo.season == 'winter' ) { | ||
+ | obs.seasonmiddle = new Date( obs.season+1, 0, 1 ); | ||
+ | } else { | ||
+ | obs.seasonmiddle = new Date( obs.season, 5, 1 ); | ||
+ | } | ||
+ | |||
+ | // create addinfo | ||
+ | obs.addInfo = ""; | ||
+ | if ( !!obs.media_url ) { | ||
+ | obs.img = new Image(); | ||
+ | obs.img.src = obs.media_url; | ||
+ | obs.addInfo = '<img style="max-width: 196px; max-height: 196px;" src="' + obs.media_url + '" />'; | ||
+ | } | ||
+ | if ( !!obs.printouts[ 'Lisätiedot' ][0] ) { | ||
+ | obs.addInfo += '<p>' + obs.printouts[ 'Lisätiedot' ][0] + '</p>'; | ||
+ | } | ||
+ | |||
+ | memo.obsMinValue = Math.min( memo.obsMinValue, obs.value ); | ||
+ | memo.obsMaxValue = Math.max( memo.obsMaxValue, obs.value ); | ||
+ | |||
+ | memo.obsMinDateMs = Math.min( memo.obsMinDateMs, obs.obsdatetime.getTime() ); | ||
+ | memo.obsMaxDateMs = Math.max( memo.obsMaxDateMs, obs.obsdatetime.getTime() ); | ||
+ | |||
+ | // add compare date to obses | ||
+ | if ( memo.season == 'summer' || obs.obsdatetime.getMonth() > 7 ) { | ||
+ | obs.compareDate = new Date( memo.curSeason, obs.obsdatetime.getMonth(), obs.obsdatetime.getDate() ); | ||
+ | } else { | ||
+ | obs.compareDate = new Date( memo.curSeason+1, obs.obsdatetime.getMonth(), obs.obsdatetime.getDate() ); | ||
+ | } | ||
+ | ms = obs.compareDate.getTime(); | ||
+ | memo.obsMinCompDateMs = Math.min(ms, memo.obsMinCompDateMs); | ||
+ | memo.obsMaxCompDateMs = Math.max(ms, memo.obsMaxCompDateMs); | ||
+ | |||
+ | // add series id | ||
+ | if ( memo.graphType == 'trend' ) { | ||
+ | obs.seriesId = 0; | ||
+ | } else if ( memo.graphType == 'dateofyear' ) { | ||
+ | obs.seriesId = memo.obscodeParts[0] + '_cat_' + obs.data.cat; | ||
+ | } else if ( memo.season == 'summer' || obs.obsdatetime.getMonth() > 7 ) { | ||
+ | obs.seriesId = obs.obsdatetime.getFullYear(); | ||
+ | } else { | ||
+ | obs.seriesId = obs.obsdatetime.getFullYear()-1; | ||
+ | } | ||
+ | |||
+ | // create popup for obs | ||
+ | obs.popup = '<div style="padding: 8px;">'; | ||
+ | obs.popup += '<div>'; | ||
+ | |||
+ | if ( i18n[memo.obscode]['type'] == 'cat') { | ||
+ | obs.popup +='<b>' + i18n[memo.obscode]['title'][memo.lang] + ': ' + i18n[memo.obscode]['catNames'][obs.value][memo.lang] + '</b> '; | ||
+ | } else if ( i18n[memo.obscode]['type'] == 'date') { | ||
+ | obs.popup +='<b>' + i18n[memo.obscode]['title'][memo.lang] + '</b> '; | ||
+ | } else { | ||
+ | obs.popup +='<b>' + i18n[memo.obscode]['title'][memo.lang] + ': ' + (Math.round(obs.value * 10)/10).toString().replace( '.', i18n['dec'][memo.lang] ) + ' ' + i18n[memo.obscode]['unit'] + '</b> '; | ||
+ | } | ||
+ | |||
+ | obs.popup += '(' + obs.obsdatetime.inRelationToToday(memo.lang) + ')'; | ||
+ | obs.popup += '</div>'; | ||
+ | |||
+ | if (!!obs.addInfo) { | ||
+ | obs.popup += '<div style="margin-top: 5px;">' + obs.addInfo + '</div>'; | ||
+ | } | ||
+ | obs.popup += '</div>'; | ||
+ | |||
+ | } | ||
+ | |||
+ | memo.obsMinDate = new Date( memo.obsMinDateMs ); | ||
+ | memo.obsMaxDate = new Date( memo.obsMaxDateMs ); | ||
+ | memo.obsMinYear = memo.obsMinDate.getFullYear(); | ||
+ | memo.obsMaxYear = memo.obsMaxDate.getFullYear(); | ||
+ | memo.obsMinCompDate = new Date( memo.obsMinCompDateMs ); | ||
+ | memo.obsMaxCompDate = new Date( memo.obsMaxCompDateMs ); | ||
+ | |||
+ | memo.obsesA = []; memo.dataA = []; | ||
+ | |||
+ | for ( var o in memo.obses ) { | ||
+ | |||
+ | obs = memo.obses[o]; | ||
+ | |||
+ | // style points | ||
+ | if ( obs.seriesId == memo.curSeason ) { | ||
+ | baseSize = 6; | ||
+ | } else if (memo.obsesTotal < 100) { | ||
+ | baseSize = 4; | ||
+ | } else if (memo.obsesTotal < 200) { | ||
+ | baseSize = 3; | ||
+ | } else if (memo.obsesTotal < 300) { | ||
+ | baseSize = 2; | ||
+ | } else { | ||
+ | baseSize = 2; | ||
+ | } | ||
+ | |||
+ | //if ( memo.graphType == 'dateofyear' ) { baseSize = baseSize + 1; } | ||
+ | |||
+ | if ( memo.maintainerShow ) { maintcol = maintColors[obs.maintainer]; } | ||
+ | else { maintcol = 'transparent'; } | ||
+ | |||
+ | if (!!obs.addInfo) { | ||
+ | obs.style = 'point { shape-type: star; size: ' + (baseSize+3) + '; shape-dent: 0.5; stroke-width: 0; stroke-color: ' + maintcol + '; }'; | ||
+ | } else { | ||
+ | obs.style = 'point { size: ' + baseSize + '; stroke-width: 0.5; stroke-color: ' + maintcol + '; }'; | ||
+ | } | ||
+ | |||
+ | memo.obsesA.push( obs ); | ||
+ | |||
+ | } | ||
+ | |||
+ | // sort | ||
+ | memo.obsesA.sort( function(a, b) { return a.obsdatetime - b.obsdatetime; }); | ||
+ | |||
+ | // create DataTable | ||
+ | memo.data = new google.visualization.DataTable(); | ||
+ | |||
+ | // col for xAxis values | ||
+ | memo.data.addColumn( 'date', 'time' ); | ||
+ | |||
+ | // make ticks for y axis on cat types | ||
+ | if ( i18n[memo.obscode]['type'] == 'cat') { | ||
+ | memo.options.vAxis.ticks = []; | ||
+ | for (var c in i18n[memo.obscode]['catNamesShort']) { | ||
+ | memo.options.vAxis.ticks.push({v: parseInt(c), f: i18n[memo.obscode]['catNamesShort'][c][memo.lang] }); | ||
+ | memo.options.vAxis.ticks.push({v: parseInt(c)+0.5, f: '' }); | ||
+ | } | ||
+ | memo.options.vAxis.ticks.sort( function(a, b) { return a.v-b.v } ); | ||
+ | memo.options.vAxis.viewWindow = { min: -0.5, max: parseInt(memo.options.vAxis.ticks[memo.options.vAxis.ticks.length-1].v)+0.5 }; | ||
+ | memo.options.vAxis.gridlines.color = '#eee'; | ||
+ | memo.options.vAxis.baselineColor = 'none'; | ||
+ | } else if ( typeof i18n[memo.obscode]['min'] != 'undefined' ) { | ||
+ | memo.options.vAxis.viewWindow = { min: i18n[memo.obscode]['min'] }; | ||
+ | } else if ( memo.obsMinValue >= 0) { | ||
+ | memo.options.vAxis.viewWindow = { min: 0 }; | ||
+ | } | ||
+ | |||
+ | memo.titleEl.html( i18n[ memo.obscode ].title[ memo.lang ] ); | ||
+ | memo.titleEl.append( ' <button style="padding: 0 0.25em; font-size: 13px; margin-bottom: 3px;" type="button" class="btn btn-secondary btn-info" data-toggle="tooltip" data-placement="top" title="' + i18n[ memo.obscode ].changes[ memo.lang ] + '">' + i18n[ 'new' ][ memo.lang ] + '</button>' ); | ||
+ | jQuery( '[data-toggle="tooltip"]' ).tooltip(); | ||
+ | |||
+ | if (memo.graphType == 'trend') { | ||
+ | |||
+ | addDataToTrendChart(memo); | ||
+ | |||
+ | } else if (memo.graphType == 'season') { | ||
+ | |||
+ | addDataToSeasonChart(memo); | ||
+ | |||
+ | } else if (memo.graphType == 'dateofyear') { | ||
+ | |||
+ | addDataToDateOfYearChart( memo ); | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | function addDataToDateOfYearChart( memo ) { | ||
+ | |||
+ | // do X axis min and max for this chart type | ||
+ | memo.options.hAxis.minValue = new Date( memo.obsMinDateMs ); | ||
+ | if ( memo.season = 'winter' && memo.options.hAxis.minValue.getMonth() < 8 ) { memo.options.hAxis.minValue.setFullYear( memo.options.hAxis.minValue.getFullYear()-1 ); } | ||
+ | memo.options.hAxis.minValue.setMonth(0); | ||
+ | memo.options.hAxis.minValue.setDate(1); | ||
+ | memo.options.hAxis.viewWindow.min = memo.options.hAxis.minValue; | ||
+ | |||
+ | memo.options.hAxis.maxValue = new Date( memo.obsMaxDateMs ); | ||
+ | if ( memo.season = 'winter' && memo.options.hAxis.maxValue.getMonth() > 7 ) { memo.options.hAxis.maxValue.setFullYear( memo.options.hAxis.maxValue.getFullYear()+1 ); } | ||
+ | else { memo.options.hAxis.maxValue.setFullYear( memo.options.hAxis.maxValue.getFullYear()+1 ); } | ||
+ | memo.options.hAxis.maxValue.setMonth(11); | ||
+ | memo.options.hAxis.maxValue.setDate(31); | ||
+ | memo.options.hAxis.viewWindow.max = memo.options.hAxis.maxValue; | ||
+ | |||
+ | // do Y axis min and max for this chart type | ||
+ | memo.options.vAxis.minValue = new Date( memo.obsMinCompDate.getTime() ); | ||
+ | memo.options.vAxis.minValue.setDate(1); | ||
+ | memo.options.vAxis.viewWindow.min = memo.options.vAxis.minValue; | ||
+ | |||
+ | memo.options.vAxis.maxValue = new Date( memo.obsMaxCompDate.getTime() ); | ||
+ | memo.options.vAxis.maxValue.setMonth( memo.options.vAxis.maxValue.getMonth()+1 ); | ||
+ | memo.options.vAxis.maxValue.setDate(0); | ||
+ | memo.options.vAxis.viewWindow.max = memo.options.vAxis.maxValue; | ||
+ | |||
+ | // do Y axis ticks and gridlines | ||
+ | memo.options.vAxis.ticks = []; | ||
+ | memo.vAxisGridlines = []; | ||
+ | memo.options.vAxis.gridlines = { color: 'transparent' }; | ||
+ | memo.options.vAxis.minorGridlines = { color: 'transparent' }; | ||
+ | minM = memo.options.vAxis.minValue.getMonth(); | ||
+ | maxM = memo.options.vAxis.maxValue.getMonth(); | ||
+ | |||
+ | if ( minM > maxM ) { mc = 13-minM+maxM; } | ||
+ | else { mc = maxM-minM+1; } | ||
+ | |||
+ | for ( mi = 0; mi < mc; mi++ ) { | ||
+ | |||
+ | mx = minM+mi; | ||
+ | yx = memo.options.vAxis.minValue.getFullYear(); | ||
+ | if ( mx > 11 ) { yx = memo.options.vAxis.maxValue.getFullYear(); mx = mx - 12; } | ||
+ | |||
+ | startOfMonth = new Date( yx, mx, 1 ); | ||
+ | middleOfMonth = new Date( yx, mx, 15 ); | ||
+ | |||
+ | // ticks | ||
+ | memo.options.vAxis.ticks.push( { v: middleOfMonth, f: i18n['months'][mx]['long'][memo.lang] } ); | ||
+ | |||
+ | // gridlines except for first | ||
+ | if (mi > 0) { | ||
+ | memo.vAxisGridlines.push( new Date( startOfMonth.getTime() ) ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | memo.seriesO = {}; | ||
+ | |||
+ | for ( var o in memo.obsesA ) { | ||
+ | obs = memo.obsesA[ o ]; | ||
+ | s = obs.seriesId; | ||
+ | if ( typeof memo.seriesO[ s ] == 'undefined' ) { | ||
+ | memo.seriesO[ s ] = { 'id': s, 'order': parseInt( obs.data.cat ), 'title': i18n[ s ].title[ memo.lang ], 'type': 'scatter', 'color': i18n[ s ].color, 'obses': [] }; | ||
+ | } | ||
+ | obs.xvalue = obs.seasonmiddle; | ||
+ | obs.yvalue = obs.compareDate; | ||
+ | obs.value = obs.obsdatetime.toLocaleDateString( memo.lang ); | ||
+ | obs.valueUnit = i18n[ 'Date' ][ memo.lang ]; | ||
+ | obs.tooltip = '<p><b>' + i18n[ 'season' ][ 'winter' ][ memo.lang ] + ' ' + obs.season + '–' + (obs.season+1) + '</b></p>'; | ||
+ | obs.tooltip += '<p>' + i18n[ s ].title2[ memo.lang ] + ': ' + obs.obsdatetime.toLocaleDateString( memo.lang ) + '</p>'; | ||
+ | obs.tooltip += obs.addInfo; | ||
+ | memo.seriesO[ s ].obses.push( obs ); | ||
+ | } | ||
+ | |||
+ | // create ice cover series | ||
+ | if ( memo.obscode == 'ice_cat_2,5' ) { | ||
+ | memo.obsesS = {}; | ||
+ | for ( var o in memo.obsesA ) { | ||
+ | var obs = memo.obsesA[ o ]; | ||
+ | |||
+ | if ( typeof memo.obsesS[ obs.season ] == 'undefined' ) { | ||
+ | memo.obsesS[ obs.season ] = { 'maintainer': obs.maintainer }; | ||
+ | } | ||
+ | |||
+ | if ( obs.data.cat == '2' ) { | ||
+ | memo.obsesS[ obs.season ][ 'low' ] = obs.compareDate; | ||
+ | } else if ( obs.data.cat == '5' ) { | ||
+ | memo.obsesS[ obs.season ][ 'high' ] = obs.compareDate; | ||
+ | } | ||
+ | if ( memo.obsesS[ obs.season ][ 'maintainer' ] != obs.maintainer ) { memo.obsesS[ obs.season ][ 'maintainer' ] = ''; } | ||
+ | |||
+ | if ( typeof memo.obsesS[ obs.season ][ 'low' ] != 'undefined' && typeof memo.obsesS[ obs.season ][ 'high' ] != 'undefined' ) { | ||
+ | days = Math.round( ( memo.obsesS[ obs.season ][ 'high' ].getTime() - memo.obsesS[ obs.season ][ 'low' ].getTime() ) / ( 1000*60*60*24 ) ); | ||
+ | if ( typeof memo.seriesO[ 'ice_cat_2,5' ] == 'undefined' ) { | ||
+ | memo.seriesO[ 'ice_cat_2,5' ] = { 'id': 'ice_cat_2,5', 'order': 10, 'title': i18n[ 'ice_cat_2,5' ].title[ memo.lang ], 'type': 'candlestick', 'color': i18n[ 'ice_cat_2,5' ].color, obses: [] }; | ||
+ | } | ||
+ | memo.seriesO[ 'ice_cat_2,5' ].obses.push( { 'obsdatetime': obs.obsdatetime, 'season': obs.season, 'value': days, 'valueUnit': i18n[ 'days' ][ memo.lang ], 'addInfo': '', 'maintainer': memo.obsesS[ obs.season ][ 'maintainer' ], 'xvalue': obs.seasonmiddle, 'low': memo.obsesS[ obs.season ][ 'low' ], 'high': memo.obsesS[ obs.season ][ 'high' ], 'tooltip': '<p><b>' + i18n[ 'season' ][ 'winter' ][ memo.lang ] + ' ' + obs.season + '–' + (obs.season+1) + '</b></p><p>' + i18n[ 'ice_cat_2,5' ].title[ memo.lang ] + ': ' + days + ' ' + i18n[ 'days' ][ memo.lang ] + '</p>' } ); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | memo.seriesA = []; for ( var s in memo.seriesO ) { memo.seriesA.push( memo.seriesO[s] ) }; | ||
+ | memo.seriesA.sort( function( a, b ) { return a.order-b.order; } ); | ||
+ | |||
+ | for ( var s in memo.seriesA ) { | ||
+ | |||
+ | if ( memo.seriesA[ s ].type == 'scatter' ) { | ||
+ | |||
+ | memo.data.addColumn( 'date', memo.seriesA[ s ].title ); // + ' ' + memo.obsMinYear + '-' + memo.obsMaxYear ); | ||
+ | memo.data.addColumn( { type: 'string', 'role': 'style' } ); | ||
+ | memo.data.addColumn( { type: 'string', role: 'tooltip', 'p': { 'html': true } } ); | ||
+ | memo.data.addColumn( { type: 'string', role: 'annotation' } ); | ||
+ | |||
+ | memo.options.series.push( { type: 'scatter', pointType: 'circle', pointSize: 9, color: memo.seriesA[ s ].color } ); | ||
+ | |||
+ | if ( memo.seriesA[ s ].obses.length > 1 ) { | ||
+ | memo.options.trendlines[ memo.options.series.length - 1 ] = { type: 'linear', title: i18n.trendline, lineWidth: 2.33, visibleInLegend: false, tooltip: false }; | ||
+ | } else { | ||
+ | memo.options.trendlines[ memo.options.series.length - 1 ] = { type: 'linear', title: i18n.trendline, lineWidth: 0, color: 'transparent', visibleInLegend: false, tooltip: false }; | ||
+ | } | ||
+ | |||
+ | } else if ( memo.seriesA[ s ].type == 'candlestick' ) { | ||
+ | |||
+ | memo.data.addColumn( 'date', memo.seriesA[ s ].title ); | ||
+ | memo.data.addColumn( 'date', '' ); | ||
+ | memo.data.addColumn( 'date', '' ); | ||
+ | memo.data.addColumn( 'date', '' ); | ||
+ | memo.data.addColumn({ role: 'tooltip', 'p': { 'html': true } }); | ||
+ | |||
+ | memo.options.series.push( { type: 'candlesticks', color: memo.seriesA[ s ].color, strokeWidth: 2, stroke: '#cccccc' } ); | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | // add data to table | ||
+ | cc = memo.data.getNumberOfColumns(); | ||
+ | var st = 0; | ||
+ | for ( var s in memo.seriesA ) { | ||
+ | |||
+ | for ( var o in memo.seriesA[ s ].obses ) { | ||
+ | |||
+ | obs = memo.seriesA[ s ].obses[ o ]; | ||
+ | |||
+ | dataRow = []; | ||
+ | |||
+ | // fill row with nulls | ||
+ | for ( var i=0; i<cc; i++ ) { dataRow.push( null ); } | ||
+ | |||
+ | // x axis value | ||
+ | dataRow[ 0 ] = obs.xvalue; | ||
+ | |||
+ | if ( memo.seriesA[ s ].type == 'candlestick' ) { | ||
+ | |||
+ | dataRow[ st+1 ] = obs.low; | ||
+ | dataRow[ st+2 ] = obs.low; | ||
+ | dataRow[ st+3 ] = obs.high; | ||
+ | dataRow[ st+4 ] = obs.high; | ||
+ | dataRow[ st+5 ] = obs.tooltip; | ||
+ | |||
+ | } else if ( memo.seriesA[ s ].type == 'scatter' ) { | ||
+ | |||
+ | dataRow[ st+1 ] = obs.yvalue; | ||
+ | dataRow[ st+2 ] = obs.style; | ||
+ | dataRow[ st+3 ] = obs.tooltip; | ||
+ | dataRow[ st+4 ] = null; | ||
+ | } | ||
+ | |||
+ | memo.dataA.push( dataRow ); | ||
+ | |||
+ | } | ||
+ | |||
+ | if ( memo.seriesA[ s ].type == 'candlestick' ) { | ||
+ | st += 5; | ||
+ | } else if ( memo.seriesA[ s ].type == 'scatter' ) { | ||
+ | st += 4; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | /* | ||
+ | // linear trend line | ||
+ | //memo.options.trendlines[0] = { labelInLegend: i18n['trendline'][memo.lang], tooltip: false, color: colors['trend'], lineWidth: 2, opacity: 0.5, type: 'linear', visibleInLegend: memo.trendType!='moving' }; | ||
+ | |||
+ | // data columns for vAxis gridlines | ||
+ | for (g=0; g < memo.vAxisGridlines.length; g++) { | ||
+ | memo.data.addColumn( 'date', 'vAxis gridline_' + g ); | ||
+ | memo.options.series[g+1] = { type: 'line', pointSize: 0, lineWidth: 1, color: '#eee', XlineDashStyle: [3, 3], visibleInLegend: false }; | ||
+ | } | ||
+ | |||
+ | |||
+ | // add gridlines | ||
+ | for (g=0; g < memo.vAxisGridlines.length; g++) { | ||
+ | |||
+ | dataRow1 = []; | ||
+ | dataRow2 = []; | ||
+ | |||
+ | // fill rows with nulls | ||
+ | for (var i=0; i<noc; i++) { dataRow1.push( null ); dataRow2.push( null ); } | ||
+ | |||
+ | dataRow1[0] = memo.options.hAxis.minValue; | ||
+ | dataRow2[0] = memo.options.hAxis.maxValue; | ||
+ | |||
+ | dataRow1[5+g] = memo.vAxisGridlines[g]; | ||
+ | dataRow2[5+g] = memo.vAxisGridlines[g]; | ||
+ | |||
+ | memo.dataA.push( dataRow1 ); | ||
+ | memo.dataA.push( dataRow2 ); | ||
+ | } | ||
+ | */ | ||
+ | |||
+ | drawChart(memo); | ||
+ | |||
+ | } | ||
+ | |||
+ | function addDataToTrendChart(memo) { | ||
+ | |||
+ | // do axis min and max | ||
+ | memo.axisMinDate = new Date(memo.obsMinDate.getTime()); | ||
+ | memo.axisMaxDate = new Date(memo.obsMaxDate.getTime()); | ||
+ | memo.axisMinDate.setMonth(0); | ||
+ | memo.axisMaxDate.setMonth(11); | ||
+ | memo.axisMinDate.setDate(1); | ||
+ | memo.axisMaxDate.setDate(31); | ||
+ | |||
+ | memo.data.addColumn( 'number', memo.obsMinYear + '-' + memo.obsMaxYear ); | ||
+ | memo.data.addColumn( {'type': 'string', 'role': 'style' } ); | ||
+ | memo.data.addColumn( { type: 'string', role: 'annotation' } ); | ||
+ | memo.data.addColumn( { type: 'string', role: 'tooltip', 'p': { 'html': true } } ); | ||
+ | |||
+ | // series for trend line | ||
+ | memo.options.trendlines[0] = { labelInLegend: i18n['trendline'][memo.lang], tooltip: false, color: colors['trend'], lineWidth: 2, opacity: 0.5, type: 'linear', visibleInLegend: memo.trendType!='moving' }; | ||
+ | |||
+ | |||
+ | for (var o in memo.obsesA) { | ||
+ | |||
+ | //dataRow = []; | ||
+ | |||
+ | //if (!!memo.obsesA[o].addInfo) { | ||
+ | //dataArr.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, 0, memo.obsesA[o].value, memo.obsesA[o].value, 'point { size: 5; fill-color: #0076b0; stroke-width: 2; stroke-color: ' + maintColors[memo.obsesA[o].maintainer] + '; }', '', memo.obsesA[o].popup ] ); | ||
+ | //memo.dataA.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, 'point { size: 5; fill-color: #0076b0; stroke-width: 2; stroke-color: ' + maintColors[memo.obsesA[o].maintainer] + '; }', null, memo.obsesA[o].popup ] ); | ||
+ | memo.dataA.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, memo.obsesA[o].style, null, memo.obsesA[o].popup ] ); | ||
+ | //} else { | ||
+ | //dataArr.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, 0, memo.obsesA[o].value, memo.obsesA[o].value, 'point { size: 4; fill-color: #5893b0; stroke-width: 2; stroke-color: ' + maintColors[memo.obsesA[o].maintainer] + '; }', '', memo.obsesA[o].popup ] ); | ||
+ | //memo.dataA.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, 'point { size: 4; fill-color: #5893b0; stroke-width: 2; stroke-color: ' + maintColors[memo.obsesA[o].maintainer] + '; }', null, memo.obsesA[o].popup ] ); | ||
+ | //} | ||
+ | |||
+ | //memo.dataA.push( dataRow ); | ||
+ | |||
+ | } | ||
+ | |||
+ | memo.options.hAxis.ticks = []; | ||
+ | for (i=memo.axisMinDate.getFullYear(); i<=memo.axisMaxDate.getFullYear(); i++) { | ||
+ | middleOfYear = new Date( i, 6, 1 ); | ||
+ | memo.options.hAxis.ticks.push({v: middleOfYear, f: String(i) }); | ||
+ | } | ||
+ | |||
+ | memo.options.series[0] = {type: 'scatter', pointSize: 6, color: '#3366cc' }; | ||
+ | |||
+ | drawChart(memo); | ||
+ | |||
+ | } | ||
+ | |||
+ | function addDataToSeasonChart(memo) { | ||
+ | |||
+ | memo.axisMinDate = new Date( memo.obsMinCompDateMs ); | ||
+ | memo.axisMinDate.setDate(1); | ||
+ | memo.axisMaxDate = new Date( memo.obsMaxCompDateMs ); | ||
+ | memo.axisMaxDate.setMonth( memo.axisMaxDate.getMonth()+1 ); | ||
+ | memo.axisMaxDate.setDate(0); | ||
+ | |||
+ | memo.seasonsO = {}; | ||
+ | memo.seasonsA = []; | ||
+ | |||
+ | for (var o in memo.obsesA) { | ||
+ | |||
+ | s = memo.obsesA[o].seriesId; | ||
+ | if (typeof memo.seasonsO[s] == 'undefined' ) { memo.seasonsO[s] = { 'obses': [] }; } | ||
+ | memo.seasonsO[s].obses.push( memo.obsesA[o] ); | ||
+ | } | ||
+ | |||
+ | for (var o in memo.seasonsO) { memo.seasonsA.push(o); } memo.seasonsA.sort( function(a,b) { return b-a; } ); | ||
+ | |||
+ | // create cols for each series | ||
+ | var sc = 0; | ||
+ | for (var s in memo.seasonsA) { | ||
+ | |||
+ | // data | ||
+ | if ( memo.season == 'summer' ) { | ||
+ | memo.data.addColumn( 'number', memo.seasonsA[s].toString() ); | ||
+ | } else { | ||
+ | memo.data.addColumn( 'number', memo.seasonsA[s].toString() + '-' + (parseInt(memo.seasonsA[s])+1).toString() ); | ||
+ | } | ||
+ | // style | ||
+ | memo.data.addColumn( { type: 'string', role: 'style' } ); | ||
+ | // tooltip | ||
+ | memo.data.addColumn( { type: 'string', role: 'tooltip', 'p': { 'html': true } } ); | ||
+ | // annotation | ||
+ | memo.data.addColumn( { type: 'string', role: 'annotation' } ); | ||
+ | |||
+ | // add to series | ||
+ | if ( memo.seasonsA[s] == memo.curSeason ) { | ||
+ | if ( memo.type == 'cat' ) { | ||
+ | memo.options.series[sc++] = { type: 'scatter', curveType: 'function', color: colors['curObses'], XpointSize: 3, lineWidth: 0, visibleInLegend: true, hideThis: false, origSize: 10 }; | ||
+ | } else { | ||
+ | memo.options.series[sc++] = { type: 'scatter', curveType: 'function', color: colors['curObses'], XpointSize: 3, lineWidth: 4, visibleInLegend: true, hideThis: false, origSize: 10 }; | ||
+ | } | ||
+ | } else { | ||
+ | memo.options.series[sc++] = { type: 'scatter', curveType: 'function', color: colors['obses'], XpointSize: 5, lineWidth: 0, visibleInLegend: false, hideThis: true, origSize: 5 }; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // legend entry for timespan | ||
+ | memo.data.addColumn( 'number', memo.obsMinDate.getFullYear() + '-' + memo.obsMaxDate.getFullYear() ); | ||
+ | memo.options.series[sc++] = { type: 'scatter', color: colors['obses'], pointSize: 5, visibleInLegend: true, hideThis: false }; | ||
+ | |||
+ | // series for average | ||
+ | memo.data.addColumn( 'number', i18n['average'][memo.lang] ); | ||
+ | |||
+ | if ( i18n[memo.obscode].trend.layout == 'area') { | ||
+ | memo.options.series[sc++] = { type: 'area', curveType: 'function', lineWidth: 2, pointSize: 0, color: colors['average'], areaOpacity: 0.25, lineDashStyle: [2,2], enableInteractivity: false, visibleInLegend: memo.trendType=='moving' }; | ||
+ | } else { | ||
+ | memo.options.series[sc++] = { type: 'line', curveType: 'function', lineWidth: 3, pointSize: 5, color: colors['average'], dataOpacity: 0.75, lineDashStyle: [6,3], enableInteractivity: false, visibleInLegend: memo.trendType=='moving' }; | ||
+ | } | ||
+ | |||
+ | memo.data.addColumn( { id: 'dev', type: 'number', role: 'interval' } ); | ||
+ | memo.data.addColumn( { id: 'dev', type: 'number', role: 'interval' } ); | ||
+ | |||
+ | // series for trend line | ||
+ | memo.data.addColumn( 'number', 'trend' ); | ||
+ | //memo.options.trendlines[sc] = { labelInLegend: i18n['trendline'][memo.lang], tooltip: false, color: colors['trend'], lineWidth: 2, opacity: 0.5, type: 'polynomial', degree: 15, visibleInLegend: memo.trendType!='moving' }; | ||
+ | memo.options.series[sc++] = { type: 'scatter', pointSize: 0, enableInteractivity: false, visibleInLegend: false, hideThis: false }; | ||
+ | |||
+ | // do average | ||
+ | if (memo.trendType == 'gaussian') { | ||
+ | |||
+ | memo.gSmoothing = 4; | ||
+ | if ( i18n[memo.obscode]['type'] == 'cat') { | ||
+ | memo.distF = 0.1; | ||
+ | } else { | ||
+ | memo.distF = 0; | ||
+ | } | ||
+ | |||
+ | // sort according to compare date | ||
+ | memo.obsesA.sort( function( a, b ) { return a.compareDate - b.compareDate; }); | ||
+ | |||
+ | // make week averages | ||
+ | memo.avgW = {}; | ||
+ | for (var o in memo.obsesA) { | ||
+ | |||
+ | mwDate = new Date( memo.obsesA[o].compareDate.getFullYear(), memo.obsesA[o].compareDate.getMonth(), memo.obsesA[o].compareDate.getDate() ); | ||
+ | y = mwDate.getFullYear(); | ||
+ | w = mwDate.getWeek(); | ||
+ | v = memo.obsesA[o].value + memo.distF*Math.random() - memo.distF*Math.random(); | ||
+ | |||
+ | if ( typeof memo.avgW[y] == 'undefined' ) { memo.avgW[y] = {}; } | ||
+ | |||
+ | if ( typeof memo.avgW[y][w] == 'undefined' ) { | ||
+ | mwDate.setDate( mwDate.getDate() - mwDate.getDay() + 3 ) | ||
+ | memo.avgW[y][w] = { cDate: mwDate, values: [ v ], sum: v, count: 1, avg: v }; | ||
+ | } else { | ||
+ | memo.avgW[y][w].values.push( v ); | ||
+ | memo.avgW[y][w].sum += v; | ||
+ | memo.avgW[y][w].count++; | ||
+ | memo.avgW[y][w].avg = memo.avgW[y][w].sum / memo.avgW[y][w].count; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //console.log(memo.avgW); | ||
+ | |||
+ | // calculate standard deviation | ||
+ | devSum = 0; | ||
+ | devC = 0; | ||
+ | devMax = 0; | ||
+ | for ( var y in memo.avgW ) { | ||
+ | for ( var w in memo.avgW[y] ) { | ||
+ | devC++; | ||
+ | devx = 0; | ||
+ | for (var vi in memo.avgW[y][w].values ) { | ||
+ | devx += Math.pow( (memo.avgW[y][w].values[vi] - memo.avgW[y][w].avg), 2 ); | ||
+ | } | ||
+ | memo.avgW[y][w].dev = Math.sqrt( devx/memo.avgW[y][w].count ); | ||
+ | devSum += memo.avgW[y][w].dev; | ||
+ | devMax = Math.max( memo.avgW[y][w].dev, devMax ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | devAvg = devSum/devC; | ||
+ | |||
+ | for ( var y in memo.avgW ) { | ||
+ | for ( var w in memo.avgW[y] ) { | ||
+ | if ( memo.avgW[y][w].count < 5 ) { | ||
+ | //memo.avgW[y][w].dev = Math.max( memo.avgW[y][w].dev, devAvg ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | memo.avgWlist = []; | ||
+ | |||
+ | for ( var y in memo.avgW ) { | ||
+ | for ( var w in memo.avgW[y] ) { | ||
+ | memo.avgWlist.push( { y: parseInt(y), w: parseInt(w), avg: memo.avgW[y][w].avg, dev: memo.avgW[y][w].dev } ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | memo.avgWlist.sort( function(a, b) { return (a.y*100+a.w) - (b.y*100+b.w); }); | ||
+ | |||
+ | //console.log(memo.avgWlist); | ||
+ | |||
+ | firstY = memo.avgWlist[0].y; | ||
+ | firstW = memo.avgWlist[0].w; | ||
+ | lastY = memo.avgWlist[memo.avgWlist.length-1].y; | ||
+ | lastW = memo.avgWlist[memo.avgWlist.length-1].w; | ||
+ | |||
+ | memo.avgMlist = []; | ||
+ | memo.avgLlist = []; | ||
+ | memo.avgHlist = []; | ||
+ | |||
+ | for ( var y=firstY; y<=lastY; y++ ) { | ||
+ | |||
+ | if ( y == firstY ) { w1 = firstW; } | ||
+ | else { w1 = 1; } | ||
+ | |||
+ | if ( y == lastY ) { w2 = lastW; } | ||
+ | else { w2 = 52; } | ||
+ | |||
+ | for ( var w=w1; w<=w2; w++) { | ||
+ | |||
+ | //console.log( y + '/' + w ); | ||
+ | |||
+ | if ( typeof(memo.avgW[y][w]) == 'undefined' ) { | ||
+ | |||
+ | memo.avgMlist.push( null ); | ||
+ | memo.avgLlist.push( null ); | ||
+ | memo.avgHlist.push( null ); | ||
+ | |||
+ | |||
+ | } else { | ||
+ | memo.avgMlist.push( memo.avgW[y][w].avg ); | ||
+ | |||
+ | if ( memo.avgW[y][w].count < 2 ) { | ||
+ | d = Math.max( devMax, memo.avgW[y][w].dev ); | ||
+ | } else if ( memo.avgW[y][w].count < 4 ) { | ||
+ | d = Math.max( devAvg, memo.avgW[y][w].dev ); | ||
+ | } else { | ||
+ | d = memo.avgW[y][w].dev; | ||
+ | } | ||
+ | |||
+ | if ( i18n[memo.obscode].type == 'cat' && ( memo.avgW[y][w].avg - 2*memo.avgW[y][w].dev ) < -memo.distF ) { | ||
+ | memo.avgLlist.push( -memo.distF*Math.random()*2 ); | ||
+ | } else { | ||
+ | memo.avgLlist.push( memo.avgW[y][w].avg - 2*d ); //memo.avgW[y][w].dev ); | ||
+ | } | ||
+ | |||
+ | memo.avgHlist.push( memo.avgW[y][w].avg + 2*d ); //memo.avgW[y][w].dev ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //console.log(memo.avgMlist); | ||
+ | |||
+ | for ( var i=0; i<memo.avgMlist.length; i++ ) { | ||
+ | |||
+ | if ( memo.avgMlist[i] === null ) { | ||
+ | |||
+ | lastM = memo.avgMlist[i-1]; | ||
+ | lastL = memo.avgLlist[i-1]; | ||
+ | lastH = memo.avgHlist[i-1]; | ||
+ | |||
+ | for ( var ix=(i+1); ix < memo.avgMlist.length; ix++ ) { | ||
+ | |||
+ | if ( memo.avgMlist[ix] !== null ) { | ||
+ | |||
+ | memo.avgMlist[i] = lastM + (memo.avgMlist[ix]-lastM) / (ix-i+1); | ||
+ | memo.avgLlist[i] = lastL + (memo.avgLlist[ix]-lastL) / (ix-i+1); | ||
+ | memo.avgHlist[i] = lastH + (memo.avgHlist[ix]-lastH) / (ix-i+1); | ||
+ | |||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //console.log(memo.avgMlist); | ||
+ | |||
+ | // if full year | ||
+ | if ( memo.avgMlist.length >= 52 ) { | ||
+ | |||
+ | memo.avgMlist = memo.avgMlist.slice( memo.avgMlist.length - memo.gSmoothing/2 - 2 ).concat( memo.avgMlist ).concat( memo.avgMlist.slice( 0, memo.gSmoothing/2 + 2 ) ); | ||
+ | memo.avgLlist = memo.avgLlist.slice( memo.avgLlist.length - memo.gSmoothing/2 - 2 ).concat( memo.avgLlist ).concat( memo.avgLlist.slice( 0, memo.gSmoothing/2 + 2 ) ); | ||
+ | memo.avgHlist = memo.avgHlist.slice( memo.avgHlist.length - memo.gSmoothing/2 - 2 ).concat( memo.avgHlist ).concat( memo.avgHlist.slice( 0, memo.gSmoothing/2 + 2 ) ); | ||
+ | |||
+ | } else { | ||
+ | |||
+ | for (var x=0; x < ( memo.gSmoothing/2 + 3 ); x++) { | ||
+ | |||
+ | if ( memo.obscode == 'secchi' ) { | ||
+ | prev = Math.max ( memo.avgMlist[0], 0 ); | ||
+ | next = Math.max ( memo.avgMlist[memo.avgMlist.length-1], 0 ); | ||
+ | } else { | ||
+ | prev = Math.max ( 2 * memo.avgMlist[0] - memo.avgMlist[1], 0 ); | ||
+ | next = Math.max ( 2 * memo.avgMlist[memo.avgMlist.length-1] - memo.avgMlist[memo.avgMlist.length-2], 0 ); | ||
+ | } | ||
+ | |||
+ | memo.avgMlist.unshift( prev ); | ||
+ | memo.avgMlist.push( next ); | ||
+ | |||
+ | memo.avgLlist.unshift( prev - 2 * devAvg ); | ||
+ | memo.avgLlist.push( next - 2 * devAvg ); | ||
+ | |||
+ | memo.avgHlist.unshift( prev + 2 * devAvg ); | ||
+ | memo.avgHlist.push( next + 2 * devAvg ); | ||
+ | |||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | memo.avgMsmooth = smooth( memo.avgMlist, memo.gSmoothing ); | ||
+ | memo.avgLsmooth = smooth( memo.avgLlist, memo.gSmoothing ); | ||
+ | memo.avgHsmooth = smooth( memo.avgHlist, memo.gSmoothing ); | ||
+ | |||
+ | |||
+ | //console.log(memo.avgMlist); | ||
+ | //console.log(memo.avgLsmooth); | ||
+ | |||
+ | cc = memo.data.getNumberOfColumns(); | ||
+ | |||
+ | msW = 7*24*60*60*1000; | ||
+ | |||
+ | for ( var i=0; i < ( memo.avgMsmooth.length ); i++ ) { | ||
+ | |||
+ | // put data into dataArr | ||
+ | dataRow = []; | ||
+ | for (var e=0; e<cc; e++) { dataRow.push( null ); } | ||
+ | |||
+ | dataRow[0] = new Date( memo.avgW[firstY][firstW].cDate.getTime() + (i - 1)*msW ); | ||
+ | |||
+ | //dataRow[cc-4] = memo.avgMlist[i]; | ||
+ | |||
+ | dataRow[cc-4] = memo.avgMsmooth[i]; | ||
+ | dataRow[cc-3] = memo.avgLsmooth[i]; | ||
+ | dataRow[cc-2] = memo.avgHsmooth[i]; | ||
+ | |||
+ | //dataRow[cc-3] = Math.min( memo.avgLsmooth[i], memo.avgMlist[i+memo.gSmoothing/2+2] ); | ||
+ | //dataRow[cc-2] = Math.max( memo.avgHsmooth[i], memo.avgMlist[i+1] ); | ||
+ | |||
+ | memo.dataA.push( dataRow ); | ||
+ | } | ||
+ | |||
+ | memo.options.intervals = { 'style':'area' }; | ||
+ | |||
+ | |||
+ | //console.log(memo.dataA); | ||
+ | |||
+ | } else if (memo.trendType == 'moving') { | ||
+ | |||
+ | // | ||
+ | } | ||
+ | |||
+ | // add data to table | ||
+ | cc = memo.data.getNumberOfColumns(); | ||
+ | for (var s in memo.seasonsA) { | ||
+ | |||
+ | for (var o in memo.seasonsO[memo.seasonsA[s]].obses) { | ||
+ | |||
+ | obs = memo.seasonsO[memo.seasonsA[s]].obses[o]; | ||
+ | |||
+ | dataRow = []; | ||
+ | |||
+ | // fill row with nulls | ||
+ | for (var i=0; i<cc; i++) { dataRow.push( null ); } | ||
+ | |||
+ | // x axis value | ||
+ | dataRow[0] = obs.compareDate; | ||
+ | |||
+ | // data for series cols | ||
+ | if ( memo.seasonsA[s] == memo.curSeason ) { | ||
+ | dataRow[s*4+1] = obs.value; | ||
+ | } else { | ||
+ | dataRow[s*4+1] = obs.value + memo.distF*Math.random() - memo.distF*Math.random(); | ||
+ | } | ||
+ | dataRow[s*4+2] = obs.style; | ||
+ | dataRow[s*4+3] = obs.popup; | ||
+ | dataRow[s*4+4] = null; //annotation | ||
+ | |||
+ | memo.dataA.push( dataRow ); | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | // make ticks for x axis | ||
+ | |||
+ | var minM = memo.axisMinDate.getMonth(); | ||
+ | var minY = memo.axisMinDate.getFullYear(); | ||
+ | var maxM = memo.axisMaxDate.getMonth(); | ||
+ | |||
+ | if (maxM < minM) { | ||
+ | mCount = 13 - minM + maxM; // 13-10+4 = 1+4 | ||
+ | } else { | ||
+ | mCount = maxM - minM + 1; | ||
+ | } | ||
+ | |||
+ | memo.options.hAxis.viewWindow.min = memo.axisMinDate; | ||
+ | memo.options.hAxis.viewWindow.max = memo.axisMaxDate; | ||
+ | memo.options.hAxis.ticks = []; | ||
+ | |||
+ | for (i=0; i<mCount; i++) { | ||
+ | |||
+ | m = minM + i; | ||
+ | maxY = minY; | ||
+ | |||
+ | if (m > 11) { | ||
+ | m = minM + i - 12; | ||
+ | maxY++; | ||
+ | } | ||
+ | |||
+ | middleOfMonth = new Date( maxY, m, 16 ); | ||
+ | |||
+ | if (mCount < 5) { | ||
+ | memo.options.hAxis.ticks.push({v: middleOfMonth, f: i18n.months[m]['long'][memo.lang] }); | ||
+ | } else if ( mCount < 10 ) { | ||
+ | memo.options.hAxis.ticks.push({v: middleOfMonth, f: i18n.months[m]['short'][memo.lang] }); | ||
+ | } else { | ||
+ | memo.options.hAxis.ticks.push({v: middleOfMonth, f: i18n.months[m]['roman'] }); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | drawChart(memo); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | function drawChart(memo) { | ||
+ | |||
+ | if (memo.dataA.length > 0) { | ||
+ | |||
+ | memo.data.addRows(memo.dataA); | ||
+ | |||
+ | memo.chart = new google.visualization.ComboChart( memo.chartEl[0] ); // document.getElementById(memo.id) | ||
+ | |||
+ | //doResize(); | ||
+ | |||
+ | memo.fullscreenEl.fadeIn( "slow" ); | ||
+ | memo.downloadEl.fadeIn( "slow" ); | ||
+ | |||
+ | memo.selectedCol = 0; | ||
+ | google.visualization.events.addListener( memo.chart, 'select', function () { | ||
+ | |||
+ | var selection = memo.chart.getSelection(); | ||
+ | |||
+ | if (selection.length > 0) { | ||
+ | |||
+ | var col = selection[0].column; | ||
+ | |||
+ | for (var c in memo.options.series) { | ||
+ | if (memo.options.series[c].hideThis) { | ||
+ | memo.options.series[c].lineWidth = 0; | ||
+ | //memo.options.series[c].pointSize = memo.options.series[c].origSize; | ||
+ | memo.options.series[c].color = colors['obses']; | ||
+ | memo.options.series[c].visibleInLegend = false; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (col != memo.selectedCol && memo.options.series[(col-1)/4].hideThis) { | ||
+ | memo.selectedCol = col; | ||
+ | memo.options.series[(col-1)/4].lineWidth = 3; | ||
+ | //memo.options.series[(col-1)/4].pointSize = 12; | ||
+ | memo.options.series[(col-1)/4].color = colors['selObses']; | ||
+ | memo.options.series[(col-1)/4].visibleInLegend = true; | ||
+ | } else { | ||
+ | memo.selectedCol = 0; | ||
+ | } | ||
+ | |||
+ | } else { | ||
+ | |||
+ | memo.selectedCol = 0; | ||
+ | |||
+ | for (var c in memo.options.series) { | ||
+ | if (memo.options.series[c].hideThis) { | ||
+ | memo.options.series[c].lineWidth = 0; | ||
+ | //memo.options.series[c].pointSize = memo.options.series[c].origSize; | ||
+ | memo.options.series[c].color = colors['obses']; | ||
+ | memo.options.series[c].visibleInLegend = false; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | //doResize(); | ||
+ | |||
+ | }); | ||
+ | |||
+ | memo.editEl.on( 'click', function() { | ||
+ | |||
+ | window.location.href = memo.editUrl; | ||
+ | |||
+ | }); | ||
+ | |||
+ | memo.fullscreenEl.on( 'click', function() { | ||
+ | |||
+ | var elem = memo.widgetEl[0]; | ||
+ | |||
+ | if (!!document.fullscreenElement) { | ||
+ | |||
+ | //memo.options.chartArea = { top: memo.margins.top, left: memo.margins.left, width: (memo.widgetEl.width() - memo.margins.left - memo.margins.right), height: (memo.widgetEl.height() - memo.margins.top - memo.margins.bottom), backgroundColor: { fill: '#daf0fa', stroke: '#fff', strokeWidth: 6 }}; | ||
+ | |||
+ | if (document.exitFullscreen) { | ||
+ | document.exitFullscreen(); | ||
+ | } else if (document.mozCancelFullScreen) { /* Firefox */ | ||
+ | document.mozCancelFullScreen(); | ||
+ | } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ | ||
+ | document.webkitExitFullscreen(); | ||
+ | } else if (document.msExitFullscreen) { /* IE/Edge */ | ||
+ | document.msExitFullscreen(); | ||
+ | } | ||
+ | |||
+ | memo.fullscreenEl.find( 'button' ).html( '<i class="fas fa-expand"></i>' ); | ||
+ | |||
+ | } else { | ||
+ | |||
+ | if (elem.requestFullscreen) { | ||
+ | elem.requestFullscreen(); | ||
+ | } else if (elem.mozRequestFullScreen) { /* Firefox */ | ||
+ | elem.mozRequestFullScreen(); | ||
+ | } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ | ||
+ | elem.webkitRequestFullscreen(); | ||
+ | } else if (elem.msRequestFullscreen) { /* IE/Edge */ | ||
+ | elem.msRequestFullscreen(); | ||
+ | } | ||
+ | |||
+ | memo.fullscreenEl.find( 'button' ).html( '<i class="fas fa-compress"></i>' ); | ||
+ | |||
+ | } | ||
+ | |||
+ | //doResize(); | ||
+ | }); | ||
+ | |||
+ | memo.downloadEl.on( 'click', function() { | ||
+ | |||
+ | var header = ''; | ||
+ | header += '\uFEFF'; // BOM | ||
+ | var csv = ''; | ||
+ | //csv += '\r\nsep=,\r\n'; | ||
+ | |||
+ | var headerCols = []; | ||
+ | var csvCols = []; | ||
+ | |||
+ | if ( i18n[memo.obscode].type == 'num' ) { | ||
+ | |||
+ | //headerCols.push( i18n[ 'Date' ][ memo.lang ] ); | ||
+ | //headerCols.push( i18n[ 'Date' ][ memo.lang ] ); | ||
+ | headerCols.push( '"' + i18n[memo.obscode].axisTitleV[memo.lang] + '"' ); | ||
+ | headerCols.push( 'Lisätiedot' ); | ||
+ | headerCols.push( 'Valokuva' ); | ||
+ | headerCols.push( 'Havainnoijan status' ); | ||
+ | |||
+ | header += headerCols.join( i18n['sep'][memo.lang] ); | ||
+ | |||
+ | for ( var o in memo.obses ) { | ||
+ | |||
+ | csvCols = []; | ||
+ | |||
+ | csvCols.push( memo.obses[o].obsdatetime.getFullYear() + '-' + ( memo.obses[o].obsdatetime.getMonth() + 1 ) + '-' + memo.obses[o].obsdatetime.getDate() ); | ||
+ | |||
+ | if ( memo.obses[o].obsdatetime.getUTCHours() == 0 && memo.obses[o].obsdatetime.getUTCMinutes() == 0 && memo.obses[o].obsdatetime.getUTCSeconds() == 0 ) { | ||
+ | csvCols.push( '' ); | ||
+ | } else { | ||
+ | csvCols.push( ( "0" + memo.obses[o].obsdatetime.getUTCHours() ).slice(-2) + ':' + ( "0" + memo.obses[o].obsdatetime.getUTCMinutes() ).slice(-2) ); | ||
+ | } | ||
+ | |||
+ | csvCols.push( '"' + memo.obses[o].value.toString().replace( '.', i18n['dec'][memo.lang] ) + '"' ); | ||
+ | csvCols.push( memo.obses[o].addInfo ); | ||
+ | csvCols.push( '' ); | ||
+ | csvCols.push( memo.obses[o].maintainer ); | ||
+ | |||
+ | csv += '\r\n' + csvCols.join( i18n['sep'][memo.lang] ); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | } else if ( i18n[memo.obscode].type == 'date' ) { | ||
+ | |||
+ | if ( i18n[memo.obscode].season == 'winter' ) { | ||
+ | header += i18n[ 'season' ][ i18n[memo.obscode].season ][ memo.lang ]; | ||
+ | } else { | ||
+ | header += i18n[ 'year' ][ memo.lang ]; | ||
+ | } | ||
+ | |||
+ | header += ';' + i18n[ 'Observation' ][ memo.lang ]; | ||
+ | header += ';' + i18n[ 'Value' ][ memo.lang ]; | ||
+ | header += ';' + i18n[ 'ValueUnit' ][ memo.lang ]; | ||
+ | header += ';' + i18n[ 'Additionalinfo' ][ memo.lang ]; | ||
+ | header += ';' + i18n[ 'Image' ][ memo.lang ]; | ||
+ | header += ';' + i18n[ 'ObserverStatus' ][ memo.lang ]; | ||
+ | |||
+ | for ( var s in memo.seriesA ) { | ||
+ | |||
+ | for ( var o in memo.seriesA[ s ].obses ) { | ||
+ | |||
+ | obs = memo.seriesA[ s ].obses[ o ]; | ||
+ | |||
+ | csv += '\r\n'; | ||
+ | |||
+ | csv += obs.season + '-' + (obs.season+1); | ||
+ | |||
+ | csv += ';' + i18n[ memo.seriesA[ s ].id ].title[ memo.lang ]; | ||
+ | |||
+ | csv += ';' + obs.value; | ||
+ | csv += ';' + obs.valueUnit; | ||
+ | |||
+ | csv += ';' + obs.addInfo; | ||
+ | csv += ';'; | ||
+ | csv += ';' + obs.maintainer; | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } else if ( i18n[memo.obscode].type == 'cat' ) { | ||
+ | |||
+ | header += 'Päivämäärä'; | ||
+ | header += ';' + 'Kellonaika'; | ||
+ | header += ';' + i18n[memo.obscode].title[memo.lang]; | ||
+ | header += ';' + i18n[memo.obscode].title[memo.lang]; | ||
+ | header += ';' + utf8StringToUtf16String( 'Lisätiedot' ); | ||
+ | header += ';' + 'Valokuva'; | ||
+ | header += ';' + 'Havainnoijan status'; | ||
+ | |||
+ | for ( var o in memo.obses ) { | ||
+ | |||
+ | csv += '\r\n'; | ||
+ | |||
+ | csv += memo.obses[o].obsdatetime.toLocaleDateString(); //.toISOString(); | ||
+ | |||
+ | if ( memo.obses[o].obsdatetime.getUTCHours() == 0 && memo.obses[o].obsdatetime.getUTCMinutes() == 0 && memo.obses[o].obsdatetime.getUTCSeconds() == 0 ) { | ||
+ | csv += ';'; | ||
+ | } else { | ||
+ | csv += ';' + ( "0" + memo.obses[o].obsdatetime.getUTCHours() ).slice(-2) + ':' + ( "0" + memo.obses[o].obsdatetime.getUTCMinutes() ).slice(-2); | ||
+ | } | ||
+ | |||
+ | csv += ';' + memo.obses[o].value; | ||
+ | csv += ';' + i18n[memo.obscode].catNames[memo.obses[o].value][memo.lang]; | ||
+ | |||
+ | csv += ';' + memo.obses[o].addInfo; | ||
+ | csv += ';'; | ||
+ | csv += ';' + memo.obses[o].maintainer; | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | csv = header + csv; | ||
+ | //console.log( csv ); | ||
+ | var exportedFilename = memo.csvfile; | ||
+ | |||
+ | var blob = new Blob( [csv], { type: 'text/csv;charset=utf-16LE;' }); | ||
+ | if (navigator.msSaveBlob) { // IE 10+ | ||
+ | navigator.msSaveBlob(blob, exportedFilename); | ||
+ | } else { | ||
+ | var link = document.createElement("a"); | ||
+ | if (link.download !== undefined) { // feature detection | ||
+ | // Browsers that support HTML5 download attribute | ||
+ | var url = URL.createObjectURL(blob); | ||
+ | link.setAttribute("href", url); | ||
+ | link.setAttribute("download", exportedFilename); | ||
+ | link.style.visibility = 'hidden'; | ||
+ | document.body.appendChild(link); | ||
+ | link.click(); | ||
+ | document.body.removeChild(link); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | }); | ||
+ | |||
+ | |||
+ | jQuery( window ).resize(function() { | ||
+ | |||
+ | setTimeout( doResize, 100 ); | ||
+ | |||
+ | }); | ||
+ | |||
+ | function doResize() { | ||
+ | |||
+ | memo.margins = { top: 10, right: 10, bottom: 80, left: 80 }; | ||
+ | |||
+ | var w = memo.chartEl.width(); | ||
+ | var h = memo.chartEl.height(); | ||
+ | |||
+ | var l = Math.max( memo.margins.left, 0.1*w ); | ||
+ | var r = Math.max( memo.margins.right, 0.02*w ); | ||
+ | var t = Math.max( memo.margins.top, 0.02*h ); | ||
+ | var b = Math.max( memo.margins.bottom, 0.15*h ); | ||
+ | |||
+ | if (!!document.fullscreenElement) { | ||
+ | //memo.options.chartArea = { top: memo.margins.top*2, left: memo.margins.left*2, width: (memo.widgetEl.width() - memo.margins.left*2 - memo.margins.right - 24), height: (memo.widgetEl.height() - memo.margins.top*2 - memo.margins.bottom*2), backgroundColor: { fill: '#daf0fa', stroke: '#fff', strokeWidth: 6 }}; | ||
+ | } else { | ||
+ | //memo.options.chartArea = { top: memo.margins.top, left: memo.margins.left, width: (memo.widgetEl.width() - memo.margins.left - memo.margins.right), height: (memo.widgetEl.height() - memo.margins.top - memo.margins.bottom), backgroundColor: { fill: '#daf0fa', stroke: '#fff', strokeWidth: 6 }}; | ||
+ | } | ||
+ | //memo.options.chartArea = { top: t, left: l, width: (w - l - r), height: (h - t - b), backgroundColor: { fill: '#daf0fa', stroke: '#fff', strokeWidth: 6 }}; | ||
+ | memo.options.chartArea = { top: t, left: l, width: (w - l - r), height: (h - t - b), backgroundColor: { fill: '#fff', stroke: '#eee', strokeWidth: 4 }}; | ||
+ | |||
+ | //console.log( memo.options ); | ||
+ | |||
+ | memo.chart.draw( memo.data, memo.options ); | ||
+ | |||
+ | // hide every second vaxis gridline on cat charts | ||
+ | if ( i18n[memo.obscode]['type'] == 'cat') { | ||
+ | var glc = 0; | ||
+ | jQuery( document.getElementById(memo.id) ).find( 'rect[height="1"]' ).each( function() { | ||
+ | if ( ( glc++ % 2 ) == 0 ) { | ||
+ | jQuery( this ).attr( 'fill', 'none' ); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | // add dash to trendlines | ||
+ | jQuery( document.getElementById(memo.id) ).find( 'path[stroke-width="2.33"]' ).each( function() { | ||
+ | jQuery( this ).attr('stroke-dasharray', '5, 5'); | ||
+ | }); | ||
+ | |||
+ | // move current observations to top | ||
+ | gEl = jQuery( document.getElementById(memo.id) ).find( 'svg' ).append( 'g' ); | ||
+ | |||
+ | //jQuery( document.getElementById(memo.id) ).find( 'circle[stroke-width="3"]' ).detach().appendTo( gEl ); | ||
+ | jQuery( document.getElementById(memo.id) ).find( 'path[stroke="#3366cc"]' ).detach().appendTo( gEl ); | ||
+ | jQuery( document.getElementById(memo.id) ).find( 'circle[fill="#3366cc"]' ).detach().appendTo( gEl ); | ||
+ | |||
+ | jQuery( document.getElementById(memo.id) ).find( 'circle[stroke-width="3"]' ).each( function() { jQuery( this ).parent().append( jQuery( this ) ); }); | ||
+ | //jQuery( document.getElementById(memo.id) ).find( 'circle[fill="#3366cc"]' ).each( function() { jQuery( this ).parent().append( jQuery( this ) ); }); | ||
+ | //jQuery( document.getElementById(memo.id) ).find( 'path[stroke="#3366cc"]' ).each( function() { jQuery( this ).parent().append( jQuery( this ) ); }); | ||
+ | |||
+ | } | ||
+ | |||
+ | } else { | ||
+ | |||
+ | jQuery( jQuery( document.getElementById(memo.id) ) ).hide(); | ||
+ | |||
+ | } | ||
+ | |||
+ | doResize(); | ||
+ | |||
+ | } | ||
+ | |||
+ | function smooth( list, degree ) { | ||
+ | var win = degree*2-1; | ||
+ | weight = _.range(0, win).map(function (x) { return 1.0; }); | ||
+ | weightGauss = []; | ||
+ | for (i in _.range(0, win)) { | ||
+ | i = i-degree+1; | ||
+ | frac = i/win; | ||
+ | gauss = 1 / Math.exp((4*(frac))*(4*(frac))); | ||
+ | weightGauss.push(gauss); | ||
+ | } | ||
+ | weight = _(weightGauss).zip(weight).map(function (x) { return x[0]*x[1]; }); | ||
+ | smoothed = _.range(0, (list.length+1)-win).map(function (x) { return 0.0; }); | ||
+ | for (i=0; i < smoothed.length; i++) { | ||
+ | smoothed[i] = _(list.slice(i, i+win)).zip(weight).map(function (x) { return x[0]*x[1]; }).reduce(function (memo, num){ return memo + num; }, 0) / _(weight).reduce(function (memo, num){ return memo + num; }, 0); | ||
+ | } | ||
+ | return smoothed; | ||
+ | } | ||
+ | |||
+ | function dec2hex( dec, padding ) { | ||
+ | return parseInt( dec, 10 ).toString( 16 ).padStart( padding, '0' ); | ||
+ | } | ||
+ | |||
+ | function utf8StringToUtf16String( str ) { | ||
+ | var utf16 = []; | ||
+ | for (var i=0, strLen=str.length; i < strLen; i++) { | ||
+ | utf16.push(dec2hex(str.charCodeAt(i), 4)); | ||
+ | } | ||
+ | return utf16.join(); | ||
+ | } | ||
+ | |||
+ | Date.prototype.getWeek = function() { | ||
+ | var date = new Date(this.getTime()); | ||
+ | date.setHours(0, 0, 0, 0); | ||
+ | // Thursday in current week decides the year. | ||
+ | date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); | ||
+ | // January 4 is always in week 1. | ||
+ | var week1 = new Date(date.getFullYear(), 0, 4); | ||
+ | // Adjust to Thursday in week 1 and count number of weeks from date to week1. | ||
+ | return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 | ||
+ | - 3 + (week1.getDay() + 6) % 7) / 7); | ||
+ | } | ||
+ | |||
+ | var maintColors = { 'authority': '#bb1111', 'expert': '#ff9933', 'experienced': '#666666', 'user': '#aaaaaa'}; | ||
+ | |||
+ | var seriesC = [ 'lightgray', '#3366cc', 'orange' ]; | ||
+ | |||
+ | var colors = { 'average': 'BurlyWood', 'trend': '#ff4500', 'obses': 'lightgray', 'curObses': '#3366cc', 'selObses': 'gold', 'noticeObses': 'tan' }; | ||
+ | |||
+ | var i18n = { | ||
+ | 'download': { 'fi': 'Lataa csv-muodossa', 'en': 'Download in csv format', 'sv': 'Ladda ner i csv-format' }, | ||
+ | 'fullscreen': { 'fi': 'Ota käyttöön/poista kokoruututila', 'en': 'Toggle fullscreen mode', 'sv': 'Växla helskärmsläge' }, | ||
+ | 'edit': { 'fi': 'Lisää/muokkaa havaintoja', 'en': 'Add/edit observations', 'sv': 'Lägg till/redigera observationer' }, | ||
+ | 'season': { 'winter': { 'fi': 'Talvi', 'en': 'Winter', 'sv': 'Vintern' } }, | ||
+ | 'dec': { 'fi': ',', 'en': '.', 'sv': ',' }, | ||
+ | 'sep': { 'fi': '\t', 'en': ' ', 'sv': ' ' }, | ||
+ | 'alg': { | ||
+ | 'type': 'cat', | ||
+ | 'min': -0.5, | ||
+ | 'season': 'summer', | ||
+ | 'trend': { 'type': 'gaussian', 'layout': 'line' }, | ||
+ | 'title': { 'fi': 'Sinilevätilanne', 'en': 'XX', 'sv': 'Xxx', 'ru': '???' }, | ||
+ | 'catNames': { 0: { 'fi': 'Ei levää', 'en': 'No algae', 'sv': 'Inga alger' }, 1: { 'fi': 'Hieman levää', 'en': 'Some algae', 'sv': 'Lite med alger' }, 2: { 'fi': 'Runsaasti levää', 'en': 'Abundant with algae', 'sv': 'Rikligt med alger' }, 3: { 'fi': 'Erittäin runsaasti levää', 'en': 'Very abundant with algae', 'sv': 'Ytterst rikligt med alger' } }, | ||
+ | 'catNamesShort': { 0: { 'fi': 'Ei levää', 'en': 'No algae', 'sv': 'Inga alger' }, 1: { 'fi': 'Hieman', 'en': 'Some', 'sv': 'Lite' }, 2: { 'fi': 'Runsaasti', 'en': 'Abundant', 'sv': 'Rikligt' }, 3: { 'fi': 'Erit. runsaasti', 'en': 'Very abundant', 'sv': 'Ytterst rikligt' } }, | ||
+ | 'unit': '', | ||
+ | 'axisTitleV': { 'fi': '', 'en': '', 'sv': '', 'ru': '' } | ||
+ | }, | ||
+ | 'temp': { | ||
+ | 'type': 'num', | ||
+ | 'season': 'summer', | ||
+ | 'trend': { 'type': 'gaussian', 'layout': 'line' }, | ||
+ | 'title': { 'fi': 'Pintaveden lämpötila', 'en': 'Surface water termperature', 'sv': 'Ytvattentemperatur', 'ru': '???' }, | ||
+ | 'unit': '°C', | ||
+ | 'axisTitleV': { 'fi': 'Lämpötila, °C', 'en': 'Temperature, °C', 'sv': 'Temperatur, °C', 'ru': '°C' } | ||
+ | }, | ||
+ | 'ice': { | ||
+ | 'catName': 'Jäätilanne', | ||
+ | 'type': 'num', | ||
+ | 'season': 'winter', | ||
+ | 'min': 0, | ||
+ | //'direction': -1, | ||
+ | 'trend': { 'type': 'gaussian', 'layout': 'line' }, | ||
+ | 'title': { 'fi': 'Jään paksuus', 'en': 'Ice thickness', 'sv': 'Isens tjocklek', 'ru': '???' }, | ||
+ | 'unit': 'cm', | ||
+ | 'axisTitleV': { 'fi': 'Jääpeite, cm', 'en': 'Ice cover, cm', 'sv': 'Istäcket, cm', 'ru': 'm' } | ||
+ | }, | ||
+ | 'ice_cat': { | ||
+ | 'catName': 'Jäätilanne', | ||
}, | }, | ||
− | { | + | 'ice_cat_2': { 'title': { 'fi': 'Jäätyminen', 'en': 'Freeze-up', 'sv': 'Förfrysning', 'ru': '???' }, 'title2': { 'fi': 'Pysyvä jääpeite', 'en': 'Permanent ice cover', 'sv': 'Permanent istäcke', 'ru': '???' }, color: '#d5da26' }, |
− | 'type': ' | + | 'ice_cat_5': { 'title': { 'fi': 'Jäänlähtö', 'en': 'Ice break-up', 'sv': 'Islossning', 'ru': '???' }, 'title2': { 'fi': 'Jäätön kausi alkoi', 'en': 'Beginning of ice-free season', 'sv': 'Början av den isfria säsongen', 'ru': '???' }, color: '#0076b0' }, |
− | ' | + | 'ice_cat_2,5': { |
− | ' | + | 'type': 'date', |
− | ' | + | 'season': 'winter', |
− | ' | + | 'trend': { 'type': 'regression', 'layout': 'line' }, |
− | + | 'title': { 'fi': 'Jääpeitekauden kesto', 'en': 'Duration of ice cover', 'sv': 'Längden på istäckesperioden', 'ru': '' }, | |
− | ' | + | //'charttitle': { 'fi': 'Jääpeite', 'en': 'Ice cover', 'sv': 'Frysning och islossning', 'ru': '' }, |
− | ' | + | 'color': '#c1e7f7', |
− | ' | + | 'unit': { 'fi': 'päivää', 'en': 'days', 'sv': 'dagar', 'ru': '' }, |
− | ' | + | 'axisTitleV': { 'fi': '', 'en': '', 'sv': '', 'ru': '' }, |
− | + | 'changes': { | |
− | //{ 'type': ' | + | 'fi': 'Jääpeitekauden pituudesta kertova kuvio on muuttunut. Aiemmat jäänlähdöstä ja jäättömän kauden alusta kertoneet erilliset graafit on yhdistetty samaan kuvaan. Jos samalta talvelta on tehty havainnot sekä pysyvän jäätilanteen että jäättömän kauden alkamisesta, piirtyy kuvioon myös jääpeitekauden pituus.', |
− | + | 'en': 'The graph showing the length of the ice cover period has changed. Separate graphs of previous freezing and icing have now been combined into the same figure. If there are observations from the same winter about the beginning of both the permanent ice situation and the ice-free season, the length of the ice cover period is also drawn in the figure.', | |
− | + | 'sv': 'Grafen som visar längden på istäckeperioden har ändrats. Separata grafer över tidigare frysning och isbildning har nu kombinerats till samma figur. Om det finns iakttagelser från samma vinter om början av både den permanenta issituationen och den isfria säsongen, ritas även istäckesperiodens längd i figuren.', | |
− | + | 'ru': '' | |
− | + | }, | |
− | + | }, | |
+ | 'snow_load': { | ||
+ | 'catName': 'Lumikuorma', | ||
+ | 'type': 'num', | ||
+ | 'season': 'winter', | ||
+ | 'min': 0, | ||
+ | 'trend': { 'type': 'moving', 'layout': 'area' }, | ||
+ | 'title': { 'fi': 'Lumikuorma', 'en': 'Snow load', 'sv': 'Snöbelastning', 'ru': '???' }, | ||
+ | 'unit': 'kg/m²', | ||
+ | 'axisTitleV': { 'fi': 'Lumikuorma, kg/m²', 'en': 'Snow load, kg/m²', 'sv': 'Snöbelastning, kg/m²', 'ru': 'm' } | ||
+ | }, | ||
+ | 'secchi': { | ||
+ | 'type': 'num', | ||
+ | 'season': 'summer', | ||
+ | 'min': 0, | ||
+ | 'direction': -1, | ||
+ | 'trend': { 'type': 'gaussian', 'layout': 'line' }, | ||
+ | //'trend': { 'type': 'regression', 'layout': 'line' }, | ||
+ | 'title': { 'fi': 'Näkösyvyys', 'en': 'Water transparency', 'sv': 'Siktdjupet', 'ru': '???' }, | ||
+ | 'unit': 'm', | ||
+ | 'axisTitleV': { 'fi': 'Näkösyvyys, m', 'en': 'Secchi depth, m', 'sv': 'Siktdjupet, m', 'ru': 'm' } | ||
+ | }, | ||
+ | 'level': { | ||
+ | 'type': 'num', | ||
+ | 'season': 'summer', | ||
+ | 'trend': { 'type': 'gaussian', 'layout': 'line' }, | ||
+ | 'title': { 'fi': 'Vedenkorkeus', 'en': 'Water level', 'sv': 'Vattenståndpunkt', 'ru': '???' }, | ||
+ | 'unit': 'cm', | ||
+ | 'axisTitleV': { 'fi': 'Vedenkorkeus, cm', 'en': 'Water level, cm', 'sv': 'Vattenståndpunkt, cm', 'ru': 'cm' } | ||
+ | }, | ||
+ | 'Observation': { 'fi': 'Havainto', 'en': 'Observation', 'sv': 'Observation', 'ru': '???' }, | ||
+ | 'new': { 'fi': 'Uusi', 'en': 'New', 'sv': 'Nytt', 'ru': '???' }, | ||
+ | 'Value': { 'fi': 'Arvo', 'en': 'Value', 'sv': 'Värde', 'ru': '???' }, | ||
+ | 'ValueUnit': { 'fi': 'Arvon tyyppi', 'en': 'Value type', 'sv': 'Värdes typ', 'ru': '???' }, | ||
+ | 'Date': { 'fi': 'Päivämäärä', 'en': 'Date', 'sv': 'Datum', 'ru': '???' }, | ||
+ | 'Additionalinfo': { 'fi': 'Lisätiedot', 'en': 'Additional info', 'sv': 'Tillägsinformation', 'ru': '???' }, | ||
+ | 'Image': { 'fi': 'Valokuva', 'en': 'Image', 'sv': 'Bild', 'ru': '???' }, | ||
+ | 'ObserverStatus': { 'fi': 'Havainnoijan status', 'en': 'Observer status', 'sv': 'Observatörens status', 'ru': '???' }, | ||
+ | 'average': { 'fi': 'Keskimäärin', 'en': 'Average', 'sv': 'Genomsnitt', 'ru': '???' }, | ||
+ | 'trendline': { 'fi': 'Trendiviiva', 'en': 'Trend line', 'sv': 'Trendlinje', 'ru': '???' }, | ||
+ | 'days': { 'fi': 'päivää', 'en': 'days', 'sv': 'dygn', 'ru': '???' }, | ||
+ | 'month': { 'fi': 'Kuukausi', 'en': 'Month', 'sv': 'Månad', 'ru': '???' }, | ||
+ | 'months': { | ||
+ | 0: { | ||
+ | 'long': { 'fi': 'Tammikuu', 'en': 'January', 'sv': 'Januari', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Tammi', 'en': 'Jan', 'sv': 'Jan', 'ru': '???' }, | ||
+ | 'roman': 'I' | ||
+ | }, | ||
+ | 1: { | ||
+ | 'long': { 'fi': 'Helmikuu', 'en': 'Febryary', 'sv': 'Februari', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Helmi', 'en': 'Feb', 'sv': 'Feb', 'ru': '???' }, | ||
+ | 'roman': 'II' | ||
+ | }, | ||
+ | 2: { | ||
+ | 'long': { 'fi': 'Maaliskuu', 'en': 'March', 'sv': 'Mars', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Maalis', 'en': 'Mar', 'sv': 'Mar', 'ru': '???' }, | ||
+ | 'roman': 'III' | ||
+ | }, | ||
+ | 3: { | ||
+ | 'long': { 'fi': 'Huhtikuu', 'en': 'April', 'sv': 'April', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Huhti', 'en': 'Apr', 'sv': 'Apr', 'ru': '???' }, | ||
+ | 'roman': 'IV' | ||
+ | }, | ||
+ | 4: { | ||
+ | 'long': { 'fi': 'Toukokuu', 'en': 'May', 'sv': 'Maj', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Touko', 'en': 'May', 'sv': 'Maj', 'ru': '???' }, | ||
+ | 'roman': 'V' | ||
+ | }, | ||
+ | 5: { | ||
+ | 'long': { 'fi': 'Kesäkuu', 'en': 'June', 'sv': 'Juni', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Kesä', 'en': 'Jun', 'sv': 'Jun', 'ru': '???' }, | ||
+ | 'roman': 'VI' | ||
+ | }, | ||
+ | 6: { | ||
+ | 'long': { 'fi': 'Heinäkuu', 'en': 'July', 'sv': 'Juli', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Heinä', 'en': 'Jul', 'sv': 'Jul', 'ru': '???' }, | ||
+ | 'roman': 'VII' | ||
+ | }, | ||
+ | 7: { | ||
+ | 'long': { 'fi': 'Elokuu', 'en': 'August', 'sv': 'Augusti', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Elo', 'en': 'Aug', 'sv': 'Aug', 'ru': '???' }, | ||
+ | 'roman': 'VII' | ||
+ | }, | ||
+ | 8: { | ||
+ | 'long': { 'fi': 'Syyskuu', 'en': 'September', 'sv': 'September', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Syys', 'en': 'Sep', 'sv': 'Sep', 'ru': '???' }, | ||
+ | 'roman': 'IX' | ||
+ | }, | ||
+ | 9: { | ||
+ | 'long': { 'fi': 'Lokakuu', 'en': 'October', 'sv': 'Oktober', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Loka', 'en': 'Oct', 'sv': 'Okt', 'ru': '???' }, | ||
+ | 'roman': 'X' | ||
+ | }, | ||
+ | 10: { | ||
+ | 'long': { 'fi': 'Marraskuu', 'en': 'November', 'sv': 'November', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Marras', 'en': 'Nov', 'sv': 'Nov', 'ru': '???' }, | ||
+ | 'roman': 'XI' | ||
+ | }, | ||
+ | 11: { | ||
+ | 'long': { 'fi': 'Joulukuu', 'en': 'December', 'sv': 'December', 'ru': '???' }, | ||
+ | 'short': { 'fi': 'Joulu', 'en': 'Dec', 'sv': 'Dec', 'ru': '???' }, | ||
+ | 'roman': 'XII' | ||
+ | } | ||
+ | } | ||
+ | }; | ||
− | + | })(); // We call our anonymous function immediately | |
− | </includeonly> | + | </script> |
+ | </includeonly> |