|
74 | 74 | const defaultStyle = styles[1]; |
75 | 75 |
|
76 | 76 | const params = window.params = {style: defaultStyle, accessToken: mapboxgl.accessToken}; |
77 | | - const arrayToOptions = (arr) => arr.reduce((acc, item) => ({...acc, [item]: item}), {}); |
| 77 | + const arrayToOptions = (arr) => Object.fromEntries(arr.map(item => [item, item])); |
78 | 78 |
|
79 | 79 | const map = window.map = new mapboxgl.Map({ |
80 | 80 | container: 'map', |
|
105 | 105 | const folder = pane.addFolder({title: fragmentName, expanded: true}); |
106 | 106 | dynamicFolders.push(folder); |
107 | 107 |
|
108 | | - // Render configuration binding |
109 | | - const schema = fragment.schema || {}; |
110 | | - for (const config in schema) { |
111 | | - const meta = schema[config]; |
112 | | - const label = meta.metadata ? meta.metadata['mapbox:title'] : ""; |
| 108 | + // Parse mapbox:auxiliary into normalized conditions array |
| 109 | + const parseAuxiliary = (aux) => { |
| 110 | + if (!aux || aux.length === 0) return null; |
| 111 | + const conditions = Array.isArray(aux[0]) ? aux : [aux]; |
| 112 | + return conditions.map(([parent, value]) => ({parent, value})); |
| 113 | + }; |
| 114 | + |
| 115 | + // Check if all conditions are met |
| 116 | + const evaluateConditions = (conditions) => { |
| 117 | + return conditions.every(({parent, value}) => params[parent] === value); |
| 118 | + }; |
| 119 | + |
| 120 | + const bindings = new Map(); |
| 121 | + |
| 122 | + // Helper to add a config binding |
| 123 | + const addConfigBinding = (targetFolder, config, meta) => { |
| 124 | + const label = meta.metadata ? meta.metadata['mapbox:title'] : config; |
113 | 125 | const options = meta.values && Array.isArray(meta.values) ? arrayToOptions(meta.values) : undefined; |
114 | 126 | params[config] = meta.default; |
115 | | - const configBinding = folder.addBinding(params, config, {label, options}); |
| 127 | + const configBinding = targetFolder.addBinding(params, config, {label, options}); |
116 | 128 | configBinding.on('change', (e) => map.setConfigProperty(id, config, e.value)); |
| 129 | + bindings.set(config, configBinding); |
| 130 | + return configBinding; |
| 131 | + }; |
| 132 | + |
| 133 | + const configGroups = fragment.metadata && fragment.metadata["mapbox:configGroups"]; |
| 134 | + const schema = fragment.schema || {}; |
| 135 | + |
| 136 | + // Collect interactivity configs from featuresets |
| 137 | + const featuresets = fragment.featuresets || {}; |
| 138 | + const interactivityConfigs = new Set(); |
| 139 | + for (const fs of Object.values(featuresets)) { |
| 140 | + const states = fs.metadata && fs.metadata['mapbox:states'] || []; |
| 141 | + for (const state of states) { |
| 142 | + if (state.importConfigs) { |
| 143 | + state.importConfigs.forEach(c => interactivityConfigs.add(c)); |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + if (configGroups && configGroups.length > 0) { |
| 149 | + const groupedProps = new Set(configGroups.flatMap(g => g.properties)); |
| 150 | + |
| 151 | + // Render grouped properties in sub-folders |
| 152 | + for (const group of configGroups) { |
| 153 | + const groupFolder = folder.addFolder({title: group.name, expanded: true}); |
| 154 | + for (const config of group.properties) { |
| 155 | + if (schema[config]) { |
| 156 | + addConfigBinding(groupFolder, config, schema[config]); |
| 157 | + } |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + // Render remaining ungrouped in "Other" folder |
| 162 | + const otherConfigs = Object.keys(schema).filter(c => |
| 163 | + !groupedProps.has(c) && !interactivityConfigs.has(c) |
| 164 | + ); |
| 165 | + if (otherConfigs.length > 0) { |
| 166 | + const otherFolder = folder.addFolder({title: 'Other', expanded: true}); |
| 167 | + for (const config of otherConfigs) { |
| 168 | + addConfigBinding(otherFolder, config, schema[config]); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + // Render Interactivity section grouped by featureset > state |
| 173 | + if (interactivityConfigs.size > 0) { |
| 174 | + const interactivityFolder = folder.addFolder({title: 'Interactivity', expanded: true}); |
| 175 | + for (const [fsId, fs] of Object.entries(featuresets)) { |
| 176 | + const states = (fs.metadata && fs.metadata['mapbox:states']) || []; |
| 177 | + const statesWithConfigs = states.filter(s => s.importConfigs && s.importConfigs.length > 0); |
| 178 | + if (statesWithConfigs.length === 0) continue; |
| 179 | + |
| 180 | + const fsTitle = (fs.metadata && fs.metadata['mapbox:title']) || fsId; |
| 181 | + const fsFolder = interactivityFolder.addFolder({title: fsTitle, expanded: false}); |
| 182 | + |
| 183 | + for (const state of statesWithConfigs) { |
| 184 | + const stateFolder = fsFolder.addFolder({title: state.id, expanded: true}); |
| 185 | + for (const config of state.importConfigs) { |
| 186 | + if (schema[config]) { |
| 187 | + addConfigBinding(stateFolder, config, schema[config]); |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + } |
| 192 | + } |
| 193 | + } else { |
| 194 | + // Fallback: flat list |
| 195 | + for (const config in schema) { |
| 196 | + addConfigBinding(folder, config, schema[config]); |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + // Set up auxiliary visibility logic |
| 201 | + for (const config in schema) { |
| 202 | + const meta = schema[config]; |
| 203 | + const auxiliary = meta.metadata && meta.metadata["mapbox:auxiliary"]; |
| 204 | + const conditions = parseAuxiliary(auxiliary); |
| 205 | + if (!conditions) continue; |
| 206 | + |
| 207 | + const binding = bindings.get(config); |
| 208 | + if (!binding) continue; |
| 209 | + |
| 210 | + // Set initial hidden state |
| 211 | + binding.hidden = !evaluateConditions(conditions); |
| 212 | + |
| 213 | + // Subscribe to parent changes |
| 214 | + for (const {parent} of conditions) { |
| 215 | + const parentBinding = bindings.get(parent); |
| 216 | + if (!parentBinding) { |
| 217 | + console.warn(`Auxiliary config "${config}" references unknown parent "${parent}"`); |
| 218 | + continue; |
| 219 | + } |
| 220 | + parentBinding.on('change', () => { |
| 221 | + binding.hidden = !evaluateConditions(conditions); |
| 222 | + }); |
| 223 | + } |
117 | 224 | } |
118 | 225 | } |
119 | 226 | }); |
|
0 commit comments