|
104 | 104 |
|
105 | 105 | } |
106 | 106 | </script> |
| 107 | + |
| 108 | + <script type=module> |
| 109 | + ;(function(){ |
| 110 | + |
| 111 | + /** |
| 112 | + * Send high-fidelity network and device information back to SpeedCurve. We |
| 113 | + * can use this to better segment and bucket metrics-by-condition. |
| 114 | + */ |
| 115 | + |
| 116 | + // Ensure SpeedCurve is up and running, otherwise, bail out. |
| 117 | + if (!window.LUX || typeof window.LUX.addData !== 'function') { |
| 118 | + console.warn('SpeedCurve not available: network detection aborted.'); |
| 119 | + return; |
| 120 | + } |
| 121 | + |
| 122 | + // Categorise and bucket high-cardinality metrics. |
| 123 | + function bucketBattery(level) { |
| 124 | + return level != null ? Math.min(100, Math.ceil(level * 100 / 5) * 5) : null; |
| 125 | + } |
| 126 | + |
| 127 | + // Bucket RTT into 25ms increments. |
| 128 | + function bucketRTT(rtt) { |
| 129 | + return rtt != null ? Math.ceil(rtt / 25) * 25 : null; |
| 130 | + } |
| 131 | + |
| 132 | + // Assign RTT its CrUX-defined category. |
| 133 | + function categoriseRTT(rtt) { |
| 134 | + if (rtt == null) return null; |
| 135 | + return rtt < 75 ? 'Low' : rtt <= 275 ? 'Medium' : 'High'; |
| 136 | + } |
| 137 | + |
| 138 | + // Bucket downlink into 5Mbps increments. |
| 139 | + function bucketDownlink(downlink) { |
| 140 | + return downlink != null ? Math.ceil(downlink / 5) * 5 : null; |
| 141 | + } |
| 142 | + |
| 143 | + // If the battery is currently less than 20%, assign ‘Low Battery’ status. |
| 144 | + function isBatteryLow(level) { |
| 145 | + return level != null ? level <= 0.2 : null; |
| 146 | + } |
| 147 | + |
| 148 | + // Grab data from the Network Information API. |
| 149 | + const netInfo = navigator.connection; |
| 150 | + |
| 151 | + if (netInfo) { |
| 152 | + |
| 153 | + window.LUX.addData('dataSaver', netInfo.saveData); |
| 154 | + console.log('dataSaver:', netInfo.saveData); |
| 155 | + |
| 156 | + const rttBucket = bucketRTT(netInfo.rtt); |
| 157 | + window.LUX.addData('rttBucket', rttBucket); |
| 158 | + console.log('rttBucket (ms):', rttBucket); |
| 159 | + |
| 160 | + const rttCategory = categoriseRTT(netInfo.rtt); |
| 161 | + window.LUX.addData('rttCategory', rttCategory); |
| 162 | + console.log('rttCategory (Low/Medium/High):', rttCategory); |
| 163 | + |
| 164 | + const downlinkBucket = bucketDownlink(netInfo.downlink); |
| 165 | + window.LUX.addData('downlinkBucket', downlinkBucket); |
| 166 | + console.log('downlinkBucket (Mbps):', downlinkBucket); |
| 167 | + |
| 168 | + if ('downlinkMax' in netInfo) { |
| 169 | + window.LUX.addData('downlinkMax', netInfo.downlinkMax); |
| 170 | + console.log('downlinkMax (Mbps):', netInfo.downlinkMax); |
| 171 | + } |
| 172 | + |
| 173 | + } |
| 174 | + |
| 175 | + // Grab data from the Battery Status API. |
| 176 | + if ('getBattery' in navigator) { |
| 177 | + |
| 178 | + navigator.getBattery().then(function(batt) { |
| 179 | + const levelBucket = bucketBattery(batt.level); |
| 180 | + window.LUX.addData('batteryLevelBucket', levelBucket); |
| 181 | + console.log('batteryLevelBucket (%):', levelBucket); |
| 182 | + |
| 183 | + window.LUX.addData('batteryCharging', batt.charging); |
| 184 | + console.log('batteryCharging:', batt.charging); |
| 185 | + |
| 186 | + const lowFlag = isBatteryLow(batt.level); |
| 187 | + window.LUX.addData('batteryLow', lowFlag); |
| 188 | + console.log('batteryLow (≤20%):', lowFlag); |
| 189 | + }).catch(function() { |
| 190 | + console.log('Battery API error or unsupported'); |
| 191 | + }); |
| 192 | + |
| 193 | + } |
| 194 | + |
| 195 | + })(); |
| 196 | + </script> |
0 commit comments