Skip to content
Snippets Groups Projects
Commit 56bbd1a7 authored by esikkala's avatar esikkala
Browse files

Support nested result classes

parent 443f0126
No related branches found
No related tags found
No related merge requests found
......@@ -33,16 +33,25 @@ class ApexChart extends React.Component {
constructor (props) {
super(props)
this.chartRef = React.createRef()
const { resultClassConfig, apexChartsConfig } = this.props
let resultClass = this.props.resultClass
if (resultClassConfig.dropdownForResultClasses) {
resultClass = resultClassConfig.defaultResultClass
}
this.state = {
resultClass: props.resultClass,
createChartData: props.createChartData,
chartType: props.dropdownForChartTypes ? props.chartTypes[0].id : null,
resultClass,
createChartData: resultClassConfig.createChartData
? apexChartsConfig[resultClassConfig.createChartData]
: apexChartsConfig[resultClassConfig.chartTypes[0].createChartData],
chartType: resultClassConfig.dropdownForChartTypes ? resultClassConfig.chartTypes[0].id : null,
dialogData: null
}
}
componentDidMount = () => {
if (this.props.rawData && this.props.rawData.length > 0 && !this.props.doNotRenderOnMount) {
const { results } = this.props
const { doNotRenderOnMount } = this.props.resultClassConfig
if (results && results.length > 0 && !doNotRenderOnMount) {
this.renderChart()
}
this.props.fetchData({
......@@ -55,12 +64,11 @@ class ApexChart extends React.Component {
}
componentDidUpdate = (prevProps, prevState) => {
// Render the chart again if the raw data has changed
if (prevProps.rawDataUpdateID !== this.props.rawDataUpdateID) {
if (prevProps.resultUpdateID !== this.props.resultUpdateID) {
this.renderChart()
}
// check if filters have changed
if (this.props.pageType === 'facetResults' && prevProps.facetUpdateID !== this.props.facetUpdateID) {
const { pageType = 'facetResults' } = this.props
if (pageType === 'facetResults' && prevProps.facetUpdateID !== this.props.facetUpdateID) {
this.props.fetchData({
perspectiveID: this.props.perspectiveConfig.id,
resultClass: this.state.resultClass,
......@@ -102,24 +110,7 @@ class ApexChart extends React.Component {
}
this.chart = new ApexCharts(
this.chartRef.current,
this.state.createChartData({
rawData: this.props.rawData,
title: this.props.title,
xaxisTitle: this.props.xaxisTitle || intl.get(`apexCharts.${this.state.resultClass}Xaxis`),
yaxisTitle: this.props.yaxisTitle || '',
seriesTitle: this.props.seriesTitle || '',
xaxisType: this.props.xaxisType || null,
xaxisTickAmount: this.props.xaxisTickAmount || null,
xaxisLabels: this.props.xaxisLabels || null,
stroke: this.props.stroke || null,
fill: this.props.fill || null,
tooltip: this.props.tooltip || null,
fetchInstanceAnalysis: this.props.fetchInstanceAnalysis,
resultClass: this.props.resultClass,
facetID: this.props.facetID,
facetClass: this.props.facetClass,
screenSize: this.props.screenSize
})
this.state.createChartData({ ...this.props })
)
this.chart.render()
}
......@@ -128,10 +119,10 @@ class ApexChart extends React.Component {
handleChartTypeOnChanhge = event => {
const chartType = event.target.value
const chartTypeObj = this.props.chartTypes.find(chartTypeObj => chartTypeObj.id === chartType)
const chartTypeObj = this.props.resultClassConfig.chartTypes.find(chartTypeObj => chartTypeObj.id === chartType)
this.setState({
chartType,
createChartData: chartTypeObj.createChartData
createChartData: this.props.apexChartsConfig[chartTypeObj.createChartData]
})
}
......@@ -146,12 +137,12 @@ class ApexChart extends React.Component {
if (this.isSmallScreen()) {
return 'auto'
}
const rootHeightReduction = this.props.layoutConfig.tabHeight + 2 * defaultPadding + 1
const rootHeightReduction = this.props.portalConfig.layoutConfig.tabHeight + 2 * defaultPadding + 1
return `calc(100% - ${rootHeightReduction}px)`
}
getHeightForChartContainer = () => {
const { dropdownForResultClasses, dropdownForChartTypes } = this.props
const { dropdownForResultClasses, dropdownForChartTypes } = this.props.resultClassConfig
if (this.isSmallScreen()) {
return 600
}
......@@ -166,14 +157,8 @@ class ApexChart extends React.Component {
}
render () {
const {
fetching, pageType, classes, dropdownForResultClasses,
dropdownForChartTypes, facetResultsType
} = this.props
let facetResultsTypeCapitalized = ''
if (facetResultsType) {
facetResultsTypeCapitalized = facetResultsType[0].toUpperCase() + facetResultsType.substring(1).toLowerCase()
}
const { classes, fetching, resultClassConfig } = this.props
const { pageType = 'facetResults', dropdownForResultClasses, resultClasses, dropdownForChartTypes, chartTypes } = resultClassConfig
let rootStyle = {
width: '100%',
height: '100%'
......@@ -199,9 +184,7 @@ class ApexChart extends React.Component {
width: '100%',
height: this.getHeightForChartContainer()
}
let dropdownText = intl.get('apexCharts.by') === ''
? intl.get('apexCharts.grouping')
: `${facetResultsTypeCapitalized} ${intl.get('apexCharts.by')}`
let dropdownText = intl.get('apexCharts.grouping')
if (this.props.xaxisType === 'numeric') {
dropdownText = intl.get('apexCharts.property')
}
......@@ -216,7 +199,7 @@ class ApexChart extends React.Component {
value={this.state.resultClass}
onChange={this.handleResultClassOnChanhge}
>
{this.props.resultClasses.map(resultClass =>
{Object.keys(resultClasses).map(resultClass =>
<MenuItem key={resultClass} value={resultClass}>{intl.get(`apexCharts.resultClasses.${resultClass}`)}</MenuItem>
)}
</Select>
......@@ -231,7 +214,7 @@ class ApexChart extends React.Component {
value={this.state.chartType}
onChange={this.handleChartTypeOnChanhge}
>
{this.props.chartTypes.map(chartType =>
{chartTypes.map(chartType =>
<MenuItem key={chartType.id} value={chartType.id}>{intl.get(`apexCharts.${chartType.id}`)}</MenuItem>
)}
</Select>
......@@ -261,23 +244,9 @@ class ApexChart extends React.Component {
}
ApexChart.propTypes = {
pageType: PropTypes.string.isRequired,
createChartData: PropTypes.func,
rawData: PropTypes.oneOfType([
PropTypes.array,
PropTypes.object
]),
rawDataUpdateID: PropTypes.number,
fetchData: PropTypes.func.isRequired,
fetching: PropTypes.bool.isRequired,
resultClass: PropTypes.string,
facetClass: PropTypes.string,
facetID: PropTypes.string,
uri: PropTypes.string,
dropdownForResultClasses: PropTypes.bool,
facetResultsType: PropTypes.string,
resultClasses: PropTypes.array,
layoutConfig: PropTypes.object.isRequired
facetClass: PropTypes.string
}
export const ApexChartComponent = ApexChart
......
......@@ -247,65 +247,21 @@ const ResultClassRoute = props => {
break
}
case 'ApexCharts': {
const {
pageType = 'facetResults',
title,
xaxisTitle,
xaxisType,
xaxisTickAmount,
yaxisTitle,
seriesTitle,
stroke,
fill,
createChartData,
doNotRenderOnMount = false,
dropdownForResultClasses = false,
dropdownForChartTypes = false
} = resultClassConfig
const apexProps = {
portalConfig,
perspectiveConfig: perspective,
pageType,
resultClassConfig,
apexChartsConfig: props.apexChartsConfig,
screenSize,
resultClass,
facetClass,
rawData: perspectiveState.results,
rawDataUpdateID: perspectiveState.resultUpdateID,
perspectiveState,
results: perspectiveState.results,
fetching: perspectiveState.fetching,
fetchData: props.fetchResults,
createChartData: props.apexChartsConfig[createChartData],
title,
xaxisTitle,
xaxisType,
xaxisTickAmount,
yaxisTitle,
seriesTitle,
stroke,
fill,
layoutConfig: props.layoutConfig,
doNotRenderOnMount,
dropdownForResultClasses
}
if (pageType === 'facetResults') {
apexProps.facetUpdateID = facetState.facetUpdateID
}
if (pageType === 'instancePage') {
apexProps.uri = perspectiveState.instanceTableData.id
}
if (dropdownForResultClasses && has(resultClassConfig, 'resultClasses')) {
apexProps.resultClass = resultClassConfig.resultClasses[0]
apexProps.resultClasses = resultClassConfig.resultClasses
apexProps.dropdownForResultClasses = true
}
if (dropdownForChartTypes && has(resultClassConfig, 'chartTypes')) {
const { chartTypes } = resultClassConfig
const newChartTypes = chartTypes.map(chartType => {
return {
id: chartType.id,
createChartData: props.apexChartsConfig[chartType.createChartData]
}
})
apexProps.chartTypes = newChartTypes
apexProps.dropdownForChartTypes = true
resultUpdateID: perspectiveState.resultUpdateID,
instanceAnalysisDataUpdateID: perspectiveState.instanceAnalysisDataUpdateID,
facetUpdateID: facetState.facetUpdateID,
fetchData: props.fetchResults
}
routeComponent = (
<Route
......
......@@ -161,9 +161,9 @@ export const arrayToObject = ({ array, keyField }) =>
return obj
}, {})
export const generateLabelForMissingValue = ({ facetClass, facetID }) => {
export const generateLabelForMissingValue = ({ perspective, property }) => {
// Check if there is a translated label for missing value, or use defaults
return intl.get(`perspectives.${facetClass}.properties.${facetID}.missingValueLabel`) ||
return intl.get(`perspectives.${perspective}.properties.${property}.missingValueLabel`) ||
intl.get('facetBar.defaultMissingValueLabel') || 'Unknown'
}
......
......@@ -2,6 +2,15 @@
import intl from 'react-intl-universal'
import { generateLabelForMissingValue } from '../../helpers/helpers'
// list of colors generated with http://phrogz.net/css/distinct-colors.html
const pieChartColors = ['#a12a3c', '#0f00b5', '#81c7a4', '#ffdea6', '#ff0033', '#424cff', '#1b6935', '#ff9d00', '#5c3c43',
'#5f74b8', '#18b532', '#3b3226', '#fa216d', '#153ca1', '#00ff09', '#703a00', '#b31772', '#a4c9fc', '#273623',
'#f57200', '#360e2c', '#001c3d', '#ccffa6', '#a18068', '#ba79b6', '#004e75', '#547500', '#c2774c', '#f321fa', '#1793b3',
'#929c65', '#b53218', '#563c5c', '#1ac2c4', '#c4c734', '#4c150a', '#912eb3', '#2a5252', '#524b00', '#bf7d7c', '#24005e',
'#20f2ba', '#b5882f']
const defaultSliceVisibilityThreshold = 0.01
export const createSingleLineChartData = ({
rawData,
title,
......@@ -106,26 +115,37 @@ export const createMultipleLineChartData = ({
return apexChartOptionsWithData
}
export const createApexPieChartData = ({ rawData, screenSize, facetClass, facetID }) => {
export const createApexPieChartData = ({
resultClass,
facetClass,
perspectiveState,
results,
resultClassConfig,
screenSize
}) => {
const labels = []
const series = []
let otherCount = 0
const totalLength = rawData.length
const threshold = 0.15
rawData.forEach(item => {
const portion = parseInt(item.instanceCount) / totalLength
if (portion < threshold) {
otherCount += parseInt(item.instanceCount)
const arraySum = results.reduce((sum, current) => sum + current.instanceCount, 0)
let actualResultClassConfig = resultClassConfig
if (resultClassConfig.dropdownForResultClasses) {
actualResultClassConfig = resultClassConfig.resultClasses[perspectiveState.resultClass]
}
const { sliceVisibilityThreshold = defaultSliceVisibilityThreshold, propertyID } = actualResultClassConfig
results.forEach(item => {
const sliceFraction = item.instanceCount / arraySum
if (sliceFraction <= sliceVisibilityThreshold) {
otherCount += item.instanceCount
} else {
if (item.id === 'http://ldf.fi/MISSING_VALUE') {
item.prefLabel = generateLabelForMissingValue({ facetClass, facetID })
if (item.id === 'http://ldf.fi/MISSING_VALUE' || item.category === 'http://ldf.fi/MISSING_VALUE') {
item.prefLabel = generateLabelForMissingValue({ perspective: facetClass, property: propertyID })
}
labels.push(item.prefLabel)
series.push(parseInt(item.instanceCount))
series.push(item.instanceCount)
}
})
if (otherCount !== 0) {
labels.push('Other')
labels.push(intl.get('apexCharts.other') || 'Other')
series.push(otherCount)
}
let chartColors = []
......@@ -157,13 +177,6 @@ export const createApexPieChartData = ({ rawData, screenSize, facetClass, facetI
return apexChartOptionsWithData
}
// list of colors generated with http://phrogz.net/css/distinct-colors.html
const pieChartColors = ['#a12a3c', '#0f00b5', '#81c7a4', '#ffdea6', '#ff0033', '#424cff', '#1b6935', '#ff9d00', '#5c3c43',
'#5f74b8', '#18b532', '#3b3226', '#fa216d', '#153ca1', '#00ff09', '#703a00', '#b31772', '#a4c9fc', '#273623',
'#f57200', '#360e2c', '#001c3d', '#ccffa6', '#a18068', '#ba79b6', '#004e75', '#547500', '#c2774c', '#f321fa', '#1793b3',
'#929c65', '#b53218', '#563c5c', '#1ac2c4', '#c4c734', '#4c150a', '#912eb3', '#2a5252', '#524b00', '#bf7d7c', '#24005e',
'#20f2ba', '#b5882f']
const apexPieChartOptions = {
// see https://apexcharts.com/docs --> Options
chart: {
......@@ -214,30 +227,45 @@ const apexPieChartOptions = {
}
export const createApexBarChartData = ({
rawData,
title,
xaxisTitle,
yaxisTitle,
seriesTitle
resultClass,
facetClass,
perspectiveState,
results,
resultClassConfig,
screenSize
}) => {
const {
title,
seriesTitle,
xaxisTitle,
yaxisTitle
} = resultClassConfig
const categories = []
const colors = []
const data = []
let otherCount = 0
const totalLength = rawData.length
const threshold = 0.3
rawData.forEach(item => {
const portion = parseInt(item.instanceCount) / totalLength
if (portion < threshold) {
otherCount += parseInt(item.instanceCount)
const arraySum = results.reduce((sum, current) => sum + current.instanceCount, 0)
let actualResultClassConfig = resultClassConfig
if (resultClassConfig.dropdownForResultClasses) {
actualResultClassConfig = resultClassConfig.resultClasses[perspectiveState.resultClass]
}
const { sliceVisibilityThreshold = defaultSliceVisibilityThreshold, propertyID } = actualResultClassConfig
results.forEach(item => {
const sliceFraction = item.instanceCount / arraySum
if (sliceFraction <= sliceVisibilityThreshold) {
otherCount += item.instanceCount
} else {
if (item.id === 'http://ldf.fi/MISSING_VALUE' || item.category === 'http://ldf.fi/MISSING_VALUE') {
item.prefLabel = generateLabelForMissingValue({ perspective: facetClass, property: propertyID })
}
categories.push(item.prefLabel)
colors.push('#000000')
data.push(parseInt(item.instanceCount))
data.push(item.instanceCount)
}
})
if (otherCount !== 0) {
categories.push('Other')
categories.push(intl.get('apexCharts.other') || 'Other')
colors.push('#000000')
data.push(otherCount)
}
......
......@@ -83,9 +83,18 @@ for (const perspective of perspectiveConfig) {
...facetsInitialState,
facets
}
let extraResultClasses = {}
for (const resultClass in resultClasses) {
if (resultClasses[resultClass].resultClasses) {
extraResultClasses = {
...extraResultClasses,
...resultClasses[resultClass].resultClasses
}
}
}
const resultsReducer = createResultsReducer(
resultsInitialStateFull,
new Set(Object.keys({ ...resultClasses, ...instancePageResultClasses })))
new Set(Object.keys({ ...resultClasses, ...instancePageResultClasses, ...extraResultClasses })))
const facetsReducer = createFacetsReducer(facetsInitialStateFull, perspectiveID)
const facetsConstrainSelfReducer = createFacetsConstrainSelfReducer(facetsInitialStateFull, perspectiveID)
reducers[perspectiveID] = resultsReducer
......
......@@ -35,6 +35,39 @@ export const mapCoordinates = sparqlBindings => {
return results
}
export const mapBirthYearCount = sparqlBindings => {
// console.log(sparqlBindings);
const results = sparqlBindings.map(b => {
return {
counted: b.counted.value,
count: b.count.value
}
})
return results
}
export const mapAgeCount = sparqlBindings => {
// console.log(sparqlBindings);
const results = sparqlBindings.map(b => {
return {
counted: b.counted.value,
count: b.count.value
}
})
return results
}
export const mapCountGroups = sparqlBindings => {
// console.log(sparqlBindings);
const results = sparqlBindings.map(b => {
return {
counted: b.counted.value,
count: b.count.value
}
})
return results
}
export const mapCount = sparqlBindings => {
return sparqlBindings[0].count.value
}
......@@ -190,7 +223,7 @@ export const mapPieChart = sparqlBindings => {
return {
category: b.category.value,
prefLabel: b.prefLabel.value,
instanceCount: b.instanceCount.value
instanceCount: parseInt(b.instanceCount.value)
}
})
return results
......
......@@ -49,10 +49,24 @@ export const createBackendSearchConfig = async () => {
}
}
// handle other resultClasses
let extraResultClasses = {}
for (const resultClass in perspectiveConfig.resultClasses) {
if (resultClass === perspectiveID) { continue }
const resultClassConfig = perspectiveConfig.resultClasses[resultClass]
processResultClassConfig(resultClassConfig, sparqlQueries, resultMappers)
if (resultClassConfig.resultClasses) {
for (const extraResultClass in resultClassConfig.resultClasses) {
processResultClassConfig(resultClassConfig.resultClasses[extraResultClass], sparqlQueries, resultMappers)
}
extraResultClasses = {
...extraResultClasses,
...resultClassConfig.resultClasses
}
}
}
perspectiveConfig.resultClasses = {
...perspectiveConfig.resultClasses,
...extraResultClasses
}
// merge facet results and instance page result classes
if (hasInstancePageResultClasses) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment