summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/chart/constants.js63
-rw-r--r--client/chart/singlePie.chart.js36
-rw-r--r--client/common/loader.component.js7
-rw-r--r--client/index.js9
-rw-r--r--client/table/citations.table.js22
-rw-r--r--client/table/file.table.js66
-rw-r--r--client/table/tabulator.css12
7 files changed, 144 insertions, 71 deletions
diff --git a/client/chart/constants.js b/client/chart/constants.js
index b916cbd2..0f23f06b 100644
--- a/client/chart/constants.js
+++ b/client/chart/constants.js
@@ -15,6 +15,24 @@ export const rainbow = [
// '#888888',
]
+export const bigRainbow = [
+ '#9e0142',
+ '#d53e4f',
+ '#f46d43',
+ '#fdae61',
+ '#fee08b',
+ '#ffffbf',
+ '#e6f598',
+ '#abdda4',
+ '#66c2a5',
+ '#3288bd',
+ '#5e4fa2',
+ '#8744ae',
+ '#a044ae',
+ '#b342a4',
+ '#b34287',
+ // '#888888',
+]
export const colorblindSafeRainbow = [
'#a50026',
'#d73027',
@@ -30,12 +48,35 @@ export const colorblindSafeRainbow = [
// '#888888',
]
+export const categoryRainbow = [
+ '#5e4fa2',
+ '#66c2a5',
+ '#d53e4f',
+ '#f46d43',
+ '#9e0142',
+ '#3288bd',
+ '#fee08b',
+ '#abdda4',
+ '#e6f598',
+ '#fdae61',
+ '#ffffbf',
+ // '#888888',
+]
+
export const institutionColors = [
'#f2f293', // edu (yellow)
'#3264f6', // company (blue)
'#f30000', // gov/mil (red)
]
+export const colorTable = {
+ rainbow,
+ bigRainbow,
+ colorblindSafeRainbow,
+ institutionColors,
+ categoryRainbow,
+}
+
/* stuff for a 'countries' legend */
export const topCountryCount = 10
@@ -45,20 +86,20 @@ export const otherCountriesLabel = 'Other Countries'
/* institution tuples, labels and templates */
export const initialInstitutionLookup = {
- 'edu': 0,
- 'company': 0,
- 'gov': 0,
+ edu: 0,
+ company: 0,
+ gov: 0,
}
export const institutionOrder = {
- 'edu': 0,
- 'company': 1,
- 'gov': 2,
+ edu: 0,
+ company: 1,
+ gov: 2,
}
export const institutionLabels = {
- 'edu': 'Academic',
- 'company': 'Commercial',
- 'gov': 'Military / Government',
- 'mil': 'Military / Government',
-} \ No newline at end of file
+ edu: 'Academic',
+ company: 'Commercial',
+ gov: 'Military / Government',
+ mil: 'Military / Government',
+}
diff --git a/client/chart/singlePie.chart.js b/client/chart/singlePie.chart.js
index fcff3214..2e770bd7 100644
--- a/client/chart/singlePie.chart.js
+++ b/client/chart/singlePie.chart.js
@@ -2,41 +2,28 @@ import React, { Component } from 'react'
import csv from 'parse-csv'
import C3Chart from 'react-c3js'
-import { toTuples } from '../util'
-
import 'c3/c3.css'
import './chart.css'
import {
- rainbow, otherCountriesLabel,
- institutionOrder, institutionLabels,
- initialInstitutionLookup,
+ rainbow, bigRainbow, colorTable
} from './constants'
class SinglePieChart extends Component {
state = {
keys: [],
data: [],
- fields: {},
}
componentDidMount() {
const { payload } = this.props
- console.log(payload)
- console.log(payload.fields)
- const fields = {}
- payload.fields.forEach(field => {
- const [k, v] = field.split(': ')
- fields[k] = v
- })
-
fetch(payload.url, { mode: 'cors' })
.then(r => r.text())
.then(text => {
try {
const keys = text.split('\n')[0].split(',').map(s => s.trim().replace(/"/, ''))
const data = csv.toJSON(text, { headers: { included: true } })
- this.setState({ keys, data, fields })
+ this.setState({ keys, data })
} catch (e) {
console.error("error making json:", payload.url)
console.error(e)
@@ -45,9 +32,9 @@ class SinglePieChart extends Component {
}
render() {
- const { payload } = this.props
- const { keys, data, fields } = this.state
- console.log(keys, data)
+ const { fields } = this.props.payload
+ const { keys, data } = this.state
+ // console.log(keys, data)
const [labelField, numberField] = keys
if (!data.length) return null
@@ -59,15 +46,16 @@ class SinglePieChart extends Component {
return [label, number]
}).sort((a, b) => b[1] - a[1])
- console.log(rows)
-
let chartRows = rows.slice(0, rowsToDisplay)
- let otherCount = rows.slice(rowsToDisplay).reduce((a, b) => { return a + b[1] }, 0)
+ let otherCount = rows.slice(rowsToDisplay).reduce((a, b) => a + b[1], 0)
if (otherCount > 0) {
chartRows.push([fields.OtherLabel, otherCount])
}
- console.log(rowsToDisplay, chartRows)
+ const height = chartRows.length < 6 ? 316 :
+ chartRows.length < 10 ? 336 : 356
+
+ const pattern = colorTable[fields.Colors] || (chartRows.length < 10 ? rainbow : bigRainbow)
return (
<div className='chart'>
@@ -78,7 +66,7 @@ class SinglePieChart extends Component {
type: 'pie',
}}
color={{
- pattern: rainbow,
+ pattern,
}}
tooltip={{
format: {
@@ -86,7 +74,7 @@ class SinglePieChart extends Component {
}
}}
size={{
- height: chartRows.length < 4 ? 316 : 336,
+ height,
}}
/>
<span className='chartCaption'>{fields.Caption}</span>
diff --git a/client/common/loader.component.js b/client/common/loader.component.js
index df25dd39..b24b31b1 100644
--- a/client/common/loader.component.js
+++ b/client/common/loader.component.js
@@ -5,9 +5,14 @@ export default function Loader() {
const spinCfg = {
width: 5,
radius: 20,
+ speed: 1,
color: 'white',
}
- return <Spinner config={spinCfg} />
+ return (
+ <div style={{ position: 'relative' }}>
+ <Spinner config={spinCfg} />
+ </div>
+ )
// return (
// <div className='loaderWrapper'>
// <div className='loader'>
diff --git a/client/index.js b/client/index.js
index 835d859c..9644ba5c 100644
--- a/client/index.js
+++ b/client/index.js
@@ -73,6 +73,15 @@ function runApplets() {
let opt = null
payload.cmd = cmd
payload.partz = cmdPartz
+ const fields = {}
+ if (payload.fields) {
+ payload.fields.forEach(field => {
+ const [k, v] = field.split(': ')
+ fields[k] = v
+ })
+ }
+ payload.fields = fields
+
if (payload.cmd === 'load_file' || payload.cmd === 'single_pie_chart') {
payload.url = 'https://nyc3.digitaloceanspaces.com/megapixels/v1' + cmdPartz.shift()
return [el, payload]
diff --git a/client/table/citations.table.js b/client/table/citations.table.js
index 8fe46b69..c1c71906 100644
--- a/client/table/citations.table.js
+++ b/client/table/citations.table.js
@@ -1,11 +1,9 @@
import React, { Component } from 'react'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
import { ReactTabulator } from 'react-tabulator'
import { saveAs } from 'file-saver'
import { Loader } from '../common'
-import { toArray, toTuples, domainFromUrl } from '../util'
+import { domainFromUrl } from '../util'
export const citationsColumns = [
{ title: 'Title', field: 'title', sorter: 'string' },
@@ -64,12 +62,12 @@ class CitationsTable extends Component {
if (!q.length) {
this.setState({ q, filteredCitations: formattedCitations })
} else {
- let q_re = new RegExp('(' + q.replace(/\s+/g, ' ').trim().replace(' ', '|') + ')', 'gi')
+ let qRe = new RegExp('(' + q.replace(/\s+/g, ' ').trim().replace(' ', '|') + ')', 'gi')
let filteredCitations = formattedCitations.filter(citation => (
- citation.title.match(q_re) ||
- citation.institution.match(q_re) ||
- citation.country.match(q_re)
- ))
+ citation.title.match(qRe) ||
+ citation.institution.match(qRe) ||
+ citation.country.match(qRe)
+ ))
this.setState({ q, filteredCitations })
}
}
@@ -85,7 +83,7 @@ class CitationsTable extends Component {
case 'number':
return String(data)
default:
- return '\"' + String(data) + '\"'
+ return '"' + String(data) + '"'
}
})
return row.join(",")
@@ -96,8 +94,8 @@ class CitationsTable extends Component {
titles.join(','),
...rows,
].join('\n')
- ], {type: "text/csv;charset=utf-8"});
- saveAs(blob, fn);
+ ], { type: "text/csv;charset=utf-8" })
+ saveAs(blob, fn)
}
render() {
@@ -111,7 +109,7 @@ class CitationsTable extends Component {
value={this.state.q}
onChange={e => this.updateFilter(e.target.value)}
className='q'
- placeholder='Enter text to search citations...'
+ placeholder='Enter text to search citations'
/>
<span className='download' onClick={() => this.download()}>Download CSV</span>
</div>
diff --git a/client/table/file.table.js b/client/table/file.table.js
index ff6c0af6..c195b09d 100644
--- a/client/table/file.table.js
+++ b/client/table/file.table.js
@@ -1,18 +1,17 @@
import React, { Component } from 'react'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
import { ReactTabulator } from 'react-tabulator'
+import csv from 'parse-csv'
-import { toArray, toTuples, domainFromUrl } from '../util'
+import { domainFromUrl } from '../util'
import { Loader } from '../common'
-import csv from 'parse-csv'
-
class FileTable extends Component {
state = {
keys: [],
data: [],
+ filteredData: [],
columns: [],
+ q: '',
}
componentDidMount() {
@@ -26,7 +25,7 @@ class FileTable extends Component {
const data = csv.toJSON(text, { headers: { included: true } })
// console.log(data)
const columns = this.getColumns(keys, data, payload.fields)
- this.setState({ keys, data, columns })
+ this.setState({ keys, data, filteredData: data, columns })
} catch (e) {
console.error("error making json:", payload.url)
console.error(e)
@@ -35,10 +34,11 @@ class FileTable extends Component {
}
getColumns(keys, data, fields) {
- let titles = fields.length ? fields[0].split(', ') : keys
- let numberFields = []
+ let titles = fields.Headings ? fields.Headings.split(', ') : keys
+ // let numberFields = []
let columns = keys.map((field, i) => {
const title = titles[i] || field
+ let widthGrow = 1
if (field.match('url')) {
let textField = field.replace('url', 'label')
data.forEach(el => el[textField] = domainFromUrl(el[field]))
@@ -46,36 +46,64 @@ class FileTable extends Component {
title,
field: textField,
formatter: 'link',
- formatterParams: { target: "_blank", urlField: field, },
+ formatterParams: { target: "_blank", urlField: field },
sorter: 'string'
}
}
+ if (title === 'Embassy') {
+ widthGrow = 2
+ }
switch (field) {
case 'images':
case 'year':
return { title, field: field.toLowerCase(), sorter: 'number' }
default:
- return { title, field: field.toLowerCase(), sorter: 'string' }
+ return { title, field: field.toLowerCase(), sorter: 'string', widthGrow }
}
})
return columns
}
+ updateFilter(q) {
+ const { keys, data } = this.state
+ if (!q.length) {
+ this.setState({ q, filteredData: data })
+ } else {
+ let qRe = new RegExp('(' + q.replace(/\s+/g, ' ').trim().replace(' ', '|') + ')', 'gi')
+ let filteredData = data.filter(row => keys.some(key => row[key].match(qRe)))
+ this.setState({ q, filteredData })
+ }
+ }
+
render() {
const { payload } = this.props
+ const { q, columns, data, filteredData } = this.state
if (!this.state.data.length) {
return <Loader />
}
+ const fn = payload.url.split('/').pop()
return (
- <ReactTabulator
- columns={this.state.columns}
- data={this.state.data}
- options={{
- height: Math.min(37 * this.state.data.length + 29, 311),
- layout: 'fitColumns',
- placeholder: 'No Data Set',
- }}
- />
+ <div className='citationBrowser'>
+ <div className='citationHeader'>
+ <input
+ type="text"
+ value={q}
+ onChange={e => this.updateFilter(e.target.value)}
+ className='q'
+ placeholder='Enter text to search data'
+ />
+ <a className='download' href={payload.url} filename={fn}>Download CSV</a>
+ </div>
+ <ReactTabulator
+ columns={columns}
+ data={filteredData}
+ options={{
+ height: Math.min(37 * data.length + 29, 311),
+ layout: 'fitColumns',
+ placeholder: 'No Data Set',
+ }}
+ />
+ </div>
)
}
}
diff --git a/client/table/tabulator.css b/client/table/tabulator.css
index 95768976..0ea81974 100644
--- a/client/table/tabulator.css
+++ b/client/table/tabulator.css
@@ -40,7 +40,7 @@
max-width: 400px;
margin-bottom: 10px;
background-image: url(/assets/img/icon-search.png);
- background-position: 380px center;
+ background-position: 378px center;
background-repeat: no-repeat;
box-shadow: 0px 2px 4px rgba(0,0,0,0.2);
border: 0;
@@ -53,17 +53,21 @@
align-items: flex-start;
justify-content: space-between;
}
-span.download {
+.download {
display: block;
font-size: 13px;
color: #ddd;
cursor: pointer;
background: #333;
- padding: 5px 8px;
+ padding: 5px 8px 5px 8px;
border-radius: 5px;
transition: all 0.2s;
+ border: 0 !important;
}
-.desktop span.download:hover {
+.content a.download {
+ padding: 5px 8px 5px 8px;
+}
+.desktop .download:hover {
color: #fff;
background: #666;
} \ No newline at end of file