Skip to content

Commit

Permalink
Merge pull request #210 from forensic-architecture/feature/add-shapes…
Browse files Browse the repository at this point in the history
…-filter-panel

Feature/add shapes filter panel
  • Loading branch information
ebefarooqui authored May 25, 2021
2 parents 4f45e80 + 9a323f7 commit dabc1b3
Show file tree
Hide file tree
Showing 24 changed files with 400 additions and 149 deletions.
29 changes: 28 additions & 1 deletion src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const EVENT_DATA_URL = urlFromEnv("EVENTS_EXT");
const ASSOCIATIONS_URL = urlFromEnv("ASSOCIATIONS_EXT");
const SOURCES_URL = urlFromEnv("SOURCES_EXT");
const SITES_URL = urlFromEnv("SITES_EXT");
const REGIONS_URL = urlFromEnv("REGIONS_EXT");
const SHAPES_URL = urlFromEnv("SHAPES_EXT");

const domainMsg = (domainType) =>
Expand Down Expand Up @@ -79,6 +80,13 @@ export function fetchDomain() {
.catch(() => handleError(domainMsg("sites")));
}

let regionsPromise = Promise.resolve([]);
if (features.USE_REGIONS) {
regionsPromise = fetch(REGIONS_URL)
.then((response) => response.json())
.catch(() => handleError(domainMsg("regions")));
}

