mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
KML export for localities
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { useMemo } from 'react'
|
||||
import { type MRT_ColumnDef } from 'material-react-table'
|
||||
import { MRT_TableInstance, type MRT_ColumnDef, MRT_RowData } from 'material-react-table'
|
||||
import { useGetAllLocalitiesQuery, useGetLocalitySpeciesListMutation } from '../../redux/localityReducer'
|
||||
import { Locality } from '@/shared/types'
|
||||
import { TableView } from '../TableView/TableView'
|
||||
import { useNotify } from '@/hooks/notification'
|
||||
import { LocalitiesMap } from '../Map/LocalitiesMap'
|
||||
import { Placemark, generateKml } from '@/util/kml'
|
||||
|
||||
const decimalCount = (num: number) => {
|
||||
const numAsString = num.toString()
|
||||
@@ -383,6 +384,19 @@ export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Localit
|
||||
a.click()
|
||||
}
|
||||
|
||||
// Downloads a KML file of filtered localities.
|
||||
const kmlExport = <T extends MRT_RowData>(table: MRT_TableInstance<T>) => {
|
||||
const rowData: Locality[] = table.getPrePaginationRowModel().rows.map(row => row.original as unknown as Locality)
|
||||
|
||||
const dataString = generateKml(rowData)
|
||||
const blob = new Blob([dataString], { type: 'text/kml' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'localities.kml'
|
||||
a.click()
|
||||
}
|
||||
|
||||
const checkRowRestriction = (row: Locality) => {
|
||||
return !!row.loc_status
|
||||
}
|
||||
@@ -401,6 +415,7 @@ export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Localit
|
||||
data={localitiesQueryData}
|
||||
url="locality"
|
||||
combinedExport={combinedExport}
|
||||
kmlExport={kmlExport}
|
||||
exportIsLoading={isLoading}
|
||||
enableColumnFilterModes={true}
|
||||
/>
|
||||
|
||||
@@ -11,12 +11,14 @@ import AddCircleIcon from '@mui/icons-material/AddCircle'
|
||||
export const TableToolBar = <T extends MRT_RowData>({
|
||||
table,
|
||||
combinedExport,
|
||||
kmlExport,
|
||||
exportIsLoading,
|
||||
selectorFn,
|
||||
showNewButton,
|
||||
}: {
|
||||
table: MRT_TableInstance<T>
|
||||
combinedExport?: (lids: number[]) => Promise<void>
|
||||
kmlExport?: (table: MRT_TableInstance<T>) => void
|
||||
exportIsLoading?: boolean
|
||||
selectorFn?: (id: T) => void
|
||||
showNewButton?: boolean
|
||||
@@ -73,7 +75,16 @@ export const TableToolBar = <T extends MRT_RowData>({
|
||||
>
|
||||
Export table
|
||||
</MenuItem>
|
||||
|
||||
{kmlExport && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
kmlExport(table)
|
||||
handleClose()
|
||||
}}
|
||||
>
|
||||
Export KML
|
||||
</MenuItem>
|
||||
)}
|
||||
{combinedExport && (
|
||||
<Box>
|
||||
<Tooltip
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
useMaterialReactTable,
|
||||
MaterialReactTable,
|
||||
MRT_VisibilityState,
|
||||
MRT_TableInstance,
|
||||
} from 'material-react-table'
|
||||
import { Box, CircularProgress, Paper } from '@mui/material'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
@@ -36,6 +37,7 @@ export const TableView = <T extends MRT_RowData>({
|
||||
url,
|
||||
title,
|
||||
combinedExport,
|
||||
kmlExport,
|
||||
exportIsLoading,
|
||||
enableColumnFilterModes,
|
||||
serverSidePagination,
|
||||
@@ -50,6 +52,7 @@ export const TableView = <T extends MRT_RowData>({
|
||||
selectorFn?: (id: T) => void
|
||||
url?: string
|
||||
combinedExport?: (lids: number[]) => Promise<void>
|
||||
kmlExport?: (table: MRT_TableInstance<T>) => void
|
||||
exportIsLoading?: boolean
|
||||
enableColumnFilterModes?: boolean
|
||||
serverSidePagination?: boolean
|
||||
@@ -202,6 +205,7 @@ export const TableView = <T extends MRT_RowData>({
|
||||
<TableToolBar<T>
|
||||
table={table}
|
||||
combinedExport={combinedExport}
|
||||
kmlExport={kmlExport}
|
||||
exportIsLoading={exportIsLoading}
|
||||
showNewButton={editRights.new && title != 'Locality-Species-Cross-Search'}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { Locality } from '@/shared/types'
|
||||
|
||||
// Replaces special characters with html entities.
|
||||
const htmlEncode = (str: string) => {
|
||||
const el = document.createElement('div')
|
||||
el.innerText = str
|
||||
return el.innerHTML
|
||||
}
|
||||
|
||||
// A single row in a locality info table
|
||||
const tableRow = (title: string, value: string, indentLevel: number) => {
|
||||
const indent = '\t'.repeat(indentLevel)
|
||||
|
||||
let tableRowString = `${indent}<tr>\n`
|
||||
|
||||
tableRowString += `${indent}\t<td>\n`
|
||||
tableRowString += `${indent}\t\t<b>${title}</b>\n`
|
||||
tableRowString += `${indent}\t</td>\n`
|
||||
|
||||
tableRowString += `${indent}\t<td>\n`
|
||||
tableRowString += `${indent}\t\t${value}\n`
|
||||
tableRowString += `${indent}\t</td>\n`
|
||||
|
||||
tableRowString += `${indent}</tr>\n`
|
||||
|
||||
return tableRowString
|
||||
}
|
||||
|
||||
// Locality info table that shows up when clicking map marker in Google Earth for example.
|
||||
const localityInfoTable = (locality: Locality, indentLevel: number = 3) => {
|
||||
const indent = '\t'.repeat(indentLevel)
|
||||
|
||||
let tableString = `${indent}<![CDATA[\n`
|
||||
tableString += `${indent}<table style="float: none; clear: none; border-collapse: collapse; margin-bottom: 16px; font-size: 90%;">\n`
|
||||
|
||||
tableString += tableRow('Locality ID:', locality.lid.toString(), indentLevel + 1)
|
||||
tableString += tableRow('Country:', htmlEncode(locality.country), indentLevel + 1)
|
||||
tableString += tableRow('Lat/Long:', `${locality.dms_lat},${locality.dms_long}`, indentLevel + 1)
|
||||
tableString += tableRow(
|
||||
'Age:',
|
||||
`${locality.max_age} Ma (${locality.bfa_max}) - ${locality.min_age} Ma (${locality.bfa_min})`,
|
||||
indentLevel + 1
|
||||
)
|
||||
|
||||
tableString += `${indent}</table>\n`
|
||||
tableString += `${indent}]]>\n`
|
||||
|
||||
return tableString
|
||||
}
|
||||
|
||||
const generatePlacemarkKml = (locality: Locality) => {
|
||||
let kmlString = `\t<Placemark>\n`
|
||||
kmlString += `\t\t<name>${htmlEncode(locality.loc_name)}</name>\n`
|
||||
|
||||
kmlString += `\t\t<description>\n`
|
||||
kmlString += localityInfoTable(locality)
|
||||
kmlString += `\t\t</description>\n`
|
||||
|
||||
kmlString += `\t\t<Point>\n`
|
||||
kmlString += `\t\t\t<coordinates>${locality.dec_long},${locality.dec_lat},0</coordinates>\n`
|
||||
kmlString += `\t\t</Point>\n`
|
||||
|
||||
kmlString += `\t</Placemark>\n`
|
||||
|
||||
return kmlString
|
||||
}
|
||||
|
||||
// Returns an XML / KML string containing locality information as map markers, openable in Google Earth for example.
|
||||
export const generateKml = (localities: Locality[]) => {
|
||||
let kmlString = `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
kmlString +=
|
||||
`<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" ` +
|
||||
`xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">\n`
|
||||
kmlString += `<Document>\n`
|
||||
kmlString += `\t<name>NOW database ${new Date().toLocaleString()}</name>\n`
|
||||
|
||||
kmlString += localities.map(generatePlacemarkKml).join('')
|
||||
|
||||
kmlString += `</Document>\n</kml>`
|
||||
|
||||
return kmlString
|
||||
}
|
||||
Reference in New Issue
Block a user