mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-12 05:18:34 +03:00
Working cluster visualization; need to modify styling for clusters for size and work out color based on events
This commit is contained in:
@@ -168,6 +168,10 @@ export function calcOpacity (num) {
|
||||
return base + (Math.min(0.5, 0.08 * (num - 1)))
|
||||
}
|
||||
|
||||
export function calcClusterSize (pointCount, numClusters) {
|
||||
return Math.min(50, 10 + (pointCount / numClusters) * 20)
|
||||
}
|
||||
|
||||
export const dateMin = function () {
|
||||
return Array.prototype.slice.call(arguments).reduce(function (a, b) {
|
||||
return a < b ? a : b
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'leaflet'
|
||||
import Sites from './presentational/Map/Sites.jsx'
|
||||
import Shapes from './presentational/Map/Shapes.jsx'
|
||||
import Events from './presentational/Map/Events.jsx'
|
||||
import Clusters from './presentational/Map/Clusters.jsx'
|
||||
import SelectedEvents from './presentational/Map/SelectedEvents.jsx'
|
||||
import Narratives from './presentational/Map/Narratives'
|
||||
import DefsMarkers from './presentational/Map/DefsMarkers.jsx'
|
||||
@@ -262,6 +263,10 @@ class Map extends React.Component {
|
||||
return [null, null]
|
||||
}
|
||||
|
||||
styleCluster (cluster) {
|
||||
return [null, null]
|
||||
}
|
||||
|
||||
renderEvents () {
|
||||
const individualClusters = this.state.clusters.filter(cl => !cl.properties.cluster)
|
||||
const filteredLocations = individualClusters.map(cl => this.props.domain.locations.find(location => location.label === cl.properties.id))
|
||||
@@ -282,6 +287,20 @@ class Map extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
renderClusters () {
|
||||
const allClusters = this.state.clusters.filter(cl => cl.properties.cluster)
|
||||
return (
|
||||
<Clusters
|
||||
svg={this.svgRef.current}
|
||||
styleCluster={this.styleCluster}
|
||||
projectPoint={this.projectPoint}
|
||||
clusters={allClusters}
|
||||
numClusters={allClusters.length}
|
||||
// onSelect={() => {}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
renderSelected () {
|
||||
return (
|
||||
<SelectedEvents
|
||||
@@ -303,7 +322,7 @@ class Map extends React.Component {
|
||||
|
||||
render () {
|
||||
const { isShowingSites } = this.props.app.flags
|
||||
// console.info(this.state.clusters)
|
||||
console.info(this.state.clusters)
|
||||
const classes = this.props.app.narrative ? 'map-wrapper narrative-mode' : 'map-wrapper'
|
||||
const innerMap = this.map ? (
|
||||
<React.Fragment>
|
||||
@@ -313,6 +332,7 @@ class Map extends React.Component {
|
||||
{this.renderShapes()}
|
||||
{this.renderNarratives()}
|
||||
{this.renderEvents()}
|
||||
{this.renderClusters()}
|
||||
{this.renderSelected()}
|
||||
</React.Fragment>
|
||||
) : null
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
import React from 'react'
|
||||
import { Portal } from 'react-portal'
|
||||
import colors from '../../../common/global.js'
|
||||
import { calcOpacity } from '../../../common/utilities'
|
||||
import { calcOpacity, calcClusterSize } from '../../../common/utilities'
|
||||
|
||||
function ClusterEvents ({
|
||||
projectPoint,
|
||||
styleCluster,
|
||||
onSelect,
|
||||
// onSelect,
|
||||
svg,
|
||||
clusters,
|
||||
radius
|
||||
numClusters,
|
||||
}) {
|
||||
function renderClusterBySize (cluster) {
|
||||
const { point_count, cluster_id } = cluster.properties
|
||||
|
||||
const size = calcClusterSize(point_count, numClusters)
|
||||
|
||||
const width = `${size}px`
|
||||
const height = `${size}px`
|
||||
|
||||
const styles = ({
|
||||
fill: 'blue',
|
||||
stroke: colors.darkBackground,
|
||||
strokeWidth: 0,
|
||||
fillOpacity: calcOpacity(point_count),
|
||||
width,
|
||||
height
|
||||
})
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<path
|
||||
class='cluster-event-marker'
|
||||
id={cluster_id}
|
||||
d="M 8 0 A 8 8 0 1 1 8 -1.959434878635765e-15 L 0 0 L 8 0 Z"
|
||||
style={styles}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +72,7 @@ function ClusterEvents ({
|
||||
<g
|
||||
className={'cluster-event'}
|
||||
transform={`translate(${x}, ${y})`}
|
||||
onClick={this.props.onSelect}
|
||||
// onClick={this.props.onSelect}
|
||||
>
|
||||
{renderClusterBySize(cluster)}
|
||||
{extraRender ? extraRender() : null}
|
||||
@@ -57,7 +82,7 @@ function ClusterEvents ({
|
||||
|
||||
return (
|
||||
<Portal node={svg}>
|
||||
<g className='clusters'>
|
||||
<g className='cluster-locations'>
|
||||
{clusters.map(renderCluster)}
|
||||
</g>
|
||||
</Portal>
|
||||
|
||||
@@ -53,7 +53,7 @@ const initial = {
|
||||
maxZoom: 18,
|
||||
bounds: null,
|
||||
maxBounds: [[180, -180], [-180, 180]],
|
||||
clusterRadius: 40,
|
||||
clusterRadius: 50,
|
||||
},
|
||||
timeline: {
|
||||
dimensions: {
|
||||
|
||||
Reference in New Issue
Block a user