@cdc/map 4.24.9 → 4.24.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcmap.js +26371 -25867
  3. package/examples/private/DEV-9644.json +184 -0
  4. package/package.json +3 -3
  5. package/src/CdcMap.tsx +25 -12
  6. package/src/_stories/CdcMap.stories.tsx +2 -6
  7. package/src/_stories/CdcMapLegend.stories.tsx +86 -0
  8. package/src/_stories/_mock/usa-state-gradient.json +238 -0
  9. package/src/_stories/_mock/wastewater-map.json +208 -0
  10. package/src/components/Annotation/AnnotationDropdown.styles.css +0 -1
  11. package/src/components/CityList.tsx +55 -10
  12. package/src/components/DataTable.tsx +94 -17
  13. package/src/components/EditorPanel/components/EditorPanel.tsx +118 -64
  14. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +27 -23
  15. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +75 -16
  16. package/src/components/Legend/components/Legend.tsx +23 -19
  17. package/src/components/Legend/components/index.scss +23 -10
  18. package/src/components/UsaMap/components/HexIcon.tsx +7 -1
  19. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +56 -11
  20. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +88 -15
  21. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +13 -0
  22. package/src/components/UsaMap/components/UsaMap.County.tsx +49 -48
  23. package/src/components/UsaMap/components/UsaMap.State.tsx +5 -4
  24. package/src/components/UsaMap/helpers/shapes.ts +207 -0
  25. package/src/coreStyles_map.scss +3 -0
  26. package/src/data/initial-state.js +1 -0
  27. package/src/index.jsx +7 -1
  28. package/src/scss/editor-panel.scss +5 -13
  29. package/src/scss/filters.scss +2 -7
  30. package/src/scss/main.scss +4 -9
  31. package/src/scss/map.scss +6 -6
  32. package/src/scss/mixins.scss +47 -0
  33. package/src/types/MapConfig.ts +6 -3
  34. package/src/types/MapContext.ts +0 -1
@@ -13,7 +13,25 @@ import Loading from '@cdc/core/components/Loading'
13
13
 
14
14
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
15
15
  const DataTable = props => {
16
- const { state, tableTitle, indexTitle, mapTitle, rawData, runtimeData, headerColor, expandDataTable, columns, displayDataAsText, applyLegendToRow, displayGeoName, navigationHandler, viewport, formatLegendLocation, tabbingId, setFilteredCountryCode } = props
16
+ const {
17
+ state,
18
+ tableTitle,
19
+ indexTitle,
20
+ mapTitle,
21
+ rawData,
22
+ runtimeData,
23
+ headerColor,
24
+ expandDataTable,
25
+ columns,
26
+ displayDataAsText,
27
+ applyLegendToRow,
28
+ displayGeoName,
29
+ navigationHandler,
30
+ viewport,
31
+ formatLegendLocation,
32
+ tabbingId,
33
+ setFilteredCountryCode
34
+ } = props
17
35
 
18
36
  const [expanded, setExpanded] = useState(expandDataTable)
19
37
  const [sortBy, setSortBy] = useState({ column: 'geo', asc: false })
@@ -140,7 +158,9 @@ const DataTable = props => {
140
158
  csvData = Papa.unparse(rawData.map(row => ({ FullGeoName: displayGeoName(row[state.columns.geo.name]), ...row })))
141
159
  } else {
142
160
  // Unparse + Add column for full Geo name
143
- csvData = Papa.unparse(rawData.map(row => ({ FullGeoName: formatLegendLocation(row[state.columns.geo.name]), ...row })))
161
+ csvData = Papa.unparse(
162
+ rawData.map(row => ({ FullGeoName: formatLegendLocation(row[state.columns.geo.name]), ...row }))
163
+ )
144
164
  }
145
165
 
146
166
  const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' })
@@ -154,16 +174,36 @@ const DataTable = props => {
154
174
  }
155
175
 
156
176
  return (
157
- <a download={fileName} type='button' onClick={saveBlob} href={URL.createObjectURL(blob)} aria-label='Download this data in a CSV file format.' className={`${headerColor} no-border`} id={`${skipId}`} data-html2canvas-ignore role='button'>
177
+ <a
178
+ download={fileName}
179
+ type='button'
180
+ onClick={saveBlob}
181
+ href={URL.createObjectURL(blob)}
182
+ aria-label='Download this data in a CSV file format.'
183
+ className={`${headerColor} no-border`}
184
+ id={`${skipId}`}
185
+ data-html2canvas-ignore
186
+ role='button'
187
+ >
158
188
  Download Data (CSV)
159
189
  </a>
160
190
  )
161
191
  }, [rawData, state.table])
