Ero sivun ”Widget:JwObsCharts2” versioiden välillä
Järvi-meriwikistä
(86 välissä olevaa versiota samalta käyttäjältä ei näytetä) | |||
Rivi 82: | Rivi 82: | ||
memo.obscodeParts = memo.obscode.split('_'); | memo.obscodeParts = memo.obscode.split('_'); | ||
memo.title = jQuery( this ).attr( 'data-title' ); if ( typeof memo.title == 'undefined' ) { memo.title = i18n[ memo.obscode ][ 'title' ][ memo.lang ]; } | memo.title = jQuery( this ).attr( 'data-title' ); if ( typeof memo.title == 'undefined' ) { memo.title = i18n[ memo.obscode ][ 'title' ][ memo.lang ]; } | ||
− | memo.info = jQuery( this ).attr( 'data-info' ); if ( typeof memo.info == 'undefined' ) { memo.info = jQuery( this ).attr( 'data- | + | memo.info = jQuery( this ).attr( 'data-info' ); if ( typeof memo.info == 'undefined' ) { memo.info = ""; } |
+ | memo.caption = jQuery( this ).attr( 'data-caption' ); if ( typeof memo.caption == 'undefined' ) { memo.caption = ""; } | ||
+ | //console.log( jQuery( this ).attr( 'data-showlink' ) ); | ||
+ | if ( typeof jQuery( this ).attr( 'data-showlink' ) == 'undefined' ) { | ||
+ | //console.log( 'sd' ); | ||
+ | memo.showlink = false; | ||
+ | } else { | ||
+ | memo.showlink = ( jQuery( this ).attr( 'data-showlink' ).toLowerCase() == 'true' ); | ||
+ | } | ||
if ( typeof jQuery( this ).attr( 'data-min' ) != 'undefined' ) { i18n[memo.obscode]['min'] = parseInt( jQuery( this ).attr( 'data-min' ) ); } | if ( typeof jQuery( this ).attr( 'data-min' ) != 'undefined' ) { i18n[memo.obscode]['min'] = parseInt( jQuery( this ).attr( 'data-min' ) ); } | ||
+ | if ( typeof jQuery( this ).attr( 'data-max' ) != 'undefined' ) { i18n[memo.obscode]['max'] = parseInt( jQuery( this ).attr( 'data-max' ) ); } | ||
if ( typeof jQuery( this ).attr( 'data-start-date' ) != 'undefined' ) { | if ( typeof jQuery( this ).attr( 'data-start-date' ) != 'undefined' ) { | ||
Rivi 116: | Rivi 125: | ||
// add chart container | // add chart container | ||
− | memo.widgetEl.append( '<div class="card JwCard mb-2" style="position: relative; width: 100%; height: 100%;"><div class="card-header" style="min-height: 49px;"></div><div class="card-body p-2" style="position: relative; width: 100%; height: 100%;"><div class="chart-container" style="position: relative; z-index: 110; width: 100%; height: 100%;"></div></div></div>' ); | + | memo.widgetEl.append( '<div class="card JwCard mb-2" style="position: relative; width: 100%; height: 100%;"><div class="card-header" style="min-height: 49px;"></div><div class="card-body p-2" style="position: relative; width: 100%; height: 100%;"><div class="chart-container" style="position: relative; z-index: 110; width: 100%; height: 100%;"></div></div><div class="card-footer"></div>' ); |
memo.chartEl = jQuery( this ).find( '.chart-container' ); | memo.chartEl = jQuery( this ).find( '.chart-container' ); | ||
memo.chartEl.css( 'height', memo.height + 'px' ); | memo.chartEl.css( 'height', memo.height + 'px' ); | ||
− | memo.headerEl = jQuery( this ).find( '.card-header' ); | + | memo.headerEl = jQuery( this ).find( '.card-header' ); |
+ | memo.footerEl = jQuery( this ).find( '.card-footer' ); | ||
// add title | // add title | ||
memo.headerEl.append( '<div class="obscharttitle" style="float: left;"></div>' ); | memo.headerEl.append( '<div class="obscharttitle" style="float: left;"></div>' ); | ||
memo.titleEl = jQuery( this ).find( '.obscharttitle' ); | memo.titleEl = jQuery( this ).find( '.obscharttitle' ); | ||
+ | console.log( memo ); | ||
+ | // add or hide footer | ||
+ | if ( memo.caption == '' ) { | ||
+ | memo.footerEl.hide(); | ||
+ | } else { | ||
+ | memo.footerEl.append( memo.caption ); | ||
+ | } | ||
// add fullscreen button | // add fullscreen button | ||
Rivi 313: | Rivi 330: | ||
}); | }); | ||
+ | } | ||
+ | |||
+ | // add show site link button | ||
+ | if ( memo.showlink ) { | ||
+ | memo.headerEl.append( '<div class="obschartbutton sitelink-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['sitelink'][memo.lang] + '" style="width: 24px; height: 24px; padding: 0; margin: 0; color: #1B599B; background: none; border: none; "><i class="fas fa-map-marked"></i></button></div>' ); | ||
+ | memo.sitelinkEl = jQuery( this ).find( '.sitelink-button' ); | ||
+ | memo.sitelinkEl.on( 'click', function() { | ||
+ | var elem = memo.widgetEl[0]; | ||
+ | window.location.href = 'https://www.jarviwiki.fi/w/index.php?curid=' + memo.siteid; | ||
+ | }); | ||
} | } | ||
− | } | + | } |
memo.loadStarts = 0; | memo.loadStarts = 0; | ||
Rivi 333: | Rivi 360: | ||
var so = { 'startdate': memo.startDate, 'custom': '' }; | var so = { 'startdate': memo.startDate, 'custom': '' }; | ||
+ | //var so = { 'custom': '' }; | ||
if ( typeof memo.obscodeParts[1] != 'undefined' ) { | if ( typeof memo.obscodeParts[1] != 'undefined' ) { | ||
Rivi 341: | Rivi 369: | ||
} | } | ||
} | } | ||
− | + | ||
− | |||
if ( memo.refcode == '-' ) { | if ( memo.refcode == '-' ) { | ||
so.obscode = memo.obscodeParts[0]; | so.obscode = memo.obscodeParts[0]; | ||
Rivi 354: | Rivi 381: | ||
so.waterbody = memo.waterbody; | so.waterbody = memo.waterbody; | ||
} | } | ||
− | + | ||
− | |||
− | |||
memo.jw.loadObses( so, function( o ) { | memo.jw.loadObses( so, function( o ) { | ||
− | memo.obses = memo.jw.obs; | + | memo.obses = memo.jw.obs; |
− | |||
drawVisualization(memo); | drawVisualization(memo); | ||
}); | }); | ||
Rivi 525: | Rivi 549: | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
memo.obsMinDate = new Date( memo.obsMinDateMs ); | memo.obsMinDate = new Date( memo.obsMinDateMs ); | ||
Rivi 592: | Rivi 600: | ||
// make ticks for y axis on cat types | // make ticks for y axis on cat types | ||
if ( memo.obsesA.length > 0 && memo.graphType != 'current' ) { | if ( memo.obsesA.length > 0 && memo.graphType != 'current' ) { | ||
+ | |||
if ( i18n[memo.obscode]['type'] == 'cat') { | if ( i18n[memo.obscode]['type'] == 'cat') { | ||
memo.options.vAxis.ticks = []; | memo.options.vAxis.ticks = []; | ||
Rivi 599: | Rivi 608: | ||
} | } | ||
memo.options.vAxis.ticks.sort( function(a, b) { return a.v-b.v } ); | memo.options.vAxis.ticks.sort( function(a, b) { return a.v-b.v } ); | ||
− | memo.options.vAxis.viewWindow = | + | memo.options.vAxis.viewWindow.min = -0.5; |
+ | memo.options.vAxis.viewWindow.max = parseInt(memo.options.vAxis.ticks[memo.options.vAxis.ticks.length-1].v)+0.5; | ||
memo.options.vAxis.gridlines.color = '#eee'; | memo.options.vAxis.gridlines.color = '#eee'; | ||
memo.options.vAxis.baselineColor = 'none'; | memo.options.vAxis.baselineColor = 'none'; | ||
− | } else if ( typeof i18n[memo.obscode]['min'] != 'undefined' ) { | + | } else { |
− | + | ||
− | + | if ( typeof i18n[memo.obscode]['min'] != 'undefined' ) { | |
+ | if ( i18n[memo.obscode]['min'] != -999 ) { | ||
+ | memo.options.vAxis.viewWindow.min = i18n[memo.obscode]['min']; | ||
+ | } | ||
+ | } else if ( memo.obsMinValue >= 0) { | ||
+ | //memo.options.vAxis.minValue = memo.obsMinValue; | ||
+ | memo.options.vAxis.viewWindow.min = memo.obsMinValue; | ||
} | } | ||
− | + | ||
− | + | if ( typeof i18n[memo.obscode]['max'] != 'undefined' ) { | |
− | + | if ( i18n[memo.obscode]['max'] != -999 ) { | |
+ | memo.options.vAxis.viewWindow.max = i18n[memo.obscode]['max']; | ||
+ | } | ||
+ | } else if ( memo.obsMaxValue >= 0) { | ||
+ | //memo.options.vAxis.minValue = memo.obsMinValue; | ||
+ | //memo.options.vAxis.viewWindow.max = memo.obsMaxValue; | ||
+ | } | ||
} | } | ||
Rivi 622: | Rivi 644: | ||
} | } | ||
− | if ( | + | if ( memo.info != '' ) { |
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="' + memo.info + '"><span class="fontawesome"></span></button>' ); | 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="' + memo.info + '"><span class="fontawesome"></span></button>' ); | ||
jQuery( '[data-toggle="tooltip"]' ).tooltip(); | jQuery( '[data-toggle="tooltip"]' ).tooltip(); | ||
Rivi 649: | Rivi 671: | ||
addDataToDateOfYearChart( memo ); | addDataToDateOfYearChart( memo ); | ||
− | + | } | |
− | |||
− | |||
− | |||
− | } | ||
} | } | ||
− | function | + | function addDataToDateOfYearChart( memo ) { |
− | // | + | // do X axis min and max for this chart type |
− | memo. | + | 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 ); } | |
− | if ( | + | 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 ) { | |
− | memo. | + | obs = memo.obsesA[ o ]; |
− | memo. | + | 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: 8, color: memo.seriesA[ s ].color, XstrokeWidth: 2, Xstroke: '#000000' } ); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 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; | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | drawChart(memo); | |
− | |||
− | + | } | |
+ | |||
+ | function addDataToSeasonWithRefsChart(memo) { | ||
− | + | // do axis min and max | |
+ | memo.axisMinDate = new Date( memo.curSeason, 0, 1 ); | ||
+ | memo.axisMaxDate = new Date( memo.curSeason, 11, 31 ); | ||
− | + | memo.data.addColumn( 'number', '1991-2020' ); | |
− | + | memo.data.addColumn( { id:'i0', type:'number', role:'interval' } ); | |
− | + | memo.data.addColumn( { id:'i0', type:'number', role:'interval' } ); | |
− | + | memo.data.addColumn( { type: 'string', role: 'tooltip', 'p': { 'html': true } } ); | |
− | + | memo.data.addColumn( 'number', memo.curSeason ); | |
− | + | 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) { | ||
+ | if ( memo.obsesA[o].printouts.ObsCode == memo.refcode ) { | ||
+ | memo.obsesA[o].compareDate = getDateOfISOWeek( memo.obsesA[o].data.week, memo.curSeason ) | ||
+ | memo.obsesA[o].compareDate.setDate( memo.obsesA[o].compareDate.getDate() + 3 ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var weekdata = []; | ||
+ | for ( var w=1; w<=53; w++ ) { | ||
+ | weekdata.push( { 'week': w, 'val': null, 'mw': null, 'low': null, 'high': null, 'style': null } ); | ||
+ | } | ||
+ | |||
+ | for (var o in memo.obsesA) { | ||
+ | if ( memo.obsesA[ o ].printouts.ObsCode == memo.obscode ) { | ||
+ | weekdata[ memo.obsesA[ o ].data.week-1 ].val = memo.obsesA[ o ].data.val; | ||
+ | weekdata[ memo.obsesA[ o ].data.week-1 ].style = memo.obsesA[ o ].style; | ||
+ | } else { | ||
+ | weekdata[ memo.obsesA[ o ].data.week-1 ].mw = memo.obsesA[ o ].data.val; | ||
+ | weekdata[ memo.obsesA[ o ].data.week-1 ].low = memo.obsesA[ o ].data.low / 100; | ||
+ | weekdata[ memo.obsesA[ o ].data.week-1 ].high = memo.obsesA[ o ].data.high / 100; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for ( var w in weekdata ) { | ||
+ | |||
+ | mow = getDateOfISOWeek( weekdata[w].week, memo.curSeason ); | ||
+ | mow.setDate( mow.getDate() + 3 ); | ||
+ | |||
+ | memo.dataA.push( [ | ||
+ | mow, | ||
+ | weekdata[w].mw, | ||
+ | weekdata[w].low, | ||
+ | weekdata[w].high, | ||
+ | '<div style="padding: 5px;"><b>Vertailukauden 1991-2020 havainnot viikolla ' + weekdata[w].week + '</b><br />Suurin arvo (HW): ' + weekdata[w].high + '<br />Keskiarvo (MW): ' + weekdata[w].mw + '<br />Pienin arvo (LW): ' + weekdata[w].low + '</div>', | ||
+ | weekdata[w].val, | ||
+ | weekdata[w].style, | ||
+ | null, | ||
+ | '<div style="padding: 5px;"><b>Kuluvan vuoden vedenkorkeus viikolla ' + weekdata[w].week + '</b><br />Keskiarvo (MW): ' + weekdata[w].val + '</div>', | ||
+ | ] ); | ||
+ | } | ||
+ | |||
+ | // make ticks for x axis | ||
+ | memo.options.hAxis.ticks = []; | ||
+ | for (i=0; i<12; i++) { | ||
+ | //m = i+1; | ||
+ | middleOfMonth = new Date( memo.curSeason, i, 16 ); | ||
+ | //console.log(m); | ||
+ | memo.options.hAxis.ticks.push({v: middleOfMonth, f: i18n.months[i]['roman'] }); | ||
} | } | ||
− | // | + | memo.options.seriesType = 'line'; |
− | + | memo.options.series[0] = { type: 'line', pointSize: 0, color: colors.average, lineWidth: 2.33 }; | |
− | + | memo.options.curveType = 'function'; | |
− | + | memo.options.intervals = { 'style': 'area' }; | |
+ | memo.options.series[1] = { type: 'line', pointSize: 0, color: colors.curObses, lineWidth: 5 }; | ||
+ | |||
+ | //memo.options.vAxis.viewWindow.min = 80.5; | ||
+ | //memo.options.vAxis.viewWindow.max = 81.7; | ||
+ | |||
+ | memo.chart = new google.visualization.LineChart( memo.chartEl[0] ); // document.getElementById(memo.id) | ||
+ | |||
+ | drawChart(memo); | ||
+ | } | ||
− | + | function addDataToTrendWithHighLowChart (memo) { | |
− | + | //console.log( 'high low chart'); | |
− | + | // 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( { id:'i0', type:'number', role:'interval' } ); | |
− | + | memo.data.addColumn( { id:'i0', type:'number', role:'interval' } ); | |
− | + | 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' }; | ||
− | + | //console.log( memo ); | |
− | |||
− | |||
− | |||
− | |||
− | + | for (var o in memo.obsesA) { | |
+ | |||
+ | dateStr = memo.obsesA[o].popup.match( /\([^)]*\)/g ); | ||
+ | yearStr = dateStr[0].match( /[0-9]{4}/g ); | ||
+ | memo.obsesA[o].popup = memo.obsesA[o].popup.replace( dateStr[0], '(' + yearStr[0] + ')' ); | ||
+ | memo.dataA.push( [ memo.obsesA[o].obsdatetime, memo.obsesA[o].value, memo.obsesA[o].data.low/100, memo.obsesA[o].data.high/100, memo.obsesA[o].style, null, memo.obsesA[o].popup ] ); | ||
+ | } | ||
− | + | 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.seriesType = 'line'; | ||
+ | memo.options.series[0] = { type: 'line', pointSize: 3, color: '#3366cc' }; | ||
+ | memo.options.curveType = 'function'; | ||
+ | memo.options.intervals = { 'style': 'area' }; | ||
+ | |||
+ | memo.options.vAxis.viewWindow.min = 80; | ||
+ | memo.options.vAxis.viewWindow.max = 82; | ||
+ | |||
+ | |||
+ | memo.chart = new google.visualization.LineChart( memo.chartEl[0] ); // document.getElementById(memo.id) | ||
+ | |||
+ | 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.axisMinDate | ||
− | memo.axisMaxDate | ||
memo.data.addColumn( 'number', memo.obsMinYear + '-' + memo.obsMaxYear ); | memo.data.addColumn( 'number', memo.obsMinYear + '-' + memo.obsMaxYear ); | ||
− | |||
− | |||
memo.data.addColumn( {'type': 'string', 'role': 'style' } ); | memo.data.addColumn( {'type': 'string', 'role': 'style' } ); | ||
memo.data.addColumn( { type: 'string', role: 'annotation' } ); | memo.data.addColumn( { type: 'string', role: 'annotation' } ); | ||
Rivi 1 090: | Rivi 1 010: | ||
// series for trend line | // 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) { | + | |
− | + | 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.obsesA[o].obsdatetime, | + | //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 { | |
− | memo.obsesA[o]. | + | //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 ); | |
+ | |||
} | } | ||
Rivi 1 115: | Rivi 1 036: | ||
} | } | ||
− | + | memo.options.series[0] = {type: 'scatter', pointSize: 6, color: '#3366cc' }; | |
− | memo.options.series[0] = { type: ' | + | |
− | + | drawChart(memo); | |
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | function | + | function addDataToSeasonChart(memo) { |
− | + | memo.axisMinDate = new Date( memo.obsMinCompDateMs ); | |
− | |||
− | |||
− | memo.axisMinDate = new Date(memo. | ||
− | |||
− | |||
− | |||
memo.axisMinDate.setDate(1); | memo.axisMinDate.setDate(1); | ||
− | memo.axisMaxDate.setDate( | + | memo.axisMaxDate = new Date( memo.obsMaxCompDateMs ); |
+ | memo.axisMaxDate.setMonth( memo.axisMaxDate.getMonth()+1 ); | ||
+ | memo.axisMaxDate.setDate(0); | ||
− | memo. | + | memo.seasonsO = {}; |
− | + | memo.seasonsA = []; | |
− | |||
− | |||
− | memo. | ||
− | |||
− | + | 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. | + | for (var o in memo.seasonsO) { memo.seasonsA.push(o); } memo.seasonsA.sort( function(a,b) { return b-a; } ); |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | // create cols for each series | |
− | for ( | + | 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 { | ||
+ | if ( memo.obscode == 'secchi' ) { | ||
+ | //console.log('secchi'); | ||
+ | memo.options.series[sc++] = { type: 'area', curveType: 'function', color: colors['curObses'], pointSize: 3, lineWidth: 4, 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. | + | 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' } ); | |
− | memo. | ||
− | memo.data.addColumn( { type: ' | ||
− | memo.data.addColumn( { | ||
+ | if ( memo.seasonsA.length == 1 && memo.seasonsA[0] == memo.curSeason ) { | ||
+ | memo.options.series[ sc-1 ].lineWidth = 0; | ||
+ | memo.options.series[ sc-1 ].pointSize = 0; | ||
+ | memo.options.series[ sc-1 ].labelInLegend = false; | ||
+ | memo.options.intervals = { 'style':'none' }; | ||
+ | } | ||
+ | |||
// series for trend line | // series for trend line | ||
− | memo.options.trendlines[ | + | 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; | |
− | + | } | |
− | + | } | |
− | + | ||
+ | // 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); }); | |
− | |||
− | |||
− | |||
− | + | 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; } | |
− | if ( | + | |
− | + | for ( var w=w1; w<=w2; w++) { | |
− | + | ||
− | + | //console.log( y + '/' + w ); | |
− | //console.log( | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 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.avgLlist); |
− | |||
− | |||
− | + | 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; | |
− | + | } | |
− | + | } | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | } | ||
} | } | ||
− | + | 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 ) ); | |
− | |||
− | |||
− | |||
− | |||
− | + | //console.log( memo.avgMlist ); | |
− | + | } 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 ); | ||
− | + | 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 ); } | ||
+ | |||
+ | xdate = new Date( memo.avgW[firstY][firstW].cDate.getTime() + ( i + 1 - memo.gSmoothing/2 ) * msW ); | ||
+ | if ( xdate.getTime() < memo.axisMinDate.getTime() ) { | ||
+ | dataRow[0] = memo.axisMinDate; | ||
+ | } else if ( xdate.getTime() > memo.axisMaxDate.getTime() ) { | ||
+ | dataRow[0] = memo.axisMaxDate; | ||
+ | } else { | ||
+ | dataRow[0] = xdate; //new Date( memo.avgW[firstY][firstW].cDate.getTime() + ( i + 1 - memo.gSmoothing/2 ) * msW ); | ||
+ | } | ||
+ | |||
+ | dataRow[cc-4] = memo.avgMsmooth[i]; | ||
+ | |||
+ | if ( memo.obscode == 'level' ) { | ||
+ | dataRow[cc-3] = memo.avgLsmooth[i]; | ||
+ | } else { | ||
+ | dataRow[cc-3] = Math.max( memo.avgLsmooth[i], 0 ); | ||
+ | } | ||
+ | dataRow[cc-2] = memo.avgHsmooth[i]; | ||
− | + | memo.dataA.push( dataRow ); | |
− | + | } | |
+ | |||
+ | } 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; | ||
+ | //console.log( obs.compareDate ); | ||
+ | if ( ( today.getTime() - obs.compareDate.getTime() < 10*24*60*60*1000 ) && s == 0 && o == ( memo.seasonsO[memo.seasonsA[s]].obses.length - 1 ) ) { | ||
− | + | var diff = obs.value - memo.avgW[ obs.compareDate.getFullYear() ][ obs.compareDate.getWeek() ].avg; | |
+ | var diff = Math.round( diff*100 ); | ||
+ | var diffStr = diff.toString() + ' cm'; | ||
+ | if ( diff > 0 ) { diffStr = '+' + diffStr; } | ||
+ | |||
+ | dataRow[s*4+4] = null; //diffStr; //annotation | ||
+ | } else { | ||
+ | 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(); | ||
− | } else { | + | 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) { | |
+ | |||
+ | memo.loaderEl.fadeOut( "slow", function() { memo.loaderEl.remove(); } ); | ||
− | + | if (memo.dataA.length > 0) { | |
− | + | memo.data.addRows(memo.dataA); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | memo. | + | if ( typeof memo.chart == 'undefined' ) { |
− | + | memo.chart = new google.visualization.ComboChart( memo.chartEl[0] ); // document.getElementById(memo.id) | |
− | + | } | |
− | |||
− | // | + | //doResize(); |
− | |||
− | + | memo.fullscreenEl.fadeIn( "slow" ); | |
− | + | if ( memo.download) { memo.downloadEl.fadeIn( "slow" ); } | |
+ | if ( memo.showlink ) { memo.sitelinkEl.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 { | } else { | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | var | + | 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; | ||
+ | } | ||
+ | } | ||
− | |||
− | |||
− | |||
} | } | ||
− | memo | + | doResize( memo ); |
+ | |||
+ | }); | ||
− | |||
− | } | + | } else { |
− | + | jQuery( jQuery( document.getElementById(memo.id) ) ).hide(); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | memo | + | doResize( memo ); |
− | |||
− | |||
− | + | } | |
− | + | ||
− | + | var doResize = function( memo ) { | |
− | + | ||
− | + | function wait() { | |
− | if ( | + | |
− | + | //console.log( memo.options ); | |
− | + | ||
− | + | var w = memo.chartEl.width(); | |
+ | var h = memo.chartEl.height(); | ||
+ | |||
+ | //console.log( w ); | ||
+ | |||
+ | if ( typeof memo.oldW == 'undefined' ) { memo.oldW = 1; } | ||
+ | if ( typeof memo.oldH == 'undefined' ) { memo.oldH = 1; } | ||
+ | |||
+ | if ( ( w != memo.oldW || h != memo.oldH ) && w*h != 0 ) { | ||
+ | |||
+ | memo.oldW = w; memo.oldH = h; | ||
− | + | memo.margins = { top: 10, right: 10, bottom: 80, left: 80 }; | |
− | + | var w = memo.chartEl.width(); | |
− | + | var h = memo.chartEl.height(); | |
− | |||
− | memo. | ||
− | |||
− | memo. | ||
− | |||
− | |||
− | + | 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 ); | ||
− | + | memo.options.chartArea = { top: t, left: l, width: (w - l - r), height: (h - t - b), backgroundColor: { fill: '#fff', stroke: '#eee', strokeWidth: 4 }}; | |
− | + | 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 | |
− | memo. | + | gEl = jQuery( document.getElementById(memo.id) ).find( 'svg' ).append( 'g' ); |
− | } | + | //console.log( jQuery( document.getElementById(memo.id) ).find( 'svg' ) ); |
+ | 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( 'circle[fill="#3366cc"]' ).each( function() { | ||
+ | //jQuery( this ).detach().appendTo( gEl ); | ||
+ | }); | ||
+ | } | ||
+ | } | ||
+ | //wait(); | ||
+ | if ( typeof memo.chartEl != 'undefined' ) { | ||
+ | setTimeout( wait, 500 ); | ||
+ | } | ||
− | + | } | |
+ | window.jwobschartresize = 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(); | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | 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() { | Date.prototype.getWeek = function() { | ||
Rivi 1 788: | Rivi 1 606: | ||
var week1 = new Date(date.getFullYear(), 0, 4); | var week1 = new Date(date.getFullYear(), 0, 4); | ||
// Adjust to Thursday in week 1 and count number of weeks from date to week1. | // Adjust to Thursday in week 1 and count number of weeks from date to week1. | ||
− | return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 | + | return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); |
− | |||
} | } | ||
+ | |||
+ | function getDateOfISOWeek(w, y) { | ||
+ | var simple = new Date(y, 0, 1 + (w - 1) * 7); | ||
+ | var dow = simple.getDay(); | ||
+ | var ISOweekStart = simple; | ||
+ | if (dow <= 4) { | ||
+ | ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1); | ||
+ | } else { | ||
+ | ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay()); | ||
+ | } | ||
+ | return ISOweekStart; | ||
+ | } | ||
var maintColors = { 'authority': '#bb1111', 'expert': '#ff9933', 'experienced': '#666666', 'user': '#aaaaaa'}; | var maintColors = { 'authority': '#bb1111', 'expert': '#ff9933', 'experienced': '#666666', 'user': '#aaaaaa'}; | ||
Rivi 1 801: | Rivi 1 630: | ||
'download': { 'fi': 'Lataa csv-muodossa', 'en': 'Download in csv format', 'sv': 'Ladda ner i csv-format' }, | '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' }, | 'fullscreen': { 'fi': 'Ota käyttöön/poista kokoruututila', 'en': 'Toggle fullscreen mode', 'sv': 'Växla helskärmsläge' }, | ||
+ | 'sitelink': { 'fi': 'Mene havaintopaikan sivulle', 'en': "Go to the observation site's page", 'sv': 'Gå till observationsplatsen.' }, | ||
'edit': { 'fi': 'Lisää/muokkaa havaintoja', 'en': 'Add/edit observations', 'sv': 'Lägg till/redigera observationer' }, | 'edit': { 'fi': 'Lisää/muokkaa havaintoja', 'en': 'Add/edit observations', 'sv': 'Lägg till/redigera observationer' }, | ||
'season': { 'winter': { 'fi': 'Talvi', 'en': 'Winter', 'sv': 'Vintern' } }, | 'season': { 'winter': { 'fi': 'Talvi', 'en': 'Winter', 'sv': 'Vintern' } }, |