Skip to content

Commit

Permalink
Indicate shapes with no connected data - transparent fill? #62
Browse files Browse the repository at this point in the history
When removing a chip, add matches to Other #63
When dropping a chip, replace with the next most popular value if available #65
* Move the found records and other records collections building into Map local variables to avoid excessive mobx reactions.
* Even though we only show the top seven search terms, all others will still be calculated and stored, but shown within 'Other'
* Clean up colour handling, add an 'Other' colour (currently a light cream colour).
* Use a transparent fill for geo polygons that have no data.
* Always show 'Other' chip in MapFilter
  • Loading branch information
dylanett committed Mar 14, 2019
1 parent 6b06e7e commit 70a19fa
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 101 deletions.
127 changes: 84 additions & 43 deletions react-app/src/components/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const L = window.L

const Map = observer(class extends React.Component {

_foundRecords = []
_otherRecords = []

static propTypes = {
selected: PropTypes.object.isRequired,
store: PropTypes.object,
Expand Down Expand Up @@ -226,10 +229,11 @@ const Map = observer(class extends React.Component {
if (found) {
foundPoints.push(point)
} else {
this._otherRecords.push(record)
L.marker(point, {icon: this.iconX})
.addTo(this.markers)
.on('click', () => {
this.updateSelected(point, record)
.on('click', (e) => {
this.updateSelected(point, record, e)
})
}
}
Expand All @@ -238,7 +242,8 @@ const Map = observer(class extends React.Component {

this.markers.addTo(this.map)

this.props.store.addFieldNames(records[0])
if (records[0] && this.props.store.fieldNames.length === 0)
this.props.store.addFieldNames(records[0])

if (foundPoints.length > 0) {
this.centerMapOnPoints(foundPoints)
Expand All @@ -247,6 +252,8 @@ const Map = observer(class extends React.Component {
}
this.updatePoints(points)

this.updateStoreRecords(this._foundRecords, this._otherRecords)

function getGeoJson(record) {
let result
if (record.geometry) {
Expand All @@ -268,13 +275,14 @@ const Map = observer(class extends React.Component {

}

// This is used for non-geojson sourced markers, and uses the little house icon.
makeFoundMarker = (point, record, index) => {
L.marker(point, {icon: this.icons[index < 7 ? index : 7], zIndexOffset: (index * 100) + 500})
.addTo(this.markers)
.on('click', () => {
this.updateSelected(point, record)
.on('click', (e) => {
this.updateSelected(point, record, e)
})
this.addFoundRecord(record, index < 7 ? index : 7)
this.addFoundRecord(record, index)
}

getFirstPoint = (geoJson) => {
Expand All @@ -297,59 +305,81 @@ const Map = observer(class extends React.Component {
return null
}

// This is used for geojson sourced markers or polygons.
getPolygonStyle = (geojson, foundPoints) => {
// Default colours
let color = '#E6A224'
let fillColor = '#E8DDD4'
let fillColor = Layout.colours[7]
let fillOpacity = 0.7
if (_.get(geojson.geometry, 'type') === 'Point') {
color = '#E8DDD4'
color = Layout.colours[7]
fillColor = '#E6A224'
}

// Basic properties of geojson
let found = false
if (this.props.store.searchStrings.length > 0) {
const records = [ geojson.properties ]
if (geojson._id) {
_.each(this.props.store.linkMap[geojson._id], (linkRecord) => {
records.push(linkRecord)
})
}
const records = [ geojson.properties ]
if (geojson._id) {
// Grab the records related to this geojson object.
_.each(this.props.store.linkMap[geojson._id], (linkRecord) => {
records.push(linkRecord)
})
}

this.props.store.searchStrings.forEach((element, index) => {
if (element.includes(':')) {
// This is a specific field/value search such as 'Surname: Smith'
const separatorLocation = element.indexOf(':')
const highlightField = element.substring(0, separatorLocation)
const highlightValue = element.substring(separatorLocation + 2)
_.each(records, (record) => {
// eslint-disable-next-line
if (_.get(record, highlightField) == highlightValue) {
found = true
fillColor = Layout.colours[index]
this.addFoundRecord(record, index)
}
})
} else {
if (records.length > 1)
_.each(records, (record) => {
// When there is no related data, go with transparent fill.
if (records.length < 2) {
fillOpacity = 0
}

// Search for any search terms to apply special highlighting
if (this.props.store.searchStrings.length > 0) {
// Look in each record related to this geojson
_.each(records, (record) => {
found = false
// Check for every search term in this record
this.props.store.searchStrings.forEach((element, index) => {
// Only search for up to the first seven search terms. The rest get tossed into 'Other'.
if (index < 7) {
if (element.includes(':')) {
// This is a specific field/value search such as 'Surname: Smith'
const separatorLocation = element.indexOf(':')
const highlightField = element.substring(0, separatorLocation)
const highlightValue = element.substring(separatorLocation + 2)
// eslint-disable-next-line
if (_.get(record, highlightField) == highlightValue) {
found = true
fillColor = Layout.colours[index]
this.addFoundRecord(record, index)
}
} else {
// This is a regular search.
if (JSON.stringify(record).toLowerCase().includes(element.toLowerCase())) {
found = true
fillColor = Layout.colours[index]
this.addFoundRecord(record, index)
}
})
}
}
})
// If nothing was found, add to otherRecords
if (!found) {
this._otherRecords.push(record)
}
})
}

// Grab any point off the geojson to use for the map centering.
if (found) {
foundPoints.push(this.getFirstPoint(geojson))
}

// Return our styling
return {
color,
fillColor,
weight: 1,
opacity: 0.25,
fillOpacity: 0.3,
fillOpacity,
}
}

Expand All @@ -369,9 +399,14 @@ const Map = observer(class extends React.Component {
}

// Emphasize newly selected marker
marker.layer._path.style.stroke = '#F00'
marker.layer._path.style.strokeOpacity = 1
marker.layer._path.style.strokeWidth = 4
if (marker.layer) {
// This is a geojson marker
marker.layer._path.style.stroke = '#F00'
marker.layer._path.style.strokeOpacity = 1
marker.layer._path.style.strokeWidth = 4
} else {
// TODO: Highlight old house style markers.
}

// Gather up records related to selection
if (record.data) { // This is a server based relationship record
Expand All @@ -397,16 +432,22 @@ const Map = observer(class extends React.Component {
this.props.store.points = points
})

addFoundRecord = action( (record, index) => {
this.props.store.foundRecords[index].push(record)
updateStoreRecords = action( (newFoundRecords, newOtherRecords) => {
this.props.store.foundRecords = newFoundRecords
this.props.store.otherRecords = newOtherRecords
})

resetFoundRecords = action( () => {
this.props.store.foundRecords = []
addFoundRecord = (record, index) => {
this._foundRecords[index].push(record)
}

resetFoundRecords = () => {
this._foundRecords = []
this._otherRecords = []
this.props.store.searchStrings.forEach(() => {
this.props.store.foundRecords.push([])
this._foundRecords.push([])
})
})
}

makePoint = (record) => {
// first try to make a point through the relationships
Expand Down
9 changes: 5 additions & 4 deletions react-app/src/components/MapDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ const MapDrawer = observer(class extends React.Component {

if (this.props.store.highlightField !== 'none') {
const pieChartData = []
for (let i=0; i<this.props.store.foundRecords.length; i++) {
let shownSliceCount = this.props.store.foundRecords.length
if (shownSliceCount>7)
shownSliceCount = 7
for (let i=0; i<shownSliceCount; i++) {
pieChartData.push({ color: Layout.colours[i], value: this.props.store.foundRecords[i].length })
}
if (this.props.store.searchStrings.length>7) {
pieChartData.push({ color: Layout.colours[7], value: this.props.store.getOtherCount() })
}
pieChartData.push({ color: Layout.colours[7], value: this.props.store.getOtherCount })
pieChart = <div>
<Typography variant='h5' align='center'>{this.props.store.highlightField}</Typography>
<PieChart
Expand Down
53 changes: 25 additions & 28 deletions react-app/src/components/MapFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,11 @@ const MapFilter = observer(class extends React.Component {

valueCounts = _.sortBy(valueCounts, (o) => -o.count)
this.props.store.searchStrings = []
for (let i=0; i<7; i++) {
for (let i=0; i<valueCounts.length; i++) {
if (valueCounts[i]) {
this.props.store.searchStrings.push(event.target.value + ': ' + valueCounts[i].value)
}
}
if (valueCounts.length>7) {
let otherCount = 0
for (let i=7; i<valueCounts.length; i++) {
otherCount += valueCounts[i].count
}
this.props.store.searchStrings.push('Other ('+otherCount+')')
}
})

countFieldValue = (valueCounts, thisValue) => {
Expand Down Expand Up @@ -96,19 +89,31 @@ const MapFilter = observer(class extends React.Component {
}
})

handleSearchDelete =
action(
(data) => {
if (this.props.store.searchStrings) {
const deletedIndex = this.props.store.searchStrings.indexOf(data)
this.props.store.searchStrings.splice(deletedIndex, 1)
this.props.store.foundRecords.splice(deletedIndex, 1)
}
});
handleSearchDelete = action( (data) => {
if (this.props.store.searchStrings) {
const deletedIndex = this.props.store.searchStrings.indexOf(data)
this.props.store.searchStrings.splice(deletedIndex, 1)
}
});

render() {
const { classes } = this.props

let otherChip = ''
if (this.props.store.searchStrings.length>0) {
const otherChipStyle = {
margin: 5,
backgroundColor: Layout.colours[7],
}
const otherLabel = 'Other: ' + this.props.store.getOtherCount
otherChip = <Chip
key='Other'
label={otherLabel}
style={otherChipStyle}
color='default'
/>
}

return (
<form className={classes.container} noValidate autoComplete='off'>

Expand Down Expand Up @@ -186,10 +191,8 @@ const MapFilter = observer(class extends React.Component {
<div className={classes.root}>
{this.props.store.searchStrings.map( (data, i) => {
let labelValue = data + ' (' + this.props.store.foundRecords[i].length + ')'
let isDeletable = true
if (data.startsWith('Other')) {
labelValue = data
isDeletable = false
}
const divStyle = {
margin: 5,
Expand All @@ -198,7 +201,7 @@ const MapFilter = observer(class extends React.Component {
let colour = 'primary'
if ([1,2,5].indexOf(i) > -1)
colour = 'default'
if (isDeletable) {
if (i<7) {
return (
<Chip
key={data}
Expand All @@ -209,16 +212,10 @@ const MapFilter = observer(class extends React.Component {
/>
)
} else {
return (
<Chip
key={data}
label={labelValue}
style={divStyle}
color={colour}
/>
)
return ''
}
})}
{otherChip}
</div>
</form>
)
Expand Down
Loading

0 comments on commit 70a19fa

Please sign in to comment.