162
192
 
193
+ const TableMediaControls = ({ belowTable }) => {
194
+ return (
195
+ <MediaControls.Section classes={['download-links'] + (belowTable ? 'below-table' : '')}>
196
+ <MediaControls.Link config={state} />
197
+ {state.general.showDownloadButton && <DownloadButton />}
198
+ </MediaControls.Section>
199
+ )
200
+ }
201
+
163
202
  // Change accessibility label depending on expanded status
164
203
  useEffect(() => {
165
204
  const expandedLabel = 'Accessible data table.'
166
- const collapsedLabel = 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
205
+ const collapsedLabel =
206
+ 'Accessible data table. This table is currently collapsed visually but can still be read using a screen reader.'
167
207
 
168
208
  if (expanded === true && accessibilityLabel !== expandedLabel) {
169
209
  setAccessibilityLabel(expandedLabel)
@@ -180,7 +220,10 @@ const DataTable = props => {
180
220
  const rows = Object.keys(runtimeData)
181
221
  .filter(row => applyLegendToRow(runtimeData[row]))
182
222
  .sort((a, b) => {
183
- const sortVal = customSort(runtimeData[a][state.columns[sortBy.column].name], runtimeData[b][state.columns[sortBy.column].name])
223
+ const sortVal = customSort(
224
+ runtimeData[a][state.columns[sortBy.column].name],
225
+ runtimeData[b][state.columns[sortBy.column].name]
226
+ )
184
227
  if (!sortBy.asc) return sortVal
185
228
  if (sortVal === 0) return 0
186
229
  if (sortVal < 0) return 1
@@ -189,11 +232,12 @@ const DataTable = props => {
189
232
 
190
233
  return (
191
234
  <ErrorBoundary component='DataTable'>
192
- <MediaControls.Section classes={['download-links']}>
193
- <MediaControls.Link config={state} />
194
- {state.general.showDownloadButton && <DownloadButton />}
195
- </MediaControls.Section>
196
- <section id={tabbingId.replace('#', '')} className={`data-table-container ${viewport}`} aria-label={accessibilityLabel}>
235
+ {!state.table.showDownloadLinkBelow && <TableMediaControls />}
236
+ <section
237
+ id={tabbingId.replace('#', '')}
238
+ className={`data-table-container ${viewport}`}
239
+ aria-label={accessibilityLabel}
240
+ >
197
241
  <SkipTo skipId={skipId} skipMessage='Skip Data Table' />
198
242
  <div
199
243
  className={expanded ? 'data-table-heading' : 'collapsed data-table-heading'}
@@ -210,9 +254,23 @@ const DataTable = props => {
210
254
  <Icon display={expanded ? 'minus' : 'plus'} base />
211
255
  {tableTitle}
212
256
  </div>
213
- <div className='table-container' style={{ maxHeight: state.dataTable.limitHeight && `${state.dataTable.height}px`, overflowY: 'scroll' }}>
214
- <table height={expanded ? null : 0} role='table' aria-live='assertive' className={expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'} hidden={!expanded} aria-rowcount={state?.data.length ? state.data.length : '-1'}>
215
- <caption className='cdcdataviz-sr-only'>{state.dataTable.caption ? state.dataTable.caption : `Datatable showing data for the ${mapLookup[state.general.geoType]} figure.`}</caption>
257
+ <div
258
+ className='table-container'
259
+ style={{ maxHeight: state.dataTable.limitHeight && `${state.dataTable.height}px`, overflowY: 'scroll' }}
260
+ >
261
+ <table
262
+ height={expanded ? null : 0}
263
+ role='table'
264
+ aria-live='assertive'
265
+ className={expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'}
266
+ hidden={!expanded}
267
+ aria-rowcount={state?.data.length ? state.data.length : '-1'}
268
+ >
269
+ <caption className='cdcdataviz-sr-only'>
270
+ {state.dataTable.caption
271
+ ? state.dataTable.caption
272
+ : `Datatable showing data for the ${mapLookup[state.general.geoType]} figure.`}
273
+ </caption>
216
274
  <thead style={{ position: 'sticky', top: 0, zIndex: 999 }}>
217
275
  <tr>
218
276
  {Object.keys(columns)
@@ -240,11 +298,19 @@ const DataTable = props => {
240
298
  setSortBy({ column, asc: sortBy.column === column ? !sortBy.asc : false })
241
299
  }
242
300
  }}
243
- className={sortBy.column === column ? (sortBy.asc ? 'sort sort-asc' : 'sort sort-desc') : 'sort'}
244
- {...(sortBy.column === column ? (sortBy.asc ? { 'aria-sort': 'ascending' } : { 'aria-sort': 'descending' }) : null)}
301
+ className={
302
+ sortBy.column === column ? (sortBy.asc ? 'sort sort-asc' : 'sort sort-desc') : 'sort'
303
+ }
304
+ {...(sortBy.column === column
305
+ ? sortBy.asc
306
+ ? { 'aria-sort': 'ascending' }
307
+ : { 'aria-sort': 'descending' }
308
+ : null)}
245
309
  >
246
310
  {text}
247
- <span className='cdcdataviz-sr-only'>{`Sort by ${text} in ${sortBy.column === column ? (!sortBy.asc ? 'descending' : 'ascending') : 'descending'} order`}</span>
311
+ <span className='cdcdataviz-sr-only'>{`Sort by ${text} in ${
312
+ sortBy.column === column ? (!sortBy.asc ? 'descending' : 'ascending') : 'descending'
313
+ } order`}</span>
248
314
  </th>
249
315
  )
250
316
  })}
@@ -283,7 +349,17 @@ const DataTable = props => {
283
349
  }
284
350
 
285
351
  return (
286
- <td tabIndex='0' role='gridcell' onClick={e => (state.general.type === 'bubble' && state.general.allowMapZoom && state.general.geoType === 'world' ? setFilteredCountryCode(row) : true)}>
352
+ <td
353
+ tabIndex='0'
354
+ role='gridcell'
355
+ onClick={e =>
356
+ state.general.type === 'bubble' &&
357
+ state.general.allowMapZoom &&
358
+ state.general.geoType === 'world'
359
+ ? setFilteredCountryCode(row)
360
+ : true
361
+ }
362
+ >
287
363
  {cellValue}
288
364
  </td>
289
365
  )
@@ -295,6 +371,7 @@ const DataTable = props => {
295
371
  </table>
296
372
  </div>
297
373
  </section>
374
+ {state.table.showDownloadLinkBelow && <TableMediaControls belowTable={true} />}
298
375
  <div id={skipId} className='cdcdataviz-sr-only'>
299
376
  Skipped data table.
300
377
  </div>
@@ -109,12 +109,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
109
109
  } = useMapLayers(state, setState, false, tooltipId)
110
110
 
111
111
  const categoryMove = (idx1, idx2) => {
112
- let categoryValuesOrder = [...state.legend.categoryValuesOrder]
112
+ let categoryValuesOrder = getCategoryValuesOrder()
113
113
 
114
114
  let [movedItem] = categoryValuesOrder.splice(idx1, 1)
115
115
 
116
116
  categoryValuesOrder.splice(idx2, 0, movedItem)
117
117
 
118
+ state.legend.categoryValuesOrder?.forEach(value => {
119
+ if(categoryValuesOrder.indexOf(value) === -1){
120
+ categoryValuesOrder.push(value)
121
+ }
122
+ })
123
+
118
124
  setState({
119
125
  ...state,
120
126
  legend: {
@@ -541,6 +547,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
541
547
  }
542
548
  })
543
549
  break
550
+ case 'toggleDownloadLinkBelow':
551
+ setState({
552
+ ...state,
553
+ table: {
554
+ ...state.table,
555
+ showDownloadLinkBelow: !state.table.showDownloadLinkBelow
556
+ }
557
+ })
558
+ break
544
559
  case 'toggleDownloadPdfButton':
545
560
  setState({
546
561
  ...state,
@@ -1153,12 +1168,20 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1153
1168
  function filterColorPalettes() {
1154
1169
  let sequential = []
1155
1170
  let nonSequential = []
1171
+ let accessibleColors = []
1156
1172
  for (let paletteName in colorPalettes) {
1157
1173
  if (!isReversed) {
1158
1174
  if (paletteName.includes('qualitative') && !paletteName.endsWith('reverse')) {
1159
1175
  nonSequential.push(paletteName)
1160
1176
  }
1161
- if (!paletteName.includes('qualitative') && !paletteName.endsWith('reverse')) {
1177
+ if (paletteName.includes('colorblindsafe') && !paletteName.endsWith('reverse')) {
1178
+ accessibleColors.push(paletteName)
1179
+ }
1180
+ if (
1181
+ !paletteName.includes('qualitative') &&
1182
+ !paletteName.includes('colorblindsafe') &&
1183
+ !paletteName.endsWith('reverse')
1184
+ ) {
1162
1185
  sequential.push(paletteName)
1163
1186
  }
1164
1187
  }
@@ -1166,15 +1189,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1166
1189
  if (paletteName.includes('qualitative') && paletteName.endsWith('reverse')) {
1167
1190
  nonSequential.push(paletteName)
1168
1191
  }
1169
- if (!paletteName.includes('qualitative') && paletteName.endsWith('reverse')) {
1192
+ if (paletteName.includes('colorblindsafe') && paletteName.endsWith('reverse')) {
1193
+ accessibleColors.push(paletteName)
1194
+ }
1195
+ if (
1196
+ !paletteName.includes('qualitative') &&
1197
+ !paletteName.includes('colorblindsafe') &&
1198
+ paletteName.endsWith('reverse')
1199
+ ) {
1170
1200
  sequential.push(paletteName)
1171
1201
  }
1172
1202
  }
1173
1203
  }
1174
1204
 
1175
- return [sequential, nonSequential]
1205
+ return [sequential, nonSequential, accessibleColors]
1176
1206
  }
1177
- const [sequential, nonSequential] = filterColorPalettes()
1207
+ const [sequential, nonSequential, accessibleColors] = filterColorPalettes()
1178
1208
 
1179
1209
  useEffect(() => {
1180
1210
  let paletteName = ''
@@ -1195,40 +1225,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1195
1225
  columnsRequiredChecker()
1196
1226
  }, [state]) // eslint-disable-line
1197
1227
 
1198
- useEffect(() => {
1199
- //If a categorical map is used and the order is either not defined or incorrect, fix it
1200
- if ('category' === state.legend.type && runtimeLegend && runtimeLegend.runtimeDataHash) {
1201
- let valid = true
1202
- if (state.legend.categoryValuesOrder) {
1203
- runtimeLegend.forEach(item => {
1204
- if (!item.special && state.legend.categoryValuesOrder.indexOf(item.value) === -1) {
1205
- valid = false
1206
- }
1207
- })
1208
- let runtimeLegendKeys = runtimeLegend.map(item => item.value)
1209
- state.legend.categoryValuesOrder.forEach(category => {
1210
- if (runtimeLegendKeys.indexOf(category) === -1) {
1211
- valid = false
1212
- }
1213
- })
1214
- } else {
1215
- valid = false
1216
- }
1217
-
1218
- if (!valid) {
1219
- let arr = runtimeLegend.filter(item => !item.special).map(({ value }) => value)
1220
-
1221
- setState({
1222
- ...state,
1223
- legend: {
1224
- ...state.legend,
1225
- categoryValuesOrder: arr
1226
- }
1227
- })
1228
- }
1229
- }
1230
- }, [runtimeLegend]) // eslint-disable-line
1231
-
1232
1228
  const columnsOptions = [
1233
1229
  <option value='' key={'Select Option'}>
1234
1230
  - Select Option -
@@ -1506,9 +1502,26 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1506
1502
  ...draggableStyle
1507
1503
  })
1508
1504
 
1505
+ const getCategoryValuesOrder = () => {
1506
+ let values = runtimeLegend ? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value) : []
1507
+
1508
+ if(state.legend.cateogryValuesOrder){
1509
+ return values.sort((a, b) => {
1510
+ let aVal = state.legend.cateogryValuesOrder.indexOf(a)
1511
+ let bVal = state.legend.cateogryValuesOrder.indexOf(b)
1512
+ if (aVal === bVal) return 0
1513
+ if (aVal === -1) return 1
1514
+ if (bVal === -1) return -1
1515
+ return aVal - bVal
1516
+ })
1517
+ } else {
1518
+ return values
1519
+ }
1520
+
1521
+ }
1522
+
1509
1523
  const CategoryList = () => {
1510
- return state.legend.categoryValuesOrder ? (
1511
- state.legend.categoryValuesOrder.map((value, index) => (
1524
+ return getCategoryValuesOrder().filter(item => !item.special).map((value, index) => (
1512
1525
  <Draggable key={value} draggableId={`item-${value}`} index={index}>
1513
1526
  {(provided, snapshot) => (
1514
1527
  <li style={{ position: 'relative' }}>
@@ -1524,10 +1537,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1524
1537
  </li>
1525
1538
  )}
1526
1539
  </Draggable>
1527
- ))
1528
- ) : (
1529
- <></>
1530
- )
1540
+ ))
1531
1541
  }
1532
1542
 
1533
1543
  const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
@@ -2242,7 +2252,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2242
2252
  </div>
2243
2253
  ))}
2244
2254
  <button
2245
- className='btn full-width'
2255
+ className='btn btn-primary full-width'
2246
2256
  onClick={e => {
2247
2257
  e.preventDefault()
2248
2258
  editColumn('primary', 'specialClassAdd', {})
@@ -2393,7 +2403,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2393
2403
  </fieldset>
2394
2404
  ))}
2395
2405
  <button
2396
- className={'btn full-width'}
2406
+ className={'btn btn-primary full-width'}
2397
2407
  onClick={event => {
2398
2408
  event.preventDefault()
2399
2409
  addAdditionalColumn(additionalColumns.length + 1)
@@ -2449,7 +2459,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2449
2459
  </fieldset>
2450
2460
  ))}
2451
2461
  <button
2452
- className={'btn full-width'}
2462
+ className={'btn btn-primary full-width'}
2453
2463
  onClick={event => {
2454
2464
  event.preventDefault()
2455
2465
  const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
@@ -2760,7 +2770,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2760
2770
  )}
2761
2771
  </Droppable>
2762
2772
  </DragDropContext>
2763
- {state.legend.categoryValuesOrder && state.legend.categoryValuesOrder.length >= 10 && (
2773
+ {runtimeLegend && runtimeLegend.length >= 10 && (
2764
2774
  <section className='error-box my-2'>
2765
2775
  <div>
2766
2776
  <strong className='pt-1'>Warning</strong>
@@ -2887,7 +2897,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2887
2897
  <p style={{ textAlign: 'center' }}>There are currently no filters.</p>
2888
2898
  )}
2889
2899
  <button
2890
- className={'btn full-width'}
2900
+ className={'btn btn-primary full-width'}
2891
2901
  onClick={event => {
2892
2902
  event.preventDefault()
2893
2903
  changeFilter(null, 'addNew')
@@ -3084,6 +3094,16 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3084
3094
  />
3085
3095
  <span className='edit-label'>Enable Image Download</span>
3086
3096
  </label>
3097
+ <label className='checkbox'>
3098
+ <input
3099
+ type='checkbox'
3100
+ checked={state.table.showDownloadLinkBelow}
3101
+ onChange={event => {
3102
+ handleEditorChanges('toggleDownloadLinkBelow', event.target.checked)
3103
+ }}
3104
+ />
3105
+ <span className='edit-label'>Show Download Link Below Table</span>
3106
+ </label>
3087
3107
  {/* <label className='checkbox'>
3088
3108
  <input
3089
3109
  type='checkbox'
@@ -3286,6 +3306,41 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3286
3306
  )
3287
3307
  })}
3288
3308
  </ul>
3309
+ <span>Colorblind Safe</span>
3310
+ <ul className='color-palette'>
3311
+ {accessibleColors.map(palette => {
3312
+ const colorOne = {
3313
+ backgroundColor: colorPalettes[palette][2]
3314
+ }
3315
+
3316
+ const colorTwo = {
3317
+ backgroundColor: colorPalettes[palette][4]
3318
+ }
3319
+
3320
+ const colorThree = {
3321
+ backgroundColor: colorPalettes[palette][6]
3322
+ }
3323
+
3324
+ // hide palettes with too few colors for region maps
3325
+ if (colorPalettes[palette].length <= 8 && state.general.geoType === 'us-region') {
3326
+ return ''
3327
+ }
3328
+ return (
3329
+ <li
3330
+ title={palette}
3331
+ key={palette}
3332
+ onClick={() => {
3333
+ handleEditorChanges('color', palette)
3334
+ }}
3335
+ className={state.color === palette ? 'selected' : ''}
3336
+ >
3337
+ <span style={colorOne}></span>
3338
+ <span style={colorTwo}></span>
3339
+ <span style={colorThree}></span>
3340
+ </li>
3341
+ )
3342
+ })}
3343
+ </ul>
3289
3344
  <label>
3290
3345
  Geocode Settings
3291
3346
  <TextField
@@ -3370,14 +3425,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3370
3425
  >
3371
3426
  <option value='circle'>Circle</option>
3372
3427
  <option value='pin'>Pin</option>
3373
- {'us-geocode' !== state.general.type && (
3374
- <>
3375
- <option value='square'>Square</option>
3376
- <option value='triangle'>Triangle</option>
3377
- <option value='diamond'>Diamond</option>
3378
- <option value='star'>Star</option>
3379
- </>
3380
- )}
3428
+ <option value='square'>Square</option>
3429
+ <option value='triangle'>Triangle</option>
3430
+ <option value='diamond'>Diamond</option>
3431
+ <option value='star'>Star</option>
3381
3432
  </select>
3382
3433
  </label>
3383
3434
  <TextField
@@ -3461,11 +3512,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3461
3512
  </div>
3462
3513
  )
3463
3514
  })}
3464
- {'us-geocode' !== state.general.type && (
3465
- <button type='button' onClick={() => editCityStyles('add', 0, '', '')} className='btn full-width'>
3466
- Add city style
3467
- </button>
3468
- )}
3515
+
3516
+ <button
3517
+ type='button'
3518
+ onClick={() => editCityStyles('add', 0, '', '')}
3519
+ className='btn btn-primary full-width'
3520
+ >
3521
+ Add city style
3522
+ </button>
3469
3523
  </>
3470
3524
  <label htmlFor='opacity'>
3471
3525
  <TextField
@@ -3565,7 +3619,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3565
3619
  </>
3566
3620
  )
3567
3621
  })}
3568
- <button className={'btn full-width'} onClick={handleAddLayer}>
3622
+ <button className={'btn btn-primary full-width'} onClick={handleAddLayer}>
3569
3623
  Add Map Layer
3570
3624
  </button>
3571
3625
  <p className='layer-purpose-details'>
@@ -11,7 +11,12 @@ import ConfigContext from '../../../../context'
11
11
  // styles
12
12
 
13
13
  const PanelAnnotate: React.FC = props => {
14
- const { state: config, setState: updateConfig, dimensions, isDraggingAnnotation } = useContext<MapContext>(ConfigContext)
14
+ const {
15
+ state: config,
16
+ setState: updateConfig,
17
+ dimensions,
18
+ isDraggingAnnotation
19
+ } = useContext<MapContext>(ConfigContext)
15
20
  const getColumns = (filter = true) => {
16
21
  const columns = {}
17
22
  config.data.forEach(row => {
@@ -20,7 +25,10 @@ const PanelAnnotate: React.FC = props => {
20
25
 
21
26
  if (filter) {
22
27
  Object.keys(columns).forEach(key => {
23
- if ((config.series && config.series.filter(series => series.dataKey === key).length > 0) || (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))) {
28
+ if (
29
+ (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
30
+ (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
31
+ ) {
24
32
  delete columns[key]
25
33
  }
26
34
  })
@@ -41,7 +49,9 @@ const PanelAnnotate: React.FC = props => {
41
49
  }
42
50
 
43
51
  const handleAddAnnotation = () => {
44
- const svgContainer = document.querySelector('.map-container > section > svg, .map-container > section > canvas')?.getBoundingClientRect()
52
+ const svgContainer = document
53
+ .querySelector('.map-container > section > svg, .map-container > section > canvas')
54
+ ?.getBoundingClientRect()
45
55
  const newSvgDims = [svgContainer.width, svgContainer.height]
46
56
 
47
57
  const newAnnotation = {
@@ -139,11 +149,17 @@ const PanelAnnotate: React.FC = props => {
139
149
  {config?.annotations &&
140
150
  config?.annotations.map((annotation, index) => (
141
151
  <Accordion>
142
- <Accordion.Section title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}>
152
+ <Accordion.Section
153
+ title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}
154
+ >
143
155
  <div className='annotation-group'>
144
156
  <label>
145
157
  Annotation Text:
146
- <textarea rows={5} value={annotation.text} onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)} />
158
+ <textarea
159
+ rows={5}
160
+ value={annotation.text}
161
+ onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)}
162
+ />
147
163
  </label>
148
164
  {/* <label>
149
165
  Vertical Anchor
@@ -304,30 +320,18 @@ const PanelAnnotate: React.FC = props => {
304
320
  </select>
305
321
  </label>
306
322
 
307
- {/* <label>
308
- Snap to Nearest Point
309
- <input
310
- type='checkbox'
311
- checked={config?.annotations[index]?.snapToNearestPoint}
312
- onClick={e => {
313
- const updatedAnnotations = [...config?.annotations]
314
- updatedAnnotations[index].snapToNearestPoint = e.target.checked
315
- updateConfig({
316
- ...config,
317
- annotations: updatedAnnotations
318
- })
319
- }}
320
- />
321
- </label> */}
322
-
323
- <Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
323
+ <Button className='btn btn-danger' onClick={() => handleRemoveAnnotation(index)}>
324
324
  Delete Annotation
325
325
  </Button>
326
326
  </div>
327
327
  </Accordion.Section>
328
328
  </Accordion>
329
329
  ))}
330
- {config?.annotations?.length < 3 && <Button onClick={handleAddAnnotation}>Add Annotation</Button>}
330
+ {config?.annotations?.length < 3 && (
331
+ <button className='btn btn-primary full-width' onClick={handleAddAnnotation}>
332
+ Add Annotation
333
+ </button>
334
+ )}
331
335
  </Accordion.Section>
332
336
  </Accordion>
333
337
  )