1- function catToColour ( cat = - 999 , accessible = true , stormType = "tropical" ) {
1+ function catToColour ( cat = - 999 , accessible = true ) {
22 const scaleName = currentScale === "default" ? ( accessible ? "accessible" : "default" ) : currentScale ;
33 const colorMap = getScaleMap ( scaleName ) ;
4-
5- if ( scaleName === "default" || scaleName === "accessible" ) {
6- return colorMap . get ( cat ) || "#C0C0C0" ;
7- }
8-
9- const value = Number ( cat ) ;
10- const normType = ( stormType || "tropical" ) . toLowerCase ( ) ;
11-
12- const norm = ( t ) => {
13- const v = String ( t || "" ) . trim ( ) . toLowerCase ( ) ;
14- if ( ! v ) return "tropical" ;
15- if ( [ "ex" , "extratropical" , "post-tropical" , "posttropical" , "pt" ] . includes ( v ) ) return "extratropical" ;
16- if ( [ "st" , "ss" , "sd" , "subtropical" ] . includes ( v ) ) return "subtropical" ;
17- return "tropical" ;
18- } ;
19-
20- const entries = customScales [ scaleName ] || [ ] ;
21-
22- let group = entries . filter ( e => norm ( e . type ) === normType ) ;
23- if ( group . length === 0 && normType !== "tropical" ) {
24- group = entries . filter ( e => norm ( e . type ) === "tropical" ) ;
25- }
26- if ( group . length === 0 ) group = entries ;
27-
28- const usable = group
29- . map ( e => ( { thr : Number ( e . cat ) , color : e . color } ) )
30- . filter ( e => Number . isFinite ( e . thr ) && e . thr !== - 999 )
31- . sort ( ( a , b ) => a . thr - b . thr ) ;
32-
33- if ( usable . length === 0 ) {
34- const anyColor = ( entries . find ( e => Number ( e . cat ) !== - 999 ) ?. color ) ;
35- return anyColor || "#C0C0C0" ;
36- }
37-
38- let chosen = null ;
39- if ( Number . isFinite ( value ) ) {
40- for ( let i = usable . length - 1 ; i >= 0 ; i -- ) {
41- if ( usable [ i ] . thr <= value ) { chosen = usable [ i ] ; break ; }
42- }
43- }
44- if ( ! chosen ) chosen = usable [ 0 ] ;
45-
46- return chosen . color || "#C0C0C0" ;
4+ return colorMap . get ( cat ) || "#C0C0C0" ;
475}
486
497const SCALE_STORAGE_KEY = "trackgen_custom_scales" ;
@@ -82,19 +40,8 @@ function getScaleMap(scaleName) {
8240 // custom scale
8341 const scale = customScales [ scaleName ] ;
8442 if ( ! scale ) return getScaleMap ( "default" ) ;
85-
8643 const map = new Map ( ) ;
87-
88- ( scale || [ ] ) . forEach ( entry => {
89- const catNum = Number ( entry . cat ) ;
90- const type = ( entry . type || "tropical" ) . toLowerCase ( ) ;
91- const color = entry . color ;
92- const typedKey = `${ catNum } |${ type } ` ;
93- if ( ! map . has ( typedKey ) ) {
94- map . set ( typedKey , color ) ;
95- }
96- } ) ;
97-
44+ scale . forEach ( entry => map . set ( Number ( entry . cat ) , entry . color ) ) ;
9845 return map ;
9946}
10047
@@ -252,7 +199,7 @@ document.addEventListener("DOMContentLoaded", () => {
252199 return {
253200 cat : speed ,
254201 color : div . querySelector ( ".scale-color" ) . value ,
255- type : ( div . querySelector ( ".scale-type" ) ? .value || "tropical" )
202+ type : div . querySelector ( ".scale-type" ) . value
256203 } ;
257204 } ) ;
258205
@@ -267,143 +214,6 @@ document.addEventListener("DOMContentLoaded", () => {
267214 } ) ;
268215} ) ;
269216
270- function normalizeStormType ( raw ) {
271- const v = String ( raw || "" ) . trim ( ) . toLowerCase ( ) ;
272- if ( ! v ) return "tropical" ;
273- // extratropical
274- if ( [ "ex" , "extratropical" , "post-tropical" , "posttropical" , "pt" ] . includes ( v ) ) return "extratropical" ;
275- // subtropical
276- if ( [ "st" , "ss" , "sd" , "subtropical" ] . includes ( v ) ) return "subtropical" ;
277- // tropical (hu/ts/td/tc, etc.)
278- return "tropical" ;
279- }
280-
281- function getStormType ( point ) {
282- return normalizeStormType (
283- point ?. type ?? point ?. stormType ?? point ?. systemType ?? point ?. status ?? point ?. subtype
284- ) ;
285- }
286-
287- function toKnots ( val , unit ) {
288- const v = Number ( val ) ;
289- if ( ! Number . isFinite ( v ) ) return NaN ;
290- switch ( ( unit || "kt" ) . toLowerCase ( ) ) {
291- case "mph" : return v / 1.15078 ;
292- case "kph" :
293- case "kmh" :
294- case "km/h" : return v / 1.852 ;
295- case "mps" :
296- case "m/s" : return v * 1.943844 ; // 1 m/s = 1.943844 kt
297- case "kt" :
298- case "kts" :
299- case "knot" :
300- case "knots" :
301- default : return v ;
302- }
303- }
304-
305- function parseSpeedStringToKnots ( input ) {
306- if ( input == null ) return NaN ;
307- const s = String ( input ) . trim ( ) . toLowerCase ( ) ;
308- const m = s . match ( / - ? \d + (?: \. \d + ) ? / ) ;
309- if ( ! m ) return NaN ;
310- const num = Number ( m [ 0 ] ) ;
311-
312- let unit = "kt" ;
313- if ( / ( m p h | m i \/ h | \b m i h \b | m i l e s \/ h ) / . test ( s ) ) unit = "mph" ;
314- else if ( / ( k p h | k m \/ h | k m h ) / . test ( s ) ) unit = "kph" ;
315- else if ( / ( m \/ s | m p s ) / . test ( s ) ) unit = "mps" ;
316- else if ( / ( k t | k t s | k n o t | k n o t s | k n \b ) / . test ( s ) ) unit = "kt" ;
317-
318- return toKnots ( num , unit ) ;
319- }
320-
321- function findUnitFor ( point , baseKey ) {
322- const candidates = [
323- `${ baseKey } _unit` , `${ baseKey } Unit` ,
324- "wind_unit" , "windUnit" , "speed_unit" , "speedUnit" ,
325- "units" , "unit"
326- ] ;
327- for ( const k of candidates ) {
328- const u = point ?. [ k ] ;
329- if ( typeof u === "string" && u . trim ( ) ) {
330- const su = u . trim ( ) . toLowerCase ( ) ;
331- if ( su . includes ( "mph" ) || su . includes ( "mi" ) ) return "mph" ;
332- if ( su . includes ( "kph" ) || su . includes ( "km" ) ) return "kph" ;
333- if ( su . includes ( "m/s" ) || su . includes ( "mps" ) ) return "mps" ;
334- if ( su . includes ( "kt" ) || su . includes ( "knot" ) || su . includes ( "kn" ) ) return "kt" ;
335- }
336- }
337- return null ;
338- }
339-
340- function getWindKnots ( point ) {
341- const num = ( v ) => {
342- const n = Number ( v ) ;
343- return Number . isFinite ( n ) ? n : NaN ;
344- } ;
345-
346- const ktsFields = [
347- "wind_kts" , "windKts" , "wind_knots" ,
348- "max_wind_kts" , "maxWindKts"
349- ] ;
350- for ( const f of ktsFields ) {
351- if ( point ?. [ f ] != null ) {
352- const direct = num ( point [ f ] ) ;
353- if ( Number . isFinite ( direct ) ) return toKnots ( direct , "kt" ) ;
354- const parsed = parseSpeedStringToKnots ( point [ f ] ) ;
355- if ( Number . isFinite ( parsed ) ) return parsed ;
356- }
357- }
358-
359- const mphFields = [ "wind_mph" , "max_wind_mph" , "maxWindMph" ] ;
360- for ( const f of mphFields ) {
361- if ( point ?. [ f ] != null ) {
362- const direct = num ( point [ f ] ) ;
363- if ( Number . isFinite ( direct ) ) return toKnots ( direct , "mph" ) ;
364- const parsed = parseSpeedStringToKnots ( point [ f ] ) ;
365- if ( Number . isFinite ( parsed ) ) return parsed ;
366- }
367- }
368- const kphFields = [ "wind_kph" , "max_wind_kph" , "maxWindKph" ] ;
369- for ( const f of kphFields ) {
370- if ( point ?. [ f ] != null ) {
371- const direct = num ( point [ f ] ) ;
372- if ( Number . isFinite ( direct ) ) return toKnots ( direct , "kph" ) ;
373- const parsed = parseSpeedStringToKnots ( point [ f ] ) ;
374- if ( Number . isFinite ( parsed ) ) return parsed ;
375- }
376- }
377-
378- const genericKeys = [
379- "wind" , "windspeed" , "speed" ,
380- "max_wind" , "maxWind" , "max_windspeed" , "sustained" , "max_sustained" , "maxSustained"
381- ] ;
382- for ( const key of genericKeys ) {
383- if ( point ?. [ key ] != null ) {
384- const unit = findUnitFor ( point , key ) ;
385- const val = point [ key ] ;
386- const n = num ( val ) ;
387- if ( Number . isFinite ( n ) ) return toKnots ( n , unit || "kt" ) ;
388- const parsed = parseSpeedStringToKnots ( val ) ;
389- if ( Number . isFinite ( parsed ) ) return parsed ;
390- }
391- }
392-
393- for ( const [ key , val ] of Object . entries ( point || { } ) ) {
394- if ( / ( l a t | l o n | l o n g | p r e s s | g u s t | g u s t s | d e g | d i r | b e a r i n g ) / i. test ( key ) ) continue ;
395- if ( typeof val === "string" && / \d / . test ( val ) ) {
396- const parsed = parseSpeedStringToKnots ( val ) ;
397- if ( Number . isFinite ( parsed ) ) return parsed ;
398- }
399- if ( typeof val === "number" && / ( w i n d | s p e e d ) / i. test ( key ) ) {
400- return toKnots ( val , findUnitFor ( point , key ) || "kt" ) ;
401- }
402- }
403-
404- return NaN ;
405- }
406-
407217class MapManager {
408218 constructor ( ) {
409219 this . config = {
@@ -859,11 +669,8 @@ function createMap(data, accessible) {
859669 return acc ;
860670 } , { } ) ;
861671
862- const isCustom = currentScale !== "default" && currentScale !== "accessible" ;
863672 const pointGroups = adjustedData . reduce ( ( map , point ) => {
864- const stormType = getStormType ( point ) ;
865- const valueForScale = isCustom ? getWindKnots ( point ) : point . category ;
866- const key = `${ catToColour ( valueForScale , accessible , stormType ) } |${ point . shape } ` ;
673+ const key = `${ catToColour ( point . category , accessible ) } |${ point . shape } ` ;
867674 if ( ! map . has ( key ) ) {
868675 map . set ( key , [ ] ) ;
869676 }
0 commit comments