1+ {% assign e = site.data[page.lang]['heatmap-ui'] %}
2+
3+ <!-- 3D Render of the Keycube -->
4+ {% include dataviz-data.html %}
5+
6+ <!-- ── Bottom bar: badge + finger context + legend + reset ── -->
7+ < div class ="bottom-bar ">
8+ < div class ="row " id ="first-row ">
9+ < button class ="first-row " id ="all-fingers " name ="finger-select " value ="total ">
10+ {{ e.total }}
11+ </ button >
12+ < button class ="first-row " id ="best-finger " name ="finger-select " value ="preferred ">
13+ {{ e.preferred }}
14+ </ button >
15+ < button class ="first-row " id ="right-hand " name ="finger-select " value ="R ">
16+ {{ e.hf_format | replace: '%h%', e.right | replace: '%f%', e.hand }}
17+ </ button >
18+ < button class ="first-row " id ="left-hand " name ="finger-select " value ="L ">
19+ {{ e.hf_format | replace: '%h%', e.left | replace: '%f%', e.hand }}
20+ </ button >
21+ </ div >
22+ < div class ="row " id ="second-row ">
23+ < button class ="second-row " id ="finger-thumb " name ="finger " value ="T "> {{ e.thumb }}</ button >
24+ < button class ="second-row " id ="finger-index " name ="finger " value ="I "> {{ e.index }}</ button >
25+ < button class ="second-row " id ="finger-middle " name ="finger " value ="M "> {{ e.middle }}</ button >
26+ < button class ="second-row " id ="finger-ring " name ="finger " value ="R "> {{ e.ring }}</ button >
27+ < button class ="second-row " id ="finger-little " name ="finger " value ="L "> {{ e.little }}</ button >
28+ </ div >
29+
30+ < div class ="finger-context " id ="finger-context ">
31+ {{ e.finger_context }}
32+ </ div >
33+
34+ < div class ="heatmap-legend " style ="flex-basis: 100%; display: flex; justify-content: center; align-items: center; ">
35+ < span > {{ e.unreachable }}</ span >
36+ < div class ="heatmap-gradient "> </ div >
37+ < span > {{ e.reachable }}</ span >
38+ < button class ="reset-view-btn " id ="reset-view-btn "> {{ e.reset_view }}</ button >
39+ </ div >
40+ </ div >
41+
42+ < script src ="/assets/js/dataviz.js "> </ script >
43+ < script type ="module ">
44+ import langFinger from '/assets/js/ui-lang.json' with { type : 'json' } ;
45+
46+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
47+ let selectedHand = '' ;
48+
49+ const selectionText = document . getElementById ( 'selection-text' ) ;
50+ const selectionIcon = document . querySelector ( '#selection-badge .selection-icon' ) ;
51+ const fingerContext = document . getElementById ( 'finger-context' ) ;
52+
53+ const FACES = [ 'R' , 'B' , 'G' , 'W' , 'Y' ] ;
54+ const ALL_FINGERS = [ 'LT' , 'LI' , 'LM' , 'LR' , 'LL' , 'RT' , 'RI' , 'RM' , 'RR' , 'RL' ] ;
55+
56+ const lang = document . documentElement . lang
57+ const fingerData = langFinger [ lang ] ? langFinger [ lang ] : langFinger [ "en" ] ;
58+
59+ function updateUI ( key ) {
60+ const data = fingerData [ key ] || { name : key , icon : '' , info : '' } ;
61+ if ( selectionText ) selectionText . textContent = data . name ;
62+ if ( selectionIcon ) selectionIcon . textContent = data . icon ;
63+ if ( fingerContext ) fingerContext . textContent = data . info ;
64+ }
65+
66+ function applyHeatmap ( data , fixedRange ) {
67+ let min = fixedRange ? fixedRange . min : Infinity ;
68+ let max = fixedRange ? fixedRange . max : - Infinity ;
69+ if ( ! fixedRange ) {
70+ FACES . forEach ( function ( f ) {
71+ data [ f ] . forEach ( function ( v ) {
72+ if ( v < min ) min = v ;
73+ if ( v > max ) max = v ;
74+ } ) ;
75+ } ) ;
76+ }
77+ if ( window . updateModel ) {
78+ window . updateModel ( {
79+ heatmap : data ,
80+ heatmapMin : min ,
81+ heatmapMax : max ,
82+ scores : data ,
83+ showScores : true ,
84+ isReachability : true ,
85+ scoreFormat : 'integer' ,
86+ figure6View : false
87+ } ) ;
88+ }
89+ }
90+
91+ function computeHandData ( fingers ) {
92+ const result = { } ;
93+ FACES . forEach ( function ( face ) {
94+ result [ face ] = [ ] ;
95+ for ( let i = 0 ; i < 16 ; i ++ ) {
96+ let sum = 0 ;
97+ fingers . forEach ( function ( f ) {
98+ const fData = window . perFingerReachability [ f ] ;
99+ if ( fData ) fData . forEach ( function ( p ) {
100+ sum += p [ face ] [ i ] ;
101+ } ) ;
102+ } ) ;
103+ result [ face ] . push ( sum ) ;
104+ }
105+ } ) ;
106+ return result ;
107+ }
108+
109+ function updateSelection ( fingerValue ) {
110+ applyHeatmap ( computeHandData ( fingerValue === 'total' ? ALL_FINGERS : [ fingerValue ] ) ) ;
111+ updateUI ( fingerValue , fingerValue === 'total' ? ALL_FINGERS : null ) ;
112+ }
113+
114+ function handleHandAll ( hand ) {
115+ const fingers = hand === 'left' ? [ 'LT' , 'LI' , 'LM' , 'LR' , 'LL' ] : [ 'RT' , 'RI' , 'RM' , 'RR' , 'RL' ] ;
116+ applyHeatmap ( computeHandData ( fingers ) ) ;
117+ updateUI ( hand + '-all' , fingers ) ;
118+ }
119+
120+ function handleBestFinger ( ) {
121+ const preferenceAggregate = window . preferenceAggregate ;
122+ if ( ! preferenceAggregate ) return ;
123+ const result = { } ;
124+ FACES . forEach ( function ( face ) {
125+ result [ face ] = [ ] ;
126+ for ( let i = 0 ; i < 16 ; i ++ ) {
127+ let best = 0 ;
128+ const preferredFingers = preferenceAggregate . tiedFingers [ face ] [ i ] ;
129+ preferredFingers . forEach ( function ( f ) {
130+ const fData = window . perFingerReachability [ f ] ;
131+ if ( fData ) {
132+ let s = 0 ;
133+ fData . forEach ( function ( p ) {
134+ s += p [ face ] [ i ] ;
135+ } ) ;
136+ if ( s > best ) best = s ;
137+ }
138+ } ) ;
139+ result [ face ] . push ( best ) ;
140+ }
141+ } ) ;
142+ applyHeatmap ( result , { min : 0 , max : 66 } ) ;
143+ updateUI ( 'best' , ALL_FINGERS ) ;
144+ }
145+
146+ function firstRowHandleSelect ( value ) {
147+ //console.log(value)
148+ if ( value === "total" ) {
149+ updateSelection ( "total" ) ;
150+ } else if ( value === "preferred" ) {
151+ handleBestFinger ( ) ;
152+ } else {
153+ selectedHand = value ;
154+ if ( value === 'L' ) {
155+ handleHandAll ( 'left' ) ;
156+ } else {
157+ handleHandAll ( 'right' ) ;
158+ }
159+ }
160+ }
161+
162+ function secondRowHandleSelect ( value ) {
163+ //console.log(value)
164+ if ( selectedHand !== '' )
165+ updateSelection ( selectedHand + value )
166+ }
167+
168+ document . querySelectorAll ( '.first-row' ) . forEach ( elem => {
169+ elem . addEventListener ( 'click' , ( ) => firstRowHandleSelect ( elem . value ) )
170+ } )
171+
172+ document . querySelectorAll ( '.second-row' ) . forEach ( elem => {
173+ elem . addEventListener ( 'click' , ( ) => secondRowHandleSelect ( elem . value ) )
174+ } )
175+
176+ firstRowHandleSelect ( "total" ) ;
177+ document . getElementById ( 'model-container' ) . classList . add ( 'active' ) ;
178+ } ) ;
179+ </ script >
0 commit comments