<%@ Language=VBScript %> <% Option Explicit ' rosy.asp ' Author: Jim Miller ' MySQL Version: 1.0 ' May 17, 2025 ' Buffer and release all at once... Response.Buffer = True %> <!-- #include file="rosy_utilities.asp" --> <% '========================================== ' Common Variables (globals) '========================================== ' From the old headers.asp file... Dim strServerName, strPathToImageDir, strURLPathToImageDir Const adStateOpen = 1 Const adStateClosed = 0 Const adOpenStatic = 3 Const adLockBatchOptimistic = 4 Const adLockReadOnly = 1 Const adCmdText = 1 Dim dicTraceIO Dim DBConnection, rstDate, rstStations, rstLatestDate, rstMostRecent, rstTimeZone ' Arrays for sensor data values Dim dataPoints_WindDirection, dataPoints_WindGust, dataPoints_WindSpeed Dim dataPoints_Pressure Dim dataPoints_TempAvg, dataPoints_TempMax, dataPoints_TempMin, dataPoints_DewPoint Dim dataPoints_DeltaP_trace_A, dataPoints_DeltaP_trace_B Dim dteMaxTimeStamp Dim strSQL, strNameForPlot, intMaxGust, intNonPlottingHeight, intTempDiffScalingThreshold Dim strTitle, strHGSL Dim sglTempMax, sglTempMin, sglPressureMin, sglPressureMax, sglTempRange, sglDewPointMin, blnDewPointData Dim strMRTime, strMRWindAvg, strMRWindMax, strMRWindDir, strMRTemp, strMRPressure, strMRDewPoint Dim Chart Dim Filename Dim WeatherTypes, WeatherTypes_URL, WeatherTypes_count, DaysChoices Dim dteStartDateTime, dteEndDateTime, dteStartDate_forLabels Dim TimeLabels, TheHour, DayValue, DaysDecSinceRef, intHour Dim blnMinMax, blnFoundSomeData Dim intTheColor Dim strRandomNameString, strFileName2, strOrderBy, intColorScaleFactor Dim fsoObject, fdrObject, filObject Dim intFileCount Dim blnDayLightSavingsTime Dim dtePostedDate, blnPostedDate_default Dim intJ, intDays, intXLabels, dblDaysIncrement, dblDaysFraction, dblFractionalPart, dteLabelDate, intLabelsPerDay Dim dblDPmin, dblDPmax Dim dblWindNormFactor, intRed, intGreen, intBlue, intGray Dim strRegionURL, strSensorType, strInitializeTimer, strLocation Dim serverTimeArray, serverTime, intPixelBottomShift, intPixelRightShift, intPixelRightShift_tweak Dim strShowImages_command Dim vrtReturnFromMINMAX Dim intMinutes, dblFiveMinutes, intSeconds_FromMinutes, intSeconds_FromSeconds, intDelay_to_5min Dim strButtonLabel Dim strTimeZone, dicTZ Dim arrRegions, strRegionValue, strRegion, strRegionState Dim strDebugMessage Dim dteNowTime, dteStartDateTime_forQuery Dim str24Hrs_state, strTimer_state, strTimer_value, strRA_state Dim useRunningAverage, RA_x, RA_y Set DBConnection = Nothing '============================================================================================= ' Functions and Subroutines '============================================================================================= ' Add error logging function that writes to the page Sub LogError(location) If Err.Number <> 0 Then Response.Write "<div style='color:red; background-color:#ffe0e0; padding:5px; margin:5px; border:1px solid red'>" Response.Write "<strong>ERROR at " & location & ":</strong> " & Err.Number & " - " & Err.Description Response.Write "</div>" Err.Clear ' Clear the error so we can continue End If End Sub Sub RBC(strTheString) Response.Write strTheString & "<BR>" & Chr(10) End Sub 'Alias for RBC Sub RWBR(strTheString) RBC strTheString End Sub Sub RC(strTheString) Response.Write strTheString & Chr(10) End Sub 'This will not make a new line in the HTML file. Sub RW(strTheString) Response.Write strTheString End Sub Sub MinMax(ByVal dblNewValue, ByRef dblMax, ByRef dblMin) If (dblNewValue > dblMax) Then dblMax = dblNewValue End If If (dblNewValue < dblMin) Then dblMin = dblNewValue End If End Sub Function DaylightTime(strMRTime) Dim strMRTime_DLS If (strMRTime <> "-") Then If (DaylightSavingsTime(strMRTime)) Then strMRTime_DLS = DateAdd("h",1,strMRTime) Else strMRTime_DLS = strMRTime End If Else strMRTime_DLS = "-" End If DaylightTime = strMRTime_DLS End Function Function AgeOfData(strMRTime) If (strMRTime <> "-") Then ' The following line works mainly because strMRTime is in standard time. So no problem with HI. AgeOfData = DateDiff("n", DaylightTime(strMRTime), Now()) + 60 * dicTZ.item(strTimeZone) Else AgeOfData = "-" End If End Function Function DaysDecSinceRefF(byVal timeMDY, byVal timeHr, byVal timeMin) Dim dteRecordTime Dim TheMin If (intDays = 1) Then TheMin = timeMin Else TheMin = 0 End If dteRecordTime = timeMDY + TimeSerial(timeHr, TheMin, 0) DaysDecSinceRefF = CDbl( DateDiff("n", dteStartDateTime, dteRecordTime) ) / 1440 End Function Function DaysDec( dteTime) ' 86400 = 24.0*60.0*60.0 (Seconds in a day). ' Decimal day as measured from the midnight start time. DaysDec = CDbl( DateDiff("s", dteStartDateTime, dteTime) ) / 86400.0 End Function Function DirectionLabel (WindDeg) If (WindDeg > 345 And WindDeg <= 360) Then DirectionLabel = "North" ElseIf (WindDeg > 0 And WindDeg <= 15) Then DirectionLabel = "North" ElseIf (WindDeg > 15 And WindDeg <= 45) Then DirectionLabel = "NNE" ElseIf (WindDeg > 45 And WindDeg <= 75) Then DirectionLabel = "ENE" ElseIf (WindDeg > 75 And WindDeg <= 105) Then DirectionLabel = "East" ElseIf (WindDeg > 105 And WindDeg <= 135) Then DirectionLabel = "ESE" ElseIf (WindDeg > 135 And WindDeg <= 165) Then DirectionLabel = "SSE" ElseIf (WindDeg > 165 And WindDeg <= 195) Then DirectionLabel = "South" ElseIf (WindDeg > 195 And WindDeg <= 225) Then DirectionLabel = "SSW" ElseIf (WindDeg > 225 And WindDeg <= 255) Then DirectionLabel = "WSW" ElseIf (WindDeg > 255 And WindDeg <= 285) Then DirectionLabel = "West" ElseIf (WindDeg > 285 And WindDeg <= 315) Then DirectionLabel = "WNW" ElseIf (WindDeg > 315 And WindDeg <= 345) Then DirectionLabel = "NNW" Else DirectionLabel = "Var" End If If (WindDeg = 45) Then DirectionLabel = "NE" ElseIf (WindDeg = 135) Then DirectionLabel = "SE" ElseIf (WindDeg = 225) Then DirectionLabel = "SW" ElseIf (WindDeg = 315) Then DirectionLabel = "NW" End If End Function Sub AddHorizontalLine_gray(intLineWidth, intColor, dblYvalue) Chart.AddSeries (5) Chart.linewidth = intLineWidth Chart.SeriesInLegend = false ' The -0.009 extends the line all the way to the left edge of the 1-day chart. MyChartAddXY -0.009, dblYvalue, "", RGB(intColor, intColor, intColor) MyChartAddXY intDays+1.0, dblYvalue, "", RGB(intColor, intColor, intColor) End Sub Sub AddHorizontalLine_color(intLineWidth, intRed, intGreen, intBlue, dblYvalue) Chart.AddSeries (5) Chart.linewidth = intLineWidth Chart.SeriesInLegend = false MyChartAddXY -0.009, dblYvalue, "", RGB(intRed, intGreen, intBlue) MyChartAddXY intDays+1.0, dblYvalue, "", RGB(intRed, intGreen, intBlue) End Sub Sub MyChartAddXY(dblXValue, dblYValue, strXLabel, intColor) ' Feed only NON-Null values to the AddXY method. If (Not IsNull(dblYValue)) Then Chart.AddXY dblXValue, dblYValue, strXLabel, intColor End If End Sub ' Format date for MySQL (YYYY-MM-DD HH:MM:SS) Function MySQLDate(dateValue) MySQLDate = "'" & Year(dateValue) & "-" & _ Right("0" & Month(dateValue), 2) & "-" & _ Right("0" & Day(dateValue), 2) & " " & _ Right("0" & Hour(dateValue), 2) & ":" & _ Right("0" & Minute(dateValue), 2) & ":" & _ Right("0" & Second(dateValue), 2) & "'" End Function Sub AddVerticalLine( dblXValue, intLineWidth) Dim intColor, intGray, intColor_Red, intColor_Green, intColor_Blue Chart.AddSeries (5) Chart.linewidth = intLineWidth Chart.SeriesInLegend = false intGray = 75 ' 0 (black) to 255 (white) intColor_Red = intGray intColor_Green = intGray intColor_Blue = intGray intColor = RGB(intColor_Red, intColor_Green, intColor_Blue) 'intColor = vbBlack MyChartAddXY dblXValue, Chart.VertAxisMin, "", intColor MyChartAddXY dblXValue, Chart.VertAxisMax, "", intColor End Sub Function DeltaP_SQL(ByVal intDays, ByRef dicTraceIO) Dim strWestSite, strEastSite strWestSite = dicTraceIO.Item("WestSite") strEastSite = dicTraceIO.Item("EastSite") If (intDays = 1) then ' This query uses an interesting trick to accomplish the delta-P ' calculation. It selects all the needed data from two sites and then ' groups it by time. It feeds the SUM operator with logic from the IIF ' operator. That is how the delta is calculated. The HAVING clause ' insures that only groups with a count of 2 are used. ' old MS Access version 'strSQL = "SELECT DateTimeStamp, TimeMDY, TimeHr, TimeMin, SUM(IIf([StationName]='" & strWestSite & "',+[Pressure],-[Pressure])) AS DeltaP " & _ ' "FROM FifteenMinData " & _ ' "WHERE ((StationName) In ('" & strWestSite & "','" & strEastSite & "')) AND " & _ ' " (DateTimeStamp <= " & MySQLDate(dteEndDateTime) & ") AND " & _ ' " (DateTimeStamp >= " & MySQLDate(dteStartDateTime_forQuery) & ") " & _ ' "GROUP BY DateTimeStamp, TimeMDY, TimeHr, TimeMin " & _ ' "HAVING (((Count(DateTimeStamp))=2)) " & _ ' "ORDER BY TimeMDY ASC, TimeHr ASC, TimeMin ASC" ' MySQL-compatible query (replacing IIf with CASE expression) strSQL = "SELECT DateTimeStamp, TimeMDY, TimeHr, TimeMin, " & _ "SUM(CASE WHEN StationName = '" & strWestSite & "' THEN Pressure ELSE -Pressure END) AS DeltaP " & _ "FROM FifteenMinData " & _ "WHERE StationName IN ('" & strWestSite & "','" & strEastSite & "') AND " & _ "DateTimeStamp <= " & MySQLDate(dteEndDateTime) & " AND " & _ "DateTimeStamp >= " & MySQLDate(dteStartDateTime_forQuery) & " " & _ "GROUP BY DateTimeStamp, TimeMDY, TimeHr, TimeMin " & _ "HAVING COUNT(DISTINCT StationName) = 2 " & _ "ORDER BY TimeMDY ASC, TimeHr ASC, TimeMin ASC" Else ' Multi-day query ' old MS Access version 'strSQL = "SELECT DateTimeStamp, TimeMDY, TimeHr, TimeMin, SUM(IIf([StationName]='" & strWestSite & "',+[Pressure],-[Pressure])) AS DeltaP1 " & _ ' "FROM FifteenMinData " & _ ' "WHERE ((StationName) In ('" & strWestSite & "','" & strEastSite & "')) AND " & _ ' " ([DateTimeStamp] <= #" & dteEndDateTime & "#) AND " & _ ' " ([DateTimeStamp] >= #" & dteStartDateTime_forQuery & "#) " & _ ' "GROUP BY DateTimeStamp, TimeMDY, TimeHr, TimeMin " & _ ' "HAVING (((Count(DateTimeStamp))=2)) " & _ ' "ORDER BY TimeMDY ASC, TimeHr ASC, TimeMin ASC" ' ' And now we feed the query above into the aggregation query below ' (another interesting SQL trick). ' 'strSQL = "SELECT TimeMDY, TimeHr, AVG(DeltaP1) AS DeltaP " & _ ' "FROM (" & strSQL & ") " & _ ' "GROUP BY TimeMDY, TimeHr " & _ ' "ORDER BY TimeMDY ASC , TimeHr ASC " ' MySQL-compatible query for multi-day strSQL = "SELECT DateTimeStamp, TimeMDY, TimeHr, TimeMin, " & _ "SUM(CASE WHEN StationName = '" & strWestSite & "' THEN Pressure ELSE -Pressure END) AS DeltaP1 " & _ "FROM FifteenMinData " & _ "WHERE StationName IN ('" & strWestSite & "','" & strEastSite & "') AND " & _ "DateTimeStamp <= " & MySQLDate(dteEndDateTime) & " AND " & _ "DateTimeStamp >= " & MySQLDate(dteStartDateTime_forQuery) & " " & _ "GROUP BY DateTimeStamp, TimeMDY, TimeHr, TimeMin " & _ "HAVING COUNT(DISTINCT StationName) = 2 " & _ "ORDER BY TimeMDY ASC, TimeHr ASC, TimeMin ASC" ' And now we feed the query above into the aggregation query below ' (another interesting SQL trick). ' For MySQL, we need to add an alias for the derived table strSQL = "SELECT TimeMDY, TimeHr, AVG(DeltaP1) AS DeltaP " & _ "FROM (" & strSQL & ") AS derived_table " & _ "GROUP BY TimeMDY, TimeHr " & _ "ORDER BY TimeMDY ASC, TimeHr ASC" End If DeltaP_SQL = strSQL End Function Function CollectTraceData(ByVal strSensor_DBName, ByVal intColor, ByRef dicTraceIO) Dim strSensorSelectClause, strSQL_trace, rstTelem Dim points(), points_smoothed(), pointCount, maxPointCount, n_records Dim dblYMax, dblYMin Dim dblXValue_raw, dblXValue Dim dblYValue_raw, dblYValue Dim arrayIndex ' Initialize array pointCount = 0 If intDays = 1 Then ' Allocate for up to a day of 5-minute data. maxPointCount = (intDays * 24 * 12) + 50 Else ' Allocate for up to a day of hourly data. maxPointCount = (intDays * 24) + 10 End If ReDim points(maxPointCount) ReDim points_smoothed(maxPointCount) dblYMax = dicTraceIO.Item("YMax") dblYMin = dicTraceIO.Item("YMin") dicTraceIO.Item("FoundData_ForThisTrace") = False If (intDays = 1) Then ' Single day query (multiple values per hour) If ((strMRTime <> "-") And (DaysDec(strMRTime) > 0.0) And (DaysDec( strMRTime) < 1.0) And (str24Hrs_state = "checked")) Then ' Go back a full day. This modification of dteStartDateTime_forQuery is in support ' of the 24h plot. dteStartDateTime_forQuery = DateAdd("d", -1, DateAdd("n", 0, strMRTime)) End If If (strSensor_DBName = "DeltaP") Then strSQL_trace = DeltaP_SQL(intDays, dicTraceIO) Else strSQL_trace = "SELECT StationName, DateTimeStamp, TimeMDY, TimeMin, TimeHr, " & strSensor_DBName & " " & _ "FROM FifteenMinData " & _ "WHERE (StationName = '" & strLocation & "') AND " & _ "(DateTimeStamp <= " & MySQLDate(dteEndDateTime) & ") AND " & _ "(DateTimeStamp >= " & MySQLDate(dteStartDateTime_forQuery) & ") AND " & _ "(" & strSensor_DBName & " IS NOT NULL) " & _ "ORDER BY TimeMDY ASC, TimeHr ASC, TimeMin ASC" End If Else ' Multi-day query (hourly data) If (strSensor_DBName = "DeltaP") Then strSQL_trace = DeltaP_SQL(intDays, dicTraceIO) Else If (strSensor_DBName = "TempMax") or (strSensor_DBName = "WindGust") Then strSensorSelectClause = "MAX(A." & strSensor_DBName & ") AS " & strSensor_DBName ElseIf (strSensor_DBName = "TempMin") Then strSensorSelectClause = "MIN(A." & strSensor_DBName & ") AS " & strSensor_DBName Else strSensorSelectClause = "AVG(A." & strSensor_DBName & ") AS " & strSensor_DBName End If strSQL_trace = "SELECT TimeMDY, TimeHr, MIN(A.StationName) AS StationName, AVG(A.DateTimeStamp) AS DateTimeStamp, " & strSensorSelectClause & " " & _ "FROM FifteenMinData AS A " & _ "WHERE (StationName = '" & strLocation & "') AND " & _ "(DateTimeStamp <= " & MySQLDate(dteEndDateTime) & ") AND " & _ "(DateTimeStamp >= " & MySQLDate(dteStartDateTime_forQuery) & ") AND " & _ "(" & strSensor_DBName & " IS NOT NULL) " & _ "GROUP BY TimeMDY, TimeHr " & _ "ORDER BY TimeMDY ASC, TimeHr ASC" End If End If Set rstTelem = Server.CreateObject("ADODB.Recordset") On Error Resume Next rstTelem.Open strSQL_trace, DBConnection, adOpenStatic, adLockReadOnly, adCmdText LogError("Recordset = rstTelem, SQL = " & strSQL_trace) On Error Goto 0 ' Collect data into the points array If Not rstTelem.EOF Then rstTelem.MoveFirst Do Until rstTelem.EOF If (intDays = 1) Then dblXValue_raw = DaysDecSinceRefF(rstTelem("TimeMDY"), rstTelem("TimeHr"), rstTelem("TimeMin")) Else dblXValue_raw = DaysDecSinceRefF(rstTelem("TimeMDY"), rstTelem("TimeHr"), 0) End If dblYValue_raw = CDbl(rstTelem( strSensor_DBName)) ' If there will the a running average done later, don't scale direction data here. ' Leave it in degrees for now. Scale after the running average (which expects degrees). If (strSensor_DBName = "WindDirection") and (strRA_state <> "checked") Then dblYValue = dblYValue_raw * dblWindNormFactor Else dblYValue = dblYValue_raw End If MinMax dblYValue, dblYMax, dblYMin ' Store in array - format: [day-since-ref, sensor-value] points(pointCount) = Array(CDbl(dblXValue_raw), CDbl(dblYValue), "", intColor) pointCount = pointCount + 1 rstTelem.MoveNext Loop ' Resize array to actual number of points If pointCount > 0 Then ReDim Preserve points(pointCount - 1) End If End If If rstTelem.State = adStateOpen Then rstTelem.Close Set rstTelem = Nothing ' Smooth the data using a running average (if requested and 5+ data points) If (strRA_state = "checked") AND (pointCount >= 5) Then ' Create the running average objects directly here Dim n_RA_stack n_RA_stack = 3 ' Initialize running average objects with stack size: n_RA_stack ' Create running average objects Set RA_x = New RunningAverage RA_x.Initialize n_RA_stack ' Reset with the total number of points to properly handle end-of-data logic RA_x.Reset pointCount If strSensor_DBName = "WindDirection" Then Set RA_y = New RunningAverage_Dir RA_y.Initialize n_RA_stack RA_y.Reset pointCount Else Set RA_y = New RunningAverage RA_y.Initialize n_RA_stack RA_y.Reset pointCount End If ' Smooth the data For arrayIndex = 0 To UBound(points) dblXValue_raw = points(arrayIndex)(0) dblYValue_raw = points(arrayIndex)(1) ' Apply running average to all points ' The RunningAverage class now handles special cases for endpoints dblXValue = RA_x.update(dblXValue_raw) ' Now, after averaging, scale the direction data to deal with the single-axis chart. ' The RunningAverage_Dir class expects the data in degrees. If (strSensor_DBName = "WindDirection") Then dblYValue = RA_y.update(dblYValue_raw) * dblWindNormFactor Else dblYValue = RA_y.update(dblYValue_raw) End If points_smoothed(arrayIndex) = Array(dblXValue, dblYValue, "", intColor) Next ReDim Preserve points_smoothed(pointCount - 1) useRunningAverage = True Else useRunningAverage = False End If ' Note that this assignment can not be made in the call to MinMax. It can't modify the ' dictionary values directly (unless you passed it the whole dictionary). If (strSensor_DBName <> "WindDirection") Then dicTraceIO.Item("YMax") = dblYMax dicTraceIO.Item("YMin") = dblYMin End If ' Return the array If pointCount > 0 Then dicTraceIO.Item("FoundData") = True dicTraceIO.Item("FoundData_ForThisTrace") = True If useRunningAverage Then CollectTraceData = points_smoothed Else CollectTraceData = points End If Else CollectTraceData = Null End If End Function Sub AddTrace(strSensorName, intSeriesType, strSeriesTitle, intLineWidth, intColor, ByRef dicTraceIO) Dim intTraceArray_index Dim intYesterdayColor, intGray Dim dblYValue, dblYValue_raw Dim dblXValue, dblXValue_raw Dim strSQL_trace Dim i Dim pointCount Dim dataPoints If (strSensorName = "WindDirection") Then dataPoints = dataPoints_WindDirection ElseIf (strSensorName = "WindGust") Then dataPoints = dataPoints_WindGust ElseIf (strSensorName = "WindSpeed") Then dataPoints = dataPoints_WindSpeed ElseIf (strSensorName = "Pressure") Then dataPoints = dataPoints_Pressure ElseIf (strSensorName = "DeltaP_trace_A") Then dataPoints = dataPoints_DeltaP_trace_A ElseIf (strSensorName = "DeltaP_trace_B") Then dataPoints = dataPoints_DeltaP_trace_B ElseIf (strSensorName = "TempAvg") Then dataPoints = dataPoints_TempAvg ElseIf (strSensorName = "TempMax") Then dataPoints = dataPoints_TempMax ElseIf (strSensorName = "TempMin") Then dataPoints = dataPoints_TempMin ElseIf (strSensorName = "DewPoint") Then dataPoints = dataPoints_DewPoint End If If (IsArray(dataPoints)) Then pointCount = UBound(dataPoints) dicTraceIO.Item("FoundData") = True dicTraceIO.Item("FoundData_ForThisTrace") = True Else dicTraceIO.Item("FoundData_ForThisTrace") = False Exit Sub End If If intSeriesType = 6 Then intGray = 200 intYesterdayColor = RGB(intGray,intGray,intGray) Else intYesterdayColor = intColor End If If (intDays = 1) Then ' Use the dataPoints array instead of directly accessing the recordset Dim yesterdayPoints, todayPoints Dim yesterdayCount, todayCount ' Initialize counters and arrays yesterdayCount = 0 todayCount = 0 ReDim yesterdayPoints(pointCount) ReDim todayPoints(pointCount) ' Loop through all data points and separate into yesterday and today (before and after midnight) For i = 0 To pointCount dblXValue = dataPoints(i)(0) dblYValue = dataPoints(i)(1) If (dblXValue < 0.0) Then ' This is yesterday's data ' Add 1.0 to the x value to move yesterday's points onto today's plot dblXValue = dblXValue + 1.0 yesterdayPoints(yesterdayCount) = Array(dblXValue, dblYValue, "", intYesterdayColor) yesterdayCount = yesterdayCount + 1 Else ' This is today's data todayPoints(todayCount) = Array(dblXValue, dblYValue, "", intColor) todayCount = todayCount + 1 End If Next ' Resize arrays to actual counts If yesterdayCount > 0 Then ReDim Preserve yesterdayPoints(yesterdayCount - 1) End If If todayCount > 0 Then ReDim Preserve todayPoints(todayCount - 1) End If ' Plot yesterday's data Chart.AddSeries(intSeriesType) Chart.SeriesInLegend = False Chart.linewidth = 1 Chart.AddXYArray yesterdayPoints ' Plot today's data Chart.AddSeries(intSeriesType) Chart.linewidth = intLineWidth Chart.SeriesTitle = strSeriesTitle Chart.AddXYArray todayPoints Else ' Multi-day chart Chart.AddSeries( intSeriesType) Chart.linewidth = intLineWidth Chart.SeriesTitle = strSeriesTitle Chart.AddXYArray dataPoints End If End Sub Sub Initialize_dicTraceIO() ' Use this to facilitate a general ByReference argument to the AddTrace subroutine. Set dicTraceIO = Server.CreateObject("Scripting.Dictionary") dicTraceIO.Add "YMax", -999 dicTraceIO.Add "YMin", 999 dicTraceIO.Add "FoundData", False dicTraceIO.Add "FoundData_ForThisTrace", False 'Used for Delta-P calculations. dicTraceIO.Add "WestSite", "" dicTraceIO.Add "EastSite", "" End Sub Sub FetchTheData() Initialize_dicTraceIO ' Set dteStartDate_forLabels and dteStartDateTime for use in queries and chart labels... dteStartDate_forLabels = DateAdd("d", (1 - intDays), dtePostedDate) ' The following is a somewhat clumsy way to deal with daylight savings time and ' timezone. Noteworthy here is the way that start and end times are shifted ' back during periods of daylight savings time. This, coupled with the way that ' points are plotted using a decimal day value that is calculated relative to ' the starting point AND using the standard time values that are in the ' database, has the net effect of shifting the standard to DLS values. It's all ' a bit confusing. Not completely sure why I originally did it this way. ' But one advantage is that when aggregating large amounts of data ' (like in the 25 day plot) each data point does not need to be converted. This ' is an efficiency that is probably not noticeable on recent computers (2015), ' but probably was worth considering when I first did this 20-some years ago. dteStartDateTime = DateAdd("d", (1 - intDays), dtePostedDate) dteEndDateTime = DateAdd("d", 1, dtePostedDate) dteNowTime = DateAdd( "h", dicTZ.item(strTimeZone), Now()) If (blnDayLightSavingsTime) Then dteNowTime = DateAdd("h", -1, dteNowTime) If (strTimeZone <> "H") Then dteStartDateTime = DateAdd("h", -1, dteStartDateTime) dteEndDateTime = DateAdd("h", -1, dteEndDateTime) End If End If ' Initialize the start time for the queries. This will later get modified for the 24h ' versions of the 1-day charts. dteStartDateTime_forQuery = dteStartDateTime If (left(strSensorType,4) = "Wind") Then dataPoints_WindDirection = CollectTraceData("WindDirection", vbWhite ,dicTraceIO) dataPoints_WindGust = CollectTraceData("WindGust", RGB(&h00,&h80,&h80), dicTraceIO) dataPoints_WindSpeed = CollectTraceData("WindSpeed", vbRed, dicTraceIO) ElseIf (strSensorType = "Temperature") Then dataPoints_TempAvg = CollectTraceData("TempAvg", vbRed, dicTraceIO) dataPoints_TempMax = CollectTraceData("TempMax", vbBlack, dicTraceIO) dataPoints_TempMin = CollectTraceData("TempMin", vbBlack, dicTraceIO) dataPoints_DewPoint = CollectTraceData("DewPoint", RGB(&h00,&h80,&h80), dicTraceIO) ElseIf (strSensorType = "Pressure") Then dataPoints_Pressure = CollectTraceData("Pressure", vbRed, dicTraceIO) ElseIf (strSensorType = "DeltaP1") Then dicTraceIO("WestSite") = "PORTLAND" dicTraceIO("EastSite") = "THE DALLES" dataPoints_DeltaP_trace_A = CollectTraceData("DeltaP", RGB(&h00,&h80,&h80), dicTraceIO) dicTraceIO("WestSite") = "THE DALLES" dicTraceIO("EastSite") = "PASCO" dataPoints_DeltaP_trace_B = CollectTraceData("DeltaP", vbRed, dicTraceIO) ElseIf (strSensorType = "DeltaP2") Then dicTraceIO("WestSite") = "KTTD" dicTraceIO("EastSite") = "KDLS" dataPoints_DeltaP_trace_A = CollectTraceData("DeltaP", RGB(&h00,&h80,&h80), dicTraceIO) dicTraceIO("WestSite") = "KDLS" dicTraceIO("EastSite") = "KHRI" dataPoints_DeltaP_trace_B = CollectTraceData("DeltaP", vbRed, dicTraceIO) End If End Sub Sub PlotTheChart() ' Set the ContentType 'Response.ContentType = "image/JPEG" ' Instantiate the Chart component Set Chart = Server.CreateObject ("ASPChart.Chart") Chart.JPEGQuality = 90 '80 Dim dblTraceArray, intTraceArray_index, directAxisScale ' Add a separate (pseudo) trace to do the x-axis labeling. Shift the y ' value by negative 200 so the points don't show on the plot. Also prevent ' it from showing in the legend. ' ' Have tried more direct methods of charting the labels as part of the data ' traces but always ran into problems. This somewhat indirect (but ' successful) method, offers more control and is general for any numeric ' based x axis. Chart.AddSeries (5) Chart.linewidth = 0 Chart.SeriesTitle = " " Chart.SeriesInLegend = False If (intDays = 1) Then TimeLabels = Array("12m","1","2","3","4","5","6am","7","8","9","10","11","12n","1","2","3","4","5","6pm","7","8","9","10","11","12m") For intHour = 0 to 24 ' The key difference in this dummy trace is that it has a parameter ' for the label. All the data traces below have an empty string in ' that position. MyChartAddXY (CDbl(intHour)/24.0), 0 - 200, TimeLabels(intHour), vbWhite Next Else ' Make a special label trace (dummy) for multiple-day charts... If (intDays >= 2) AND (intDays <= 4) Then intLabelsPerDay = 4 ElseIf (intDays >= 5) AND (intDays <= 9) Then intLabelsPerDay = 2 ElseIf (intDays >= 10) AND (intDays <= 25) Then intLabelsPerDay = 1 Else ' Shouldn't be able to get here... End If intXLabels = (intDays * intLabelsPerDay) + 1 ' Dim the dynamic array... ReDim strTimeLabels(intXLabels) dblDaysIncrement = 1 / intLabelsPerDay For intJ = 0 To intXLabels - 1 dblDaysFraction = intJ * dblDaysIncrement ' Put a Day label on the integer values (midnight)... If (dblDaysFraction = Int(dblDaysFraction)) Then dteLabelDate = DateAdd("d", Int(dblDaysFraction), dteStartDate_forLabels) strTimeLabels(intJ) = Left(WeekDayName(WeekDay(dteLabelDate), True),2) & "-" & Day(dteLabelDate) Else dblFractionalPart = dblDaysFraction - Int(dblDaysFraction) If (dblFractionalPart = 0.50) Then ' Suppress the 12n marks for 7 though 9. If (intDays <= 6) Then strTimeLabels(intJ) = "12n" Else strTimeLabels(intJ) = "" End If Else strTimeLabels(intJ) = "" 'CStr(dblDaysFraction) End If End If Next ' Plot the pseudo trace.... For intJ = 0 To intXLabels - 1 ' The key difference in this pseudo trace is that it has a parameter ' for the label. All the data traces below have an empty string in ' that position. MyChartAddXY intJ * dblDaysIncrement, 0 - 200, strTimeLabels(intJ), vbWhite Next End If '=============================================================================== ' Add trace(s) depending on the sensor or plot type... '=============================================================================== If (left(strSensorType,4) = "Wind") Then intGray = 175 ' Make horizontal lines for the compass points. Do this before adding the ' trace lines so data points will lay on top of this reference lines. If (strSensorType = "Wind36") Then AddHorizontalLine_gray 1, intGray, 45 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 135 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 225 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 315 * dblWindNormFactor End If ' These are common to both Wind40 and Wind36 AddHorizontalLine_gray 1, intGray, 0 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 90 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 180 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 270 * dblWindNormFactor AddHorizontalLine_gray 1, intGray, 360 * dblWindNormFactor AddTrace "WindDirection", 6, "Direction ", 3, vbWhite, dicTraceIO AddTrace "WindGust", 5, "Maximum Speed", 2, RGB(&h00,&h80,&h80), dicTraceIO intMaxGust = dicTraceIO.Item("YMax") AddTrace "WindSpeed", 5, "Average Speed", 2, vbRed, dicTraceIO If dicTraceIO.Item("FoundData") Then ' To be consistent with the other sensor charts, putting these scale ' limits here, after the trace filling calls above. Chart.VertAxisMin = 0.0 '-10 If (intMaxGust > 40) then Chart.VertAxisMax = CDbl(intMaxGust) Else Chart.VertAxisMax = 40.0 End If Chart.AddAxisLabel 1, "Wind Speed (mph)" If (intDays > 1) then Chart.ChartTitleAdd " Wind at " & strNameForPlot Chart.HorizAxisMin = 0.00 Else Chart.ChartTitleAdd " Wind at " & strNameForPlot & " on " & WeekDayName(WeekDay(dtePostedDate)) & " " & dtePostedDate Chart.HorizAxisMin = 0.04 End If ' Use tweak of -4 if there is a carriage return after each image element ' in the div. intPixelRightShift_tweak = -4 If (intDays >= 10) Then Chart.Width = 1250 + 61 ' The 61 helps to get the days to line up with the temperature chart. intPixelRightShift = -210 + intPixelRightShift_tweak - 3 ' The -3 is a secondary tweak needed after I added the 61 in the line above. Else Chart.Width = 855 intPixelRightShift = -188 + intPixelRightShift_tweak End If ' Set the chart height based on the y-axis maximum value. Scale up the ' plotting area by the ratio of intMaxGust/40. intNonPlottingHeight = 75 If (intMaxGust > 40) then Chart.Height = ((500 - intNonPlottingHeight) * (intMaxGust/40)) + intNonPlottingHeight ' This gets used in the style-sheet the positions the directions-overlay image. intPixelBottomShift = Fix((intMaxGust * 0.320) - 11) 'This is always positive. Else Chart.Height = 500 intPixelBottomShift = 0 End If Chart.LeftAxisIncrement = 5 End If ElseIf (strSensorType = "Temperature") Then ' Do this one first. This one should return data for any type ' of temperature plot. If not, don't try the other parts. AddTrace "TempAvg", 5, "Dry Bulb", 2, vbRed, dicTraceIO If dicTraceIO.Item("FoundData") Then If IsArray(dataPoints_TempMin) Then AddTrace "TempMin", 5, " Min", 1, vbBlack, dicTraceIO AddTrace "TempMax", 5, " Max", 1, vbBlack, dicTraceIO End If If IsArray(dataPoints_DewPoint) Then AddTrace "DewPoint", 5, "Dew Point", 2, RGB(&h00,&h80,&h80), dicTraceIO End If ' Ongoing (overall) Min and Max values are collected in dicTraceIO as each trace ' generated. sglTempMin = dicTraceIO("YMin") sglTempMax = dicTraceIO("YMax") sglTempRange = sglTempMax - sglTempMin ' To be consistent with the other sensor charts, putting these scale ' limits here, after the trace filling loop above. But seems to work ' either way here... intTempDiffScalingThreshold = 40 intNonPlottingHeight = 108 If (sglTempRange < intTempDiffScalingThreshold) then Chart.VertAxisMin = sglTempMin - ((intTempDiffScalingThreshold - sglTempRange)/2) Chart.VertAxisMax = sglTempMax + ((intTempDiffScalingThreshold - sglTempRange)/2) Chart.Height = 500 Else ' The 0.2 keeps the max and min data from being obscured by the outer ' boundaries of the charting area. Chart.VertAxisMin = sglTempMin - 0.2 Chart.VertAxisMax = sglTempMax + 0.2 Chart.Height = ((500 - intNonPlottingHeight) * (sglTempRange/intTempDiffScalingThreshold)) + intNonPlottingHeight End If Chart.LeftAxisIncrement = 5 ' Y axis label Chart.AddAxisLabel 1, "Temperature (F)" If (intDays > 1) Then Chart.ChartTitleAdd " Temperature at " & strNameForPlot Else Chart.ChartTitleAdd " Temperature at " & strNameForPlot & " on " & WeekDayName(WeekDay(dtePostedDate)) & " " & dtePostedDate End If If (intDays >= 10) Then Chart.Width = 1250 Else Chart.Width = 791 '780 End If End If ElseIf (strSensorType = "Pressure") Then AddTrace "Pressure", 5, "no trace label", 2, vbRed, dicTraceIO If dicTraceIO.Item("FoundData") Then Chart.SeriesInLegend = False sglPressureMin = dicTraceIO.Item("YMin") sglPressureMax = dicTraceIO.Item("YMax") Chart.AddAxisLabel 1, "Pressure (Inches Hg)" If (intDays > 1) then Chart.ChartTitleAdd " Barometer at " & strNameForPlot Else Chart.ChartTitleAdd " Barometer at " & strNameForPlot & " on " & WeekDayName(WeekDay(dtePostedDate)) & " " & dtePostedDate end If ' Note: these axis limits only work if they come after ' the chart filling loop above... If (sglPressureMin < 29.42) then Chart.VertAxisMin = sglPressureMin - 0.005 Else Chart.VertAxisMin = 29.41 End If If (sglPressureMax > 30.42) then Chart.VertAxisMax = sglPressureMax + 0.005 Else Chart.VertAxisMax = 30.43 End If If (sglPressureMin = 0) then Chart.VertAxisMin = -0.5 Chart.VertAxisMax = 0.5 End If Chart.LeftAxisIncrement = 0.1 'Chart.AddAxisLabel 1, "Pressure (Inches Hg)" Chart.Height = 500 If (intDays >= 10) Then Chart.Width = 1128 Else Chart.Width = 685 End If End If ElseIf (Left(strSensorType,6) = "DeltaP") Then ' Add some horizontal lines Chart.AddSeries (5) Chart.linewidth = 2 Chart.SeriesInLegend = False MyChartAddXY 0, 0, "", vbBlack If (Request.QueryString("specName") = "") Then MyChartAddXY intDays+1, 0, "", vbWhite Else ' Gray line (if request is for the 50Webs example chart page). MyChartAddXY intDays+1, 0, "", RGB(&hB5,&hB5,&hB5) End If ' Add the delta-P traces. If (strSensorType = "DeltaP1") Then dicTraceIO("WestSite") = "PORTLAND" dicTraceIO("EastSite") = "THE DALLES" AddTrace "DeltaP_trace_A", 5, "Portland - The Dalles ", 2, RGB(&h00,&h80,&h80), dicTraceIO dicTraceIO("WestSite") = "THE DALLES" dicTraceIO("EastSite") = "PASCO" AddTrace "DeltaP_trace_B", 5, "The Dalles - Pasco", 2, vbRed, dicTraceIO '"NORTH BEND", "PASCO" ElseIf (strSensorType = "DeltaP2") Then dicTraceIO("WestSite") = "KTTD" dicTraceIO("EastSite") = "KDLS" AddTrace "DeltaP_trace_A", 5, "Troutdale - The Dalles", 2, RGB(&h00,&h80,&h80), dicTraceIO dicTraceIO("WestSite") = "KDLS" dicTraceIO("EastSite") = "KHRI" AddTrace "DeltaP_trace_B", 5, "The Dalles - Hermiston", 2, vbRed, dicTraceIO ' dicTraceIO("WestSite") = "KTTD" ' dicTraceIO("EastSite") = "KHRI" ' AddTrace "DeltaP_trace_B", 5, "Troutdale - Hermiston", 2, vbBlue, dicTraceIO End If If dicTraceIO.Item("FoundData") Then ' Force limits on the Y axis for the Delta-P chart. dblDPmin = dicTraceIO("YMin") dblDPmax = dicTraceIO("YMax") If (dblDPmin < -0.08) Then Chart.VertAxisMin = dblDPmin - .001 Else Chart.VertAxisMin = -0.08 End If If (dblDPmax > 0.18) Then Chart.VertAxisMax = dblDPmax + 0.001 Else Chart.VertAxisMax = 0.18 End If If (intDays > 1) Then Chart.ChartTitleAdd "Delta-P" Else Chart.ChartTitleAdd "Delta-P on " & WeekDayName(WeekDay(dtePostedDate)) & " " & dtePostedDate End If Chart.LeftAxisIncrement = 0.05 Chart.AddAxisLabel 1, "Pressure Differential (Inches Hg)" If (intDays >= 10) Then Chart.Width = 1270 Else Chart.Width = 875 End If ' Scale the height of the image if the y range is larger than the default of 0.26. intNonPlottingHeight = 90 If ((Chart.VertAxisMax - Chart.VertAxisMin) > 0.26) Then Chart.Height = ((510 - intNonPlottingHeight) * ((Chart.VertAxisMax - Chart.VertAxisMin)/0.26)) + intNonPlottingHeight Else Chart.Height = 510 End If End If Else ' Shouldn't ever get here... RBC "No data or no match found for the specified sensor type." End If '============================================================================= ' Control chart axes and labeling... ' (This is done for every type of plot) '============================================================================= If dicTraceIO.Item("FoundData") Then ' Plot the LatestRecord and the NOW lines. If ((intDays = 1) and (str24Hrs_state = "checked")) Then AddVerticalLine DaysDec( strMRTime), 1 AddVerticalLine DaysDec( dteNowTime), 1 End If Chart.HorizAxisMax = intDays Chart.ShowMinorTicks false, false If (intDays > 1) then ' Set Horizontal Axis Label Style to: Axis Scales (2) Chart.HLabelStyle = 0 If (blnDayLightSavingsTime And (strTimeZone <> "H")) Then Chart.AddAxisLabel 2, "Days Starting with " & WeekDayName(WeekDay(dteStartDate_forLabels)) & " " & FormatDateTime(dteStartDate_forLabels, vbShortDate) & " (" & strTimeZone & "DT)" Else Chart.AddAxisLabel 2, "Days Starting with " & WeekDayName(WeekDay(dteStartDate_forLabels)) & " " & FormatDateTime(dteStartDate_forLabels, vbShortDate) & " (" & strTimeZone & "ST)" End If Chart.HorizAxisMin = 0.0 Else ' Set Horizontal Axis Label Style to: Automatic (0) Chart.HLabelStyle = 0 If (blnDayLightSavingsTime And (strTimeZone <> "H")) Then Chart.AddAxisLabel 2, "Hour of the Day (" & strTimeZone & "DT)" Else Chart.AddAxisLabel 2, "Hour of the Day (" & strTimeZone & "ST)" End If ' Make a little more room on the y axis for the last point from yesterday. The ' square boxes (markers) for the direction trace enforce a little more room on ' their own, so the non-wind plots require a little more wiggle room on each ' end of the x-axis. If (left(strSensorType,4) = "Wind") Then Chart.HorizAxisMin = -0.001 Chart.HorizAxisMax = intDays + 0.001 Else 'Chart.HorizAxisMin = 0.00 Chart.HorizAxisMin = -0.003 Chart.HorizAxisMax = intDays + 0.003 End If End If Chart.ChartTitleFont.Size = 16 Chart.ChartTitleFont.Name = "Arial" 'Chart.ChartTitleFontColor = vbBlue Chart.ChartTitleFontColor = RGB(&h00,&h80,&h80) Chart.LegendFont.Size = 10 Chart.AxisLabelFontBottom.Size = 10 Chart.AxisLabelFontLeft.Size = 10 Chart.BevelOuter = false If (Request.QueryString("specName") <> "") Then Chart.GradientVisible = false Else Chart.GradientVisible = true End If Chart.GradientStartColor = RGB(&hff,&hcc,&h99) Chart.GradientEndColor = vbWhite Chart.PanelColor = vbWhite Chart.View3D = false Chart.LegendVisible = true Chart.LegendStyle = 1 ' Set the filename, save the image and write the image tag. ' Do this with sessionID and random name generated via the ' FileSystemObject. First make a string with a random name in it. Use ' split here to get rid of the txt extension that normally is returned. strRandomNameString = Split(Server.CreateObject("Scripting.FileSystemObject").GetTempName,".")(0) If (Request.QueryString("specName") <> "") Then strFileName2 = Request.QueryString("specName") & ".jpg" Else strFileName2 = "S" & "_" & Session.SessionID & "_" & strRandomNameString & ".jpg" End If 'Response.Write "filename = " & strPathToImageDir & strFileName2 Chart.FileName = strPathToImageDir & strFileName2 Chart.SaveChart Set Chart = nothing ' Put these two images into a DIV element that doesn't wrap! Then ' position the directions overlay relative to the original chart image. RC "<div style='white-space:nowrap;'>" RC "<img id='chartimage' style='visibility:hidden' src='" & strURLPathToImageDir & strFileName2 & "'>" If (Left(strSensorType,4) = "Wind") Then If (strSensorType = "Wind40") Then directAxisScale = "'pictures/directions_40.gif'" ElseIf (strSensorType = "Wind36") Then directAxisScale = "'pictures/directions_36.gif'" End If RC "<img id='directions' src=" & directAxisScale & _ "style='visibility:hidden; position:relative; left:" & intPixelRightShift & "px; bottom:" & intPixelBottomShift & "px'>" Else ' Could add secondary images for other sensors types here... End If RC "</div>" Else Response.Write "The query has returned no data for the selected sensor, location, and time period." End If End Sub Function TimeZone( strStationName) strSQL = "SELECT StationNames.StationName, StationNames.NickName, StationNames.TimeZone FROM StationNames " & _ "WHERE (StationName = '" & strStationName & "') " Set rstTimeZone = Server.CreateObject("ADODB.Recordset") On Error Resume Next rstTimeZone.Open strSQL, DBConnection, adOpenStatic, adLockReadOnly, adCmdText LogError("Recordset = rstTelem, SQL = " & strSQL_trace) On Error Goto 0 If (rstTimeZone.RecordCount = 0) Then TimeZone = "?" Else rstTimeZone.MoveFirst TimeZone = rstTimeZone("TimeZone") End If If rstTimeZone.State = adStateOpen Then rstTimeZone.Close Set rstTimeZone = Nothing End Function Function RegionString( strRegion) If (strRegion = "MN") Then RegionString = "Minnesota Weather" ElseIf (strRegion = "CR") Then RegionString = "Columbia Basin Weather" ElseIf (strRegion = "Misc") Then RegionString = "Misc. Weather Stations" Else RWBR "No match when branching on Region." End If End Function '======================================================================================= ' Main program body (start here and execute every time in) '======================================================================================= ' Build the page %> <html> <head> <meta name='Author' content='Jim Miller'> <meta name='keywords' content='WA,Washington,OR,Orgeon,MN,Minnesota,columbia,basin,weather,chart,plot,roosevelt, windsurfing,gorge,richland,wind,temperature,pressure,dewpoint'> <meta charset="UTF-8"> <!-- Icon for browsers using Waconia. --> <link rel='SHORTCUT ICON' href='pictures/favicon.ico'> <title>Waconia Weather Database</title> <style> TD {font-family: Times;} TD.data {font-family: Arial;} A {color:#008080; text-decoration:underline} A:hover {color:#008080; text-decoration:none; background:#FFF1E3} A.noline {color:#008080; text-decoration:none; font-size:18pt; font-weight:bolder; } A.noline:hover {color:#008080; text-decoration:underline; font-size:18pt; font-weight:bolder; background:#FFCC99} span.regionstring {color:#008080; font-size:18pt; font-weight:bolder;} div.pageblock {min-width: 650px; max-width: 1000px;} </style> <!--[if IE]> <style> div.pageblock {width: expression(document.body.clientWidth > 1000? "1000px": "auto" )}; </style> <![endif]--> </head> <% strServerName = UCase(request.servervariables("SERVER_NAME")) strPathToImageDir = request.servervariables("APPL_PHYSICAL_PATH") & "\chart-images\" strURLPathToImageDir = "chart-images/" ' Connect to the database. Set DBConnection = CreateObject("ADODB.Connection") ' Open a connection to MySQL (telem schema) using 32-bit system DSN (MySQL ODBC 5.3 Unicode Driver) DBConnection.Open "DSN=MySQL_telem_for_ASP;" Set dicTZ = Server.CreateObject("Scripting.Dictionary") dicTZ.Add "H", -4 dicTZ.Add "AK", -3 dicTZ.Add "P", -2 dicTZ.Add "M", -1 dicTZ.Add "C", 0 dicTZ.Add "E", 1 dicTZ.Add "J", 15 dicTZ.Add "NZ", 18 serverTimeArray = split(Now()," ") serverTime = serverTimeArray(1) ' Establish defaults ' Region_state (hidden) is used to facilitate changing the location to a default value ' when the region is changed. If (Request.QueryString("Region_state") = "") Then strRegionState = "new" Else strRegionState = Request.QueryString("Region_state") End If If (Request.QueryString("Region") = "") Then strRegion = "CR" Else strRegion = Request.QueryString("Region") End If If (Request.QueryString("chk24Hrs") = "on") Then str24Hrs_state = "checked" Else str24Hrs_state = "" End If If (Request.QueryString("chkRA") = "on") Then strRA_state = "checked" Else strRA_state = "" End If If (Request.QueryString("chkTimer") = "on") Then strTimer_state = "checked" Else strTimer_state = "" End If If (strTimer_state = "checked") Then 'Check to see how far off the 5-minute mark. This should serve 'to compensate for the drift in the client side timer. 'Get the seconds and minutes from the server time. intSeconds_FromSeconds = CInt(right(serverTime,2)) intMinutes = CInt(Split(serverTime,":")(1)) 'How many five minute chunks. dblFiveMinutes = CDbl(intMinutes)/5.0 'Take the fractional part of this and convert to seconds. intSeconds_FromMinutes = CInt(round(300*(dblFiveMinutes - Fix(dblFiveMinutes)),0)) 'Subtract both of these values from 300 to get the proper delay for the client. 'Then add 9 to keep it tracking at 10 seconds after the 5-minute mark. intDelay_to_5min = 300 - intSeconds_FromMinutes - intSeconds_FromSeconds + 9 strInitializeTimer = "initializeTimer(" & CStr(intDelay_to_5min) & ");" Else strInitializeTimer = "" End If blnPostedDate_default = False If (Request.QueryString("EndDate") = "") Then ' Use the current date for a default. dtePostedDate = CStr(Date()) blnPostedDate_default = True Else ' Split to just get the DATE part of this post. dtePostedDate = split(Request.QueryString("EndDate")," ")(0) End If If (Request.QueryString("Days") = "") Then intDays = 1 Else intDays = Request.QueryString("Days") End If If (Request.QueryString("Sensor") = "") Then strSensorType = "Wind40" Else strSensorType = Request.QueryString("Sensor") ' Don't allow request for Delta-P from any region but CR. If (strRegion <> "CR") And (strSensorType = "DeltaP") Then strSensorType = "Wind40" End If End If ' Set the normalization factor for the wind direction data If (strSensorType = "Wind40") Then dblWindNormFactor = 40.0 / 360.0 Else dblWindNormFactor = 1.0 / 10.0 End If ' Set a default value for the location if the first time in or if the user changes ' the region. If ((Request.QueryString("Location") = "") or (strRegionState = "new")) Then If (strRegion = "CR") Then strLocation = "PASC" ElseIf (strRegion = "MN") Then strLocation = "KMKT" ElseIf (strRegion = "Misc") Then strLocation = "KCQX" Else strLocation = "" RWBR "No match in region branch..." End If Else strLocation = Request.QueryString("Location") End If If ((strSensorType = "Wind40") OR (strSensorType = "Wind36")) Then strShowImages_command = "showImage();showDirections();" Else strShowImages_command = "showImage();" End If strTimeZone = TimeZone( strLocation) RC "<body onLoad=testJS();" & strShowImages_command & strInitializeTimer & _ " bgcolor=#FFCC99 link=#008080 vlink=#008080 topmargin=2 style=font-family:Arial;>" RC "<div class='pageblock'>" ' If the region is specified, then make preparations for populating the table ' including getting the most recent values for all the sensor data. If (Request.QueryString("Region") <> "") Then ' If the end date in the chart request is within daylight savings time, then ' set the DLS flag. Add 3 hours to make sure you evaluate the day after the ' 2am change over point. If (DaylightSavingsTime(dateadd("h",3,dtePostedDate))) Then blnDayLightSavingsTime = True End If ' Find the time of the most recent station record. strSQL = "SELECT * FROM FifteenMinData " & _ "WHERE (StationName = '" & strLocation & "') " & _ "ORDER BY DateTimeStamp DESC " & _ "LIMIT 1" Set rstMostRecent = Server.CreateObject("ADODB.Recordset") On Error Resume Next rstMostRecent.Open strSQL, DBConnection, adOpenStatic, adLockReadOnly, adCmdText LogError("Recordset = rstTelem, SQL = " & strSQL_trace) On Error Goto 0 ' Check to see if there are any records before applying the MoveFirst method If (Not rstMostRecent.EOF) Then ' If a default value was used for the posted date, correct it if the posted date ' is more recent than the most recent data. If blnPostedDate_default and (DateDiff("d", dtePostedDate, rstMostRecent("TimeMDY")) < 0) Then dtePostedDate = rstMostRecent("TimeMDY") End If 'Warning: this variable changes type here. strMRTime = rstMostRecent("TimeMDY") & " " & rstMostRecent("TimeHr") & ":" & rstMostRecent("TimeMin") strMRTime = FormatDateTime(strMRTime, vbGeneralDate) If (rstMostRecent("WindDirection") = -10) Then strMRWindDir = "Variable" Else If IsNull(rstMostRecent("WindDirection")) Then strMRWindDir = "-" Else strMRWindDir = rstMostRecent("WindDirection") & _ " deg. [" & DirectionLabel(rstMostRecent("WindDirection")) & "]" & _ " [" & FormatNumber(rstMostRecent("WindDirection") * dblWindNormFactor, 1) & "]" End If End If If IsNull(rstMostRecent("WindSpeed")) Then strMRWindAvg = "-" strMRWindMax = "-" Else strMRWindAvg = rstMostRecent("WindSpeed") strMRWindMax = rstMostRecent("WindGust") End If If IsNull(rstMostRecent("Pressure")) Then strMRPressure = "-" Else strMRPressure = round(rstMostRecent("Pressure"),2) End If strMRTemp = rstMostRecent("TempAvg") If (IsNull(strMRTemp)) Then strMRTemp = "-" End If strMRDewPoint = rstMostRecent("DewPoint") If (IsNull(strMRDewPoint)) Then strMRDewPoint = "-" End If Else strMRTime = "-" strMRWindDir = "-" strMRWindAvg = "-" strMRWindMax = "-" strMRTemp = "-" strMRPressure = "-" strMRDewPoint = "-" End If If rstMostRecent.State = adStateOpen Then rstMostRecent.Close Set rstMostRecent = Nothing strButtonLabel = "Update" Else dtePostedDate = "" ' Before first post (first time in) just show these dashes in the table... strMRTime = "-" strMRWindDir = "-" strMRWindAvg = "-" strMRWindMax = "-" strMRTemp = "-" strMRPressure = "-" strMRDewPoint = "-" strButtonLabel = "Chart" End If '=========================================================================== ' The current data table and CONTROLS form... '=========================================================================== RC "<table border='1'>" ' First row RC "<tr>" RC "<td class='data' width='37%' rowspan='3'>" 'RC "<p align='center'><a onmouseover=""changeRegionAnchorValue('" & strRegion & "')"" onmouseout=""changeRegionAnchorValue('" & strTitle & "')"" name='regionanchor' id='regionanchor' class='noline' href='" & strRegionURL & "'>" & strTitle & "</a>&nbsp;<br>" RC "<p align='center'><span class='regionstring'>" & RegionString( strRegion) & "</span><br>" 'RC "<a target='_blank' href='https://waconia.triquence.org/faq.html'><font size='2' color='#FF0000'>Help</font>" & _ ' "<font size='2' color='#008080'>: FAQs</font></a>&nbsp;" If (strRegion = "MN") Then RC "<a href='pictures/mn_sites.jpg'><font size='2' color='#008080'>Sites</font></a>&nbsp;" End If RC "<a href='default.htm'><font size='2'>(home)</font></a>" ' Create a object for working with the image files... Set fsoObject = CreateObject("Scripting.FileSystemObject") ' Note: path to image directory is defined in include file. Set fdrObject = fsoObject.GetFolder(strPathToImageDir) ' Clean out any old temp image files. This is a new approach that doesn't depend on script in the global ASA intFileCount = 0 For Each filObject in fdrObject.Files Dim fileAge, fileDate fileDate = filObject.DateLastModified fileAge = DateDiff("h", fileDate, Now()) ' Count files that are less than 1 day old. If (fileAge <= 24) Then intFileCount = intFileCount + 1 End If ' Delete files that are more than three days old. If (fileAge > 72) Then filObject.delete End If Next ' Write out a count of image files in the directory (1 and 7 day counts). ' Put the serverTime in a span so can access it from the client (if needed, may not actually use this). RC "<font color='#008080' size='1'>" & _ "&nbsp;&nbsp;" & intFileCount & "-(1d)&nbsp;&nbsp;" & fdrObject.Files.Count & "-(3d)&nbsp;&nbsp;" & _ "<span id='spServerTime' name='spServerTime'>" & serverTime & "</span>" & _ " (" & AgeOfData(strMRTime) & ")" & _ "</font>" & _ "</p>" RC "</td>" ' Rest of the table headers RC "<td width='23%' align='center' rowspan='2'><b><font color='#FF0000'>Latest</font>" RC "<font color='#008080'> Reading" RC "</font></b>" RC "</td>" RC "<td width='26%' align='center' colspan='3'><font color='#008080'><b>Wind </b><font size='2'> (mph)</font></font></td>" RC "<td nowrap width='6%' align='center' colspan='2' rowspan='1'><font color='#008080'><b>Temp</b><font size='2'> (<sup>o</sup>F)</font></font></td>" RC "<td width='8%' align='center' rowspan='2'><font color='#008080'><b>Pressure<br></b><font size='2'> (in Hg" & strHGSL & ")</font></font></td>" RC "</tr>" ' Second row RC "<tr>" RC "<td width='6%' align='center'><font color='#008080' size='2'>Avg</font></td>" RC "<td width='5%' align='center'><font color='#008080' size='2'>Max</font></td>" RC "<td width='18%' align='center'><font color='#008080' size='2'>Direction</font></td>" RC "<td align='center'><font color='#008080' size='2'>DryBulb</font></td>" RC "<td align='center'><font color='#008080' size='2'>DewPoint</font></td>" RC "</tr>" ' Third row RC "<tr>" RC "<td class='data' width='20%' align='center'><font color='#000000' size='2'>" If (strMRTime <> "-") Then 'rwbr "strMRTime = " & strMRTime & ", strTimeZone = " & strTimeZone & ", DaylightSavingsTime(strMRTime) = " & DaylightSavingsTime(strMRTime) If (DaylightSavingsTime(strMRTime) And (strTimeZone <> "H")) Then Response.Write DateAdd("h",1,strMRTime) & " (" & strTimeZone & "DT)" Else Response.Write strMRTime & " (" & strTimeZone & "ST)" End If Else Response.Write strMRTime End If RC "</font></td>" RC "<td class='data' width='6%' align='center'><font color='#000000' size='2'>" & strMRWindAvg & "</font></td>" RC "<td class='data' width='5%' align='center'><font color='#000000' size='2'>" & strMRWindMax & "</font></td>" RC "<td class='data' width='18%' align='center'><font color='#000000' size='2'>" & strMRWindDir & "</font></td>" RC "<td class='data' width='6%' align='center'><font color='#000000' size='2'>" & strMRTemp & "</font></td>" RC "<td class='data' width='6%' align='center'><font color='#000000' size='2'>" & strMRDewPoint & "</font></td>" RC "<td class='data' width='8%' align='center'><font color='#000000' size='2'>" & strMRPressure & "</font></td>" RC "</tr>" RC "</table>" '============================================================================= ' Build a line of controls '============================================================================= RC "<br>" ' Note that the GET method invokes the QueryString approach and submits form data in the URL. RC "<form method='GET' accept-charset='utf-8' action='rosy.asp' name='ChartingParameters' id='ChartingParameters'>" ' Removing the "name" parameter here avoids submitting this with the form. ' Another option is to use "button" instead of "input". ' The submit button. 'RC "<...........................................name='submit_button'>" RC "<input type='button' title='Query the database and update the plot.' value='" & strButtonLabel & "' name='myButton' id='myButton' style='width: 90px' onclick='submitform()'>" ' Region RC "<select title='Region' size='1' name='Region' id='Region' onChange='setRegionState()'>" arrRegions = Array("MN","CR","Misc") For each strRegionValue in arrRegions If (strRegionValue = strRegion) Then RC " <option selected>" & strRegionValue Else RC " <option>" & strRegionValue End If Next RC "</select>" ' A hidden field that serves to indicate whether a new region has been selected. This is needed ' for determining the default location if the region selection changes. RC "<input type='hidden' name='Region_state' id= 'Region_state' value='old'>" ' Location strSQL = "SELECT StationNames.Priority, StationNames.StationName, StationNames.NickName FROM StationNames " & _ "WHERE (Region='" & strRegion & "') " & _ "ORDER BY Priority, NickName" Set rstStations = Server.CreateObject("ADODB.Recordset") On Error Resume Next rstStations.Open strSQL, DBConnection, adOpenStatic, adLockReadOnly, adCmdText LogError("Recordset = rstTelem, SQL = " & strSQL_trace) On Error Goto 0 RC "<select title='Location of weather station' size='1' name='Location' id='Location' onChange='submitform()'>" rstStations.movefirst Do until rstStations.EOF ' Exclude inactive stations from the selection list (marked as "skip" in the database). If (InStr(rstStations("Priority"),"skip")=0) Then 'Populate the list and set the selected station for the two regions. If (rstStations("StationName") = strLocation) Then strNameForPlot = rstStations("NickName") RC " <option value='" & rstStations("StationName") & "' selected>" & rstStations("NickName") Else RC " <option value='" & rstStations("StationName") & "'>" & rstStations("NickName") End If End If rstStations.movenext loop RC "</select>" If rstStations.State = adStateOpen Then rstStations.Close Set rstStations = Nothing ' Click for next location. RC "<INPUT title='Click to step through the list of locations.' type='button' style='WIDTH:18px; HEIGHT:23px; COLOR:black; padding-left:3px;' value='>' id='btnStepLocationForward' name='btnStepLocationForward' onClick='stepLocationForward()'>" ' Sensor type WeatherTypes = Array("Wind (0-36)", "Wind (0-40)", "Temperature", "Pressure", "Delta-P1", "Delta-P2") WeatherTypes_URL = Array("Wind36", "Wind40", "Temperature", "Pressure", "DeltaP1" , "DeltaP2") WeatherTypes_count = UBound(WeatherTypes) ' Don't offer the Delta-P plot anywhere but in the Columbia Basin. If (strRegion <> "CR") then WeatherTypes_count = WeatherTypes_count - 2 End If RC "<select title='Sensor type' size='1' name='Sensor' id='Sensor' onChange='submitform()'>" For intJ = 0 to WeatherTypes_count If ((WeatherTypes_URL(intJ)= strSensorType) OR ((strSensorType = "") AND (WeatherTypes_URL(intJ)= "Wind40"))) Then RC " <option selected value=" & WeatherTypes_URL(intJ) & " >" & WeatherTypes(intJ) Else RC " <option value=" & WeatherTypes_URL(intJ) & " >" & WeatherTypes(intJ) End If Next RC "</select>" ' Select the last day. strSQL = "SELECT DISTINCT DaysGleaned.TimeMDY FROM DaysGleaned ORDER BY DaysGleaned.TimeMDY DESC" ' See IIShelp for description of parameters: Open Method (Recordset - ADO). ' The AdCmdText just tells it that it is a SQL string in the first parameter. ' Alternatively you could tell it that the first parameter is a table name... Set rstDate = Server.CreateObject("ADODB.Recordset") On Error Resume Next rstDate.Open strSQL, DBConnection, adOpenStatic, adLockReadOnly, adCmdText LogError("Recordset = rstTelem, SQL = " & strSQL_trace) On Error Goto 0 RC "<select title='Last day' size='1' name='EndDate' id='EndDate' onChange='submitform()'>" rstDate.movefirst do until rstDate.EOF ' Coerce the date object to a string by using the (& "") If ((dtePostedDate = (rstDate("TimeMDY") & "")) OR ((dtePostedDate = "") AND (rstDate("TimeMDY") = Date()))) then RC " <option selected>" & rstDate("TimeMDY") & " " & weekdayname(weekday(rstDate("TimeMDY")),True) Else RC " <option>" & rstDate("TimeMDY") & " " & weekdayname(weekday(rstDate("TimeMDY")),True) End If rstDate.movenext loop RC "</select>" If rstDate.State = adStateOpen Then rstDate.Close Set rstDate = Nothing ' Select the time range. RC "&nbsp;&nbsp;&nbsp;<font color='#008080'>Days:</font>" RC "<select title='Time range' size='1' name='Days' id='Days' onChange='submitform()'>" DaysChoices = Array("1","2","3","4","5","6","7","8","9","10","14","25") For each DayValue in DaysChoices If (DayValue = intDays) Then RC " <option selected>" & DayValue Else RC " <option>" & DayValue End If Next RC "</select>" ' Time steppers RC "<INPUT title='Click to step back in time.' type='button' style='WIDTH: 18px; HEIGHT: 23px; COLOR: black; padding-left:3px;' value='<' id='btnStepBack' name='btnStepBack' onClick='stepBack()'>" RC "<INPUT title='Click to step forward in time.' type='button' style='WIDTH: 18px; HEIGHT: 23px; COLOR: black; padding-left:3px;' value='>' id='btnStepForward' name='btnStepForward' onClick='stepForward()'>" ' The 24-Hour charting option. RC "&nbsp;&nbsp;" & _ "<input " & str24Hrs_state & " type='checkbox' name='chk24Hrs' " & _ "title='Select to display 24 hours of the most recent data (including data from yesterday) on the 1-day chart. " & _ "Please refer to the FAQ on the ""24h"" checkbox.' " & _ "onClick='submitform()'/>" & _ "<font size='2' color='#008080'>24h</font>" ' The Running-average option RW "" & _ "<input " & strRA_state & " type='checkbox' name='chkRA' " & _ "title='Select to apply a running average to all the data.' " & _ "onClick='submitform()'/>" & _ "<font size='2' color='#008080'>RA</font>" ' The timer for auto-plots RW "&nbsp;" & _ "<input " & strTimer_state & " type='checkbox' name='chkTimer' " & _ "title='Select to enable a repeating 5-minute countdown timer. This is synchronized with the server to trigger a chart update immediately after " & _ "the database has been updated.' " & _ "onClick='submitform()'/>" If (strTimer_state = "checked") Then ' The space in the span is needed for an initial value. The client-sided JavaScript changes this value ' every second. strTimer_value = " " Else strTimer_value = "Timer" End If RW "<span id='spTimerSec' name='spTimerSec' style='color:#008080; font-size:10pt;'>" & strTimer_value & "</span>" ' A hidden field that serves to test if the client has JavaScript enabled. Some script will ' try to change this value from F to T. RC "<input type='hidden' name='jS' id='jS' value='F'>" RC "</form>" If (Request.QueryString("jS") = "F") Then RBC "JavaScript is needed to use the charting controls and view a chart image." RBC "" RBC "Please enable JavaScript in your web browser. If you enable JavaScript, this warning" RBC "will clear after your second click of the press-to-chart button." RBC "" RBC "Note that requesting a chart update before the previous chart has completed is another" RBC "possible cause for this error message. Please wait until the image returns from the" RBC "server." Else '================================================================================= ' PLOT THE CHART... ' ' If the region has been specified in the query, then plot the chart. ' '================================================================================= If (Request.QueryString("Region") <> "") Then If (strMRTime <> "-") Then FetchTheData ' Close the database connection If IsObject(DBConnection) Then If DBConnection.State <> adStateClosed Then DBConnection.Close End If Set DBConnection = Nothing End If PlotTheChart Else RWBR "No data available for the selected station." End If Else RWBR "" RWBR "Specifiy a region and then click the chart button." End If End If %> <!-- Client side script --> <SCRIPT LANGUAGE="javascript"> <!-- // Globals var cP = document.getElementById('ChartingParameters'); var cmbEndDate = document.getElementById('EndDate'); var cmbDays = document.getElementById('Days'); var cmbLocation = document.getElementById('Location'); var stepIncrement = cmbDays.options[cmbDays.selectedIndex].text; function testJS(){ document.getElementById('jS').value = 'T'; } function showDirections(){ try { var imgDirections = document.getElementById('directions'); imgDirections.style.visibility = 'visible'; } catch(e){} } function showImage(){ try { var imgChartImage = document.getElementById('chartimage'); imgChartImage.style.visibility = 'visible'; } catch(e){} } function changeColorSubmitButton(){ document.getElementById('myButton').style.color='red'; } function submitform(){ //document.getElementById('Sensor').style.backgroundColor='#FFE4C4'; document.getElementById('myButton').value = 'Please Wait'; cP.submit(); } function stepLocationForward(){ var targetIndex = cmbLocation.selectedIndex; if (targetIndex < (cmbLocation.length - 1)){ cmbLocation.selectedIndex = targetIndex + 1; } else { cmbLocation.selectedIndex = 0; } submitform(); } function stepBack(){ var targetIndex = cmbEndDate.selectedIndex + (stepIncrement * 1.0); if (targetIndex > (cmbEndDate.length - 1)){ cmbEndDate.selectedIndex = cmbEndDate.selectedIndex; } else { cmbEndDate.selectedIndex = targetIndex; } submitform(); } function stepForward(){ var targetIndex = cmbEndDate.selectedIndex - (stepIncrement * 1.0); if (targetIndex < 0){ cmbEndDate.selectedIndex = 0; } else { cmbEndDate.selectedIndex = targetIndex; } submitform(); } // Timer functions var secs; var timerID = null; var timerRunning = false; var delay = 1000; function initializeTimer(secsFromChart){ // Set the length of the timer, in seconds if (secsFromChart == null){ if (timerRunning){ secs = secs - 5; if (secs < 0){ secs = 3; } }else{ if (secs == null){ secs = 298; } } }else{ secs = secsFromChart; } stopTheTimer(); startTheTimer(); } function stopTheTimer(){ if (timerRunning){ clearTimeout(timerID); timerRunning = false; // This color change was used when there was a pause mode. //document.getElementById('spTimerSec').style.color = 'red'; } } function startTheTimer(){ // Reset the color back to normal. //document.getElementById('spTimerSec').style.color = '#008080'; if (secs==0){ // Here's where you put something useful that's // executes after the allotted time. submitform(); }else{ self.status = secs; if (secs < 10){ secs = ' ' + secs; } document.getElementById('spTimerSec').firstChild.nodeValue = '' + secs + 's.'; secs = secs - 1; timerRunning = true; timerID = self.setTimeout("startTheTimer()", delay); } } function changeRegionAnchorValue( theInputString){ if (theInputString=='MN') { document.getElementById('regionanchor').firstChild.nodeValue = 'Columbia Basin Weather'; } else if (theInputString=='CR') { document.getElementById('regionanchor').firstChild.nodeValue = 'Minnesota Weather'; } else { document.getElementById('regionanchor').firstChild.nodeValue = theInputString; } } function setRegionState(){ document.getElementById('Region_state').value = 'new'; submitform(); } //--> </SCRIPT> </div> </body> </html>