1515 const rows = [ ] ;
1616 let row = { } ;
1717
18- const list = actions
19- . map ( action => {
20- const when = new Date ( action . date )
21- const date = when . toLocaleDateString ( ) . slice ( 0 , - 5 )
22- const month = date . split ( / \/ / ) [ 0 ]
23- const day = when . toLocaleString ( window . navigator . language , { weekday : 'short' } )
24- const fold = items [ items . findIndex ( item => item . id == action . id ) - 1 ] . text
25- const coord = action . item . text . split ( / \n / ) . pop ( )
26- if ( occupied ( fold ) ) { rows . push ( row ) ; row = { } }
27- row [ fold ] = { day, date, month, coord}
28- return `${ day } ${ date } ⇒ ${ dist ( coord ) . toFixed ( 3 ) } ${ fold } `
29- } )
30- . join ( "<br>" )
31- rows . push ( row )
18+ const list = actions
19+ . map ( ( action ) => {
20+ const when = new Date ( action . date ) ;
21+ const date = when . toLocaleDateString ( ) . slice ( 0 , - 5 ) ;
22+ const month = date . split ( / \/ / ) [ 0 ] ;
23+ const day = when . toLocaleString ( window . navigator . language , {
24+ weekday : "short" ,
25+ } ) ;
26+ const fold =
27+ items [ items . findIndex ( ( item ) => item . id == action . id ) - 1 ] . text ;
28+ const coord = action . item . text . split ( / \n / ) . pop ( ) ;
29+ const miles = dist ( coord ) ;
30+ if ( occupied ( fold ) ) {
31+ rows . push ( row ) ;
32+ row = { } ;
33+ }
34+ row [ fold ] = { day, date, month, fold, coord, miles } ;
35+ return `${ day } ${ date } ⇒ ${ dist ( coord ) . toFixed ( 3 ) } ${ fold } ` ;
36+ } )
37+ . join ( "<br>" ) ;
38+ rows . push ( row ) ;
3239
33- const table = `
34- <table style="border-collapse: collapse;" onclick=preview(event)>
35- ${ `<tr>${ quads . map ( quad => `<th style="text-align: center">
36- ${ quad } ` ) . join ( "" ) } `}
37- ${ rows . map ( ( row , r ) =>
38- `<tr>${ quads . map ( ( quad , c ) => format ( row [ quad ] , r , c ) ) . join ( "" ) } `
39- ) . join ( "" ) }
40- </table>`
41- window . preview = preview
42- window . result . innerHTML = `
43- ${ table }
44- <br>
45- <details><summary>data</summary>
46- ${ list }
47- </details>
48- `
40+ const table = `
41+ <table style="border-collapse: collapse;" onclick=preview(event)>
42+ ${ `<tr>${ quads
43+ . map (
44+ ( quad ) => `<th style="text-align: center">
45+ ${ quad } ` ,
46+ )
47+ . join ( "" ) } `}
48+ ${ rows
49+ . map (
50+ ( row , r ) =>
51+ `<tr>${ quads . map ( ( quad , c ) => format ( row [ quad ] , r , c ) ) . join ( "" ) } ` ,
52+ )
53+ . join ( "" ) }
54+ </table>` ;
55+ window . preview = preview ;
56+ window . groups = groups ;
57+ window . result . innerHTML = `
58+ ${ table }
59+ <p>
60+ <button onclick=groups(event)>groups</button>
61+ <\p>
62+ <details><summary>data</summary>
63+ ${ list }
64+ </details>
65+ ` ;
4966
50- function format ( item , r , c ) {
51- let style = `border: 1px solid black; padding: 6px; `
52- if ( item ) {
53- const { day, date, month, coord} = item
54- if ( diff ( month , r - 1 , c ) ) style += "border-top:2.5px solid black; "
55- if ( diff ( month , r , c - 1 ) ) style += "border-left:2.5px solid black; "
56- if ( best ( r , c ) ) style += "background:gold; "
57- const title = `${ bearing ( coord ) } on ${ date } `
58- const field = `${ day } ⇒ ${ dist ( coord ) . toFixed ( 2 ) } `
59- return `<td title="${ title } " style="${ style } ">${ field } `
67+ function format ( item , r , c ) {
68+ let style = `border: 1px solid black; padding: 6px; ` ;
69+ if ( item ) {
70+ const { day, date, month, coord } = item ;
71+ if ( diff ( month , r - 1 , c ) )
72+ style += "border-top:2.5px solid black; " ;
73+ if ( diff ( month , r , c - 1 ) )
74+ style += "border-left:2.5px solid black; " ;
75+ if ( best ( r , c ) ) style += "background:gold; " ;
76+ const title = `${ bearing ( coord ) } on ${ date } ` ;
77+ const field = `${ day } ⇒ ${ dist ( coord ) . toFixed ( 2 ) } ` ;
78+ return `<td title="${ title } " style="${ style } ">${ field } ` ;
79+ }
80+ return `<td style="${ style } ">` ;
6081 }
61- return `<td style="${ style } ">`
62- }
6382
64- function diff ( month , r , c ) {
65- if ( r < 0 || c < 0 ) return false
66- if ( ! ( quads [ c ] in rows [ r ] ) ) return false
67- return month != rows [ r ] [ quads [ c ] ] . month
68- }
83+ function diff ( month , r , c ) {
84+ if ( r < 0 || c < 0 ) return false ;
85+ if ( ! ( quads [ c ] in rows [ r ] ) ) return false ;
86+ return month != rows [ r ] [ quads [ c ] ] . month ;
87+ }
6988
70- function best ( r , c ) {
71- const quad = quads [ c ]
72- const here = dist ( rows [ r ] [ quad ] . coord )
73- const others = rows . map ( row => ( quad in row ) ? ( dist ( row [ quad ] . coord ) ) : 0 )
74- return ! others . some ( other => other > here )
75- }
89+ function best ( r , c ) {
90+ const quad = quads [ c ] ;
91+ const here = dist ( rows [ r ] [ quad ] . coord ) ;
92+ const others = rows . map ( ( row ) =>
93+ quad in row ? dist ( row [ quad ] . coord ) : 0 ,
94+ ) ;
95+ return ! others . some ( ( other ) => other > here ) ;
96+ }
7697
77- function dist ( coord ) {
78- const [ lat , lon ] = coord . split ( / , / )
79- const dx = Math . abs ( home . lon - lon ) * 49
80- const dy = Math . abs ( home . lat - lat ) * 69
81- return ( 2 * ( dx + dy ) )
82- }
98+ function dist ( coord ) {
99+ const [ lat , lon ] = coord . split ( / , / ) ;
100+ const dx = Math . abs ( home . lon - lon ) * 49 ;
101+ const dy = Math . abs ( home . lat - lat ) * 69 ;
102+ return 2 * ( dx + dy ) ;
103+ }
83104
84- function bearing ( coord ) {
85- const [ lat , lon ] = coord . split ( / , / )
105+ function bearing ( coord ) {
106+ const [ lat , lon ] = coord . split ( / , / ) ;
86107
87- const φ1 = home . lat * Math . PI / 180 ;
88- const φ2 = lat * Math . PI / 180 ;
89- const Δλ = ( lon - home . lon ) * Math . PI / 180 ;
108+ const φ1 = ( home . lat * Math . PI ) / 180 ;
109+ const φ2 = ( lat * Math . PI ) / 180 ;
110+ const Δλ = ( ( lon - home . lon ) * Math . PI ) / 180 ;
90111
91- const y = Math . sin ( Δλ ) * Math . cos ( φ2 ) ;
92- const x = Math . cos ( φ1 ) * Math . sin ( φ2 ) - Math . sin ( φ1 ) * Math . cos ( φ2 ) * Math . cos ( Δλ ) ;
93- const θ = Math . atan2 ( y , x ) ; // Radians
112+ const y = Math . sin ( Δλ ) * Math . cos ( φ2 ) ;
113+ const x =
114+ Math . cos ( φ1 ) * Math . sin ( φ2 ) -
115+ Math . sin ( φ1 ) * Math . cos ( φ2 ) * Math . cos ( Δλ ) ;
116+ const θ = Math . atan2 ( y , x ) ; // Radians
94117
95- const brng = ( θ * 180 / Math . PI + 360 ) % 360 ;
96- return `${ Math . round ( brng ) } °` ;
97- }
118+ const brng = ( ( θ * 180 ) / Math . PI + 360 ) % 360 ;
119+ return `${ Math . round ( brng ) } °` ;
120+ }
98121
99- function occupied ( fold ) {
100- const wants = quads . slice ( quads . indexOf ( fold ) )
101- for ( const want of wants )
102- if ( want in row ) return true
103- return false
104- }
122+ function occupied ( fold ) {
123+ const wants = quads . slice ( quads . indexOf ( fold ) ) ;
124+ for ( const want of wants ) if ( want in row ) return true ;
125+ return false ;
126+ }
105127
106- function preview ( event ) {
107- const target = event . target
108- const c = target . cellIndex
109- const r = target . parentNode . rowIndex - 1
110- if ( r < 0 || ! ( quads [ c ] in rows [ r ] ) ) return
111- const { day, date, month, coord} = rows [ r ] [ quads [ c ] ]
112- const detail = `${ dist ( coord ) . toFixed ( 2 ) } miles ${ quads [ c ] } at ${ bearing ( coord ) } `
113- const title = `Place on ${ day } ${ date } `
114- console . log ( title , detail )
115- const story = [
116- { type :' paragraph' , text :detail } ,
117- { type :' map' , text :`${ coord } ${ detail } ` }
118- ]
119- frame . open ( { title, story} , event . shiftKey )
120- }
128+ function preview ( event ) {
129+ const target = event . target ;
130+ const c = target . cellIndex ;
131+ const r = target . parentNode . rowIndex - 1 ;
132+ if ( r < 0 || ! ( quads [ c ] in rows [ r ] ) ) return ;
133+ const { day, date, month, coord } = rows [ r ] [ quads [ c ] ] ;
134+ const detail = `${ dist ( coord ) . toFixed ( 2 ) } miles ${ quads [ c ] } at ${ bearing ( coord ) } ` ;
135+ const title = `Place on ${ day } ${ date } ` ;
136+ console . log ( title , detail ) ;
137+ const story = [
138+ { type : " paragraph" , text : detail } ,
139+ { type : " map" , text : `${ coord } ${ detail } ` } ,
140+ ] ;
141+ frame . open ( { title, story } , event . shiftKey ) ;
142+ }
121143
122- </ script >
144+ function groups ( event ) {
145+ const list = rows . map ( ( row ) => Object . values ( row ) ) . flat ( 2 ) ;
146+ const segs = Object . groupBy ( list , ( { miles} ) => Math . round ( miles ) ) ;
147+ const mark = ( { day, date, fold, coord, miles } ) =>
148+ `${ coord } ${ day } ${ date } , ${ fold } ${ miles . toFixed ( 2 ) } miles` ;
149+ const story = Object . keys ( segs ) . map ( ( seg ) => [
150+ { type : "paragraph" , text :`Around ${ seg } miles.` } ,
151+ { type : "map" , text : segs [ seg ] . map ( mark ) . join ( "\n" ) }
152+ ] ) . flat ( ) ;
153+ const title = `Places by Distance` ;
154+ story . unshift ( { type :"paragraph" , text :"Runs organized by Manhattan distance." } )
155+ frame . open ( { title, story } , event . shiftKey ) ;
156+ }
157+ </ script >
0 commit comments