let shapesPromise = Promise.resolve([]);
if (features.USE_SHAPES) {
shapesPromise = fetch(SHAPES_URL)
Expand All @@ -91,6 +99,7 @@ export function fetchDomain() {
associationsPromise,
sourcesPromise,
sitesPromise,
regionsPromise,
shapesPromise,
])
.then((response) => {
Expand All @@ -99,7 +108,8 @@ export function fetchDomain() {
associations: response[1],
sources: response[2],
sites: response[3],
shapes: response[4],
regions: response[4],
shapes: response[5],
notifications,
};
if (
Expand All @@ -111,6 +121,7 @@ export function fetchDomain() {
}
dispatch(toggleFetchingDomain());
dispatch(setInitialCategories(result.associations));
dispatch(setInitialShapes(result.shapes));
return result;
})
.catch((err) => {
Expand Down Expand Up @@ -205,6 +216,14 @@ export function toggleAssociations(association, value, shouldColor) {
};
}

export const TOGGLE_SHAPES = "TOGGLE_SHAPES";
export function toggleShapes(shape) {
return {
type: TOGGLE_SHAPES,
shape,
};
}

export const SET_LOADING = "SET_LOADING";
export function setLoading() {
return {
Expand All @@ -227,6 +246,14 @@ export function setInitialCategories(values) {
};
}

export const SET_INITIAL_SHAPES = "SET_INITIAL_SHAPES";
export function setInitialShapes(values) {
return {
type: SET_INITIAL_SHAPES,
values,
};
}

export const UPDATE_TIMERANGE = "UPDATE_TIMERANGE";
export function updateTimeRange(timerange) {
return {
Expand Down
23 changes: 22 additions & 1 deletion src/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,31 @@ export const ASSOCIATION_MODES = {
FILTER: "FILTER",
};

export const TIMELINE_ONLY = "TIMELINE_ONLY";
export const SHAPE = "SHAPE";

export const DEFAULT_TAB_ICONS = {
CATEGORY: "widgets",
NARRATIVE: "timeline",
FILTER: "filter_list",
SHAPE: "change_history",
};

export const AVAILABLE_SHAPES = {
STAR: "STAR",
DIAMOND: "DIAMOND",
PENTAGON: "PENTAGON",
SQUARE: "SQUARE",
DOT: "DOT",
BAR: "BAR",
TRIANGLE: "TRIANGLE",
};

export const POLYGON_CLIP_PATH = {
STAR:
"polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)",
DIAMOND: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)",
PENTAGON: "polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)",
TRIANGLE: "polygon(50% 0%, 0% 100%, 100% 100%)",
};

export const DEFAULT_CHECKBOX_COLOR = "#ffffff";
6 changes: 5 additions & 1 deletion src/common/data/copy.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@
"categories": "Categories",
"categories_label": "Categories",
"explore_by_category__title": "Explore events by category",
"explore_by_category__description": "‘Categories’ refer to the victims of a given incident.<br><br>If no categories are selected, all datapoints are displayed."
"explore_by_category__description": "‘Categories’ refer to the victims of a given incident.<br><br>If no categories are selected, all datapoints are displayed.",
"shapes": "Shapes",
"shapes_label": "Shapes",
"explore_by_shapes__title": "Explore events by shape breakdown",
"explore_by_shape__description": "Shapes map to a given type of event that appears on the timeline.<br><br>Select the shape marker to toggle this type of event on / off"
},
"timeline": {
"labels_title": "Testimonies",
Expand Down
24 changes: 22 additions & 2 deletions src/common/utilities.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import moment from "moment";
import hash from "object-hash";

import { ASSOCIATION_MODES } from "./constants";
import { ASSOCIATION_MODES, POLYGON_CLIP_PATH } from "./constants";

let { DATE_FMT, TIME_FMT } = process.env;
if (!DATE_FMT) DATE_FMT = "MM/DD/YYYY";
Expand Down Expand Up @@ -148,7 +148,7 @@ export function getFilterAncestors(filter) {
const accumulatedPath = splitFilter.slice(0, index + 1).join("/");
ancestors.push(accumulatedPath);
});
// // The last element here will be the leaf node aka the filter passed in
// The last element here will be the leaf node aka the filter passed in
ancestors.pop();
return ancestors;
}
Expand Down Expand Up @@ -510,3 +510,23 @@ export function setD3Locale(d3) {
d3.timeFormatDefaultLocale(languages[language]);
}
}

export function mapStyleByShape(shapes, activeShapes) {
const styledShapes = shapes.map((s) => {
const { colour, shape, id } = s;
const style = {
checkboxStyles: {
background: activeShapes.includes(id) ? colour : "black",
border: "none",
clipPath: POLYGON_CLIP_PATH[shape],
},
containerStyles: {
background: colour,
clipPath: POLYGON_CLIP_PATH[shape],
},
};
s.styles = style;
return s;
});
return styledShapes;
}
1 change: 1 addition & 0 deletions src/components/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ class Dashboard extends React.Component {
actions.toggleAssociations("filters", filters),
onCategoryFilter: (categories) =>
actions.toggleAssociations("categories", categories),
onShapeFilter: actions.toggleShapes,
onSelectNarrative: this.setNarrative,
}}
/>
Expand Down
103 changes: 53 additions & 50 deletions src/components/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as selectors from "../selectors";
import { Tabs, TabPanel } from "react-tabs";
import FilterListPanel from "./controls/FilterListPanel";
import CategoriesListPanel from "./controls/CategoriesListPanel";
import ShapesListPanel from "./controls/ShapesListPanel";
import BottomActions from "./controls/BottomActions";
import copy from "../common/data/copy.json";
import {
Expand All @@ -17,7 +18,6 @@ import {
addToColoringSet,
removeFromColoringSet,
} from "../common/utilities.js";
import { DEFAULT_TAB_ICONS } from "../common/constants";

class Toolbar extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -85,17 +85,10 @@ class Toolbar extends React.Component {

renderToolbarNarrativePanel() {
const { panels } = this.props.toolbarCopy;
const panelTitle = panels.narratives.label
? panels.narratives.label
: copy[this.props.language].toolbar.narratives;
const panelDescription = panels.narratives.description
? panels.narratives.description
: copy[this.props.language].toolbar.explore_by_narrative__description;

return (
<TabPanel>
<h2>{panelTitle}</h2>
<p>{panelDescription}</p>
<h2>{panels.narratives.label}</h2>
<p>{panels.narratives.description}</p>
{this.props.narratives.map((narr) => {
return (
<div className="panel-action action">
Expand All @@ -118,13 +111,6 @@ class Toolbar extends React.Component {

renderToolbarCategoriesPanel() {
const { panels } = this.props.toolbarCopy;
const panelTitle = panels.categories.label
? panels.categories.label
: copy[this.props.language].toolbar.categories;
const panelDescription = panels.categories.description
? panels.categories.description
: copy[this.props.language].toolbar.explore_by_category__description;

if (this.props.features.USE_CATEGORIES) {
return (
<TabPanel>
Expand All @@ -133,8 +119,8 @@ class Toolbar extends React.Component {
activeCategories={this.props.activeCategories}
onCategoryFilter={this.props.methods.onCategoryFilter}
language={this.props.language}
title={panelTitle}
description={panelDescription}
title={panels.categories.label}
description={panels.categories.description}
/>
</TabPanel>
);
Expand All @@ -143,13 +129,6 @@ class Toolbar extends React.Component {

renderToolbarFilterPanel() {
const { panels } = this.props.toolbarCopy;
const panelTitle = panels.filters.label
? panels.filters.label
: copy[this.props.language].toolbar.filters;
const panelDescription = panels.filters.description
? panels.filters.description
: copy[this.props.language].toolbar.explore_by_filter__description;

return (
<TabPanel>
<FilterListPanel
Expand All @@ -159,13 +138,32 @@ class Toolbar extends React.Component {
language={this.props.language}
coloringSet={this.props.coloringSet}
filterColors={this.props.filterColors}
title={panelTitle}
description={panelDescription}
title={panels.filters.label}
description={panels.filters.description}
/>
</TabPanel>
);
}

renderToolbarShapePanel() {
const { panels } = this.props.toolbarCopy;

if (this.props.features.USE_SHAPES) {
return (
<TabPanel>
<ShapesListPanel
shapes={this.props.shapes}
activeShapes={this.props.activeShapes}
onShapeFilter={this.props.methods.onShapeFilter}
language={this.props.language}
title={panels.shapes.label}
description={panels.shapes.description}
/>
</TabPanel>
);
}
}

renderToolbarTab(_selected, label, iconKey) {
const isActive = this.state._selected === _selected;
const classes = isActive ? "toolbar-tab active" : "toolbar-tab";
Expand Down Expand Up @@ -196,6 +194,7 @@ class Toolbar extends React.Component {
: null}
{features.USE_CATEGORIES ? this.renderToolbarCategoriesPanel() : null}
{features.USE_ASSOCIATIONS ? this.renderToolbarFilterPanel() : null}
{features.USE_SHAPES ? this.renderToolbarShapePanel() : null}
</Tabs>
</div>
);
Expand Down Expand Up @@ -228,49 +227,50 @@ class Toolbar extends React.Component {
const narrativesExist = narratives && narratives.length !== 0;
let title = copy[this.props.language].toolbar.title;
if (process.env.display_title) title = process.env.display_title;

const { panels } = toolbarCopy;
const narrativesLabel = copy[this.props.language].toolbar.narratives_label;
const filtersLabel = panels.filters.label
? panels.filters.label
: copy[this.props.language].toolbar.filters_label;
const categoriesLabel = panels.categories.label
? panels.categories.label
: copy[this.props.language].toolbar.categories_label;

const filterIcon = panels.filters.icon
? panels.filters.icon
: DEFAULT_TAB_ICONS.FILTER;
const categoriesIcon = panels.categories.icon
? panels.categories.icon
: DEFAULT_TAB_ICONS.CATEGORY;

const narrativesIdx = 0;
const categoriesIdx = narrativesExist ? 1 : 0;
const filtersIdx =
narrativesExist && features.CATEGORIES_AS_FILTERS
narrativesExist && features.USE_CATEGORIES
? 2
: narrativesExist || features.CATEGORIES_AS_FILTERS
: narrativesExist || features.USE_CATEGORIES
? 1
: 0;
const shapesIdx = filtersIdx + 1;
return (
<div className="toolbar">
<div className="toolbar-header" onClick={this.props.methods.onTitle}>
<p>{title}</p>
</div>
<div className="toolbar-tabs">
{narrativesExist
? this.renderToolbarTab(narrativesIdx, narrativesLabel, "timeline")
? this.renderToolbarTab(
narrativesIdx,
panels.narratives.label,
panels.narratives.icon
)
: null}
{features.CATEGORIES_AS_FILTERS
{features.USE_CATEGORIES
? this.renderToolbarTab(
categoriesIdx,
categoriesLabel,
categoriesIcon
panels.categories.label,
panels.categories.icon
)
: null}
{features.USE_ASSOCIATIONS
? this.renderToolbarTab(filtersIdx, filtersLabel, filterIcon)
? this.renderToolbarTab(
filtersIdx,
panels.filters.label,
panels.filters.icon
)
: null}
{features.USE_SHAPES
? this.renderToolbarTab(
shapesIdx,
panels.shapes.label,
panels.shapes.icon
)
: null}
</div>
<BottomActions
Expand Down Expand Up @@ -311,17 +311,20 @@ function mapStateToProps(state) {
filters: selectors.getFilters(state),
categories: selectors.getCategories(state),
narratives: selectors.selectNarratives(state),
shapes: selectors.getShapes(state),
language: state.app.language,
toolbarCopy: state.app.toolbar,
activeFilters: selectors.getActiveFilters(state),
activeCategories: selectors.getActiveCategories(state),
activeShapes: selectors.getActiveShapes(state),
viewFilters: state.app.associations.views,
narrative: state.app.associations.narrative,
sitesShowing: state.app.flags.isShowingSites,
infoShowing: state.app.flags.isInfopopup,
coloringSet: state.app.associations.coloringSet,
maxNumOfColors: state.ui.coloring.maxNumOfColors,
filterColors: state.ui.coloring.colors,
eventRadius: state.ui.eventRadius,
features: selectors.getFeatures(state),
};
}
Expand Down
Loading

0 comments on commit dabc1b3

Please sign in to comment.