|
|
|
@ -15,32 +15,41 @@ |
|
|
|
|
|
|
|
<script> |
|
|
|
import { onMount } from "svelte"; |
|
|
|
import shortid from "shortid" |
|
|
|
|
|
|
|
const _id = shortid.generate() |
|
|
|
|
|
|
|
export let type = "bar"; |
|
|
|
export let data = []; |
|
|
|
export let tooltipProps = null; |
|
|
|
export let legendProps = null; |
|
|
|
export let useTooltip = false; |
|
|
|
export let useLegend = false; |
|
|
|
|
|
|
|
export let colors = colorSchemas ? colorSchemas.britecharts : null; |
|
|
|
|
|
|
|
export let gradients = colorGradients ? colorGradients.bluePurple : null; |
|
|
|
export let tooltip = null; //can bind to outside the component and therefore access |
|
|
|
|
|
|
|
let chartElement = null; |
|
|
|
let chartContainer = null; |
|
|
|
let tooltipContainer = null; |
|
|
|
|
|
|
|
let tooltipElement = null; |
|
|
|
let legendContainer = null; |
|
|
|
let legend = null; |
|
|
|
|
|
|
|
let chart = chartTypes.includes(type) ? britecharts[type]() : null; |
|
|
|
export let tooltip = null; //can bind and therefore access |
|
|
|
|
|
|
|
const chartClass = `chart-container-${_id}` |
|
|
|
const legendClass = `legend-container-${_id}` |
|
|
|
|
|
|
|
onMount(() => { |
|
|
|
if (chart) { |
|
|
|
chartContainer = d3.select(chartElement); |
|
|
|
chartContainer = d3.select(`.${chartClass}`); |
|
|
|
bindChartColors(); |
|
|
|
bindChartTooltip(); |
|
|
|
bindChartUIProps(); |
|
|
|
bindChartEvents(); |
|
|
|
chartContainer.datum(data).call(chart); |
|
|
|
bindChartTooltip(); |
|
|
|
bindChartLegend(); |
|
|
|
} else { |
|
|
|
console.error("Britecharts could not be found"); |
|
|
|
} |
|
|
|
@ -58,28 +67,38 @@ |
|
|
|
if (canUseTooltip) { |
|
|
|
tooltip = britecharts.tooltip(); |
|
|
|
|
|
|
|
const validTooltipProps = Object.getOwnPropertyNames(tooltip); |
|
|
|
|
|
|
|
const props = Object.entries(tooltipProps); |
|
|
|
for (let [key, value] of props) { |
|
|
|
if (validTooltipProps.includes(key)) { |
|
|
|
tooltip[key](value); |
|
|
|
} |
|
|
|
} |
|
|
|
bindProps(tooltip, tooltipProps) |
|
|
|
|
|
|
|
tooltipContainer = d3.select(tooltipElement); |
|
|
|
tooltipContainer = d3.select(`.${chartClass} .metadata-group .vertical-marker-container`); |
|
|
|
tooltipContainer.datum([]).call(tooltip); |
|
|
|
// tooltip.show() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function excludeProps(props, propsToExclude) { |
|
|
|
const modifiedProps = {}; |
|
|
|
for (const prop in props) { |
|
|
|
if (!propsToExclude.includes(prop)) { |
|
|
|
modifiedProps[prop] = props[prop]; |
|
|
|
function bindChartLegend() { |
|
|
|
if(useLegend) { |
|
|
|
|
|
|
|
if(!Array.isArray(data)) { |
|
|
|
console.warn("Cannot use legend as data is not an array") |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
let excludeProps = [] |
|
|
|
|
|
|
|
legend = britecharts.legend(); |
|
|
|
|
|
|
|
if(!legendProps || !legendProps.width) { |
|
|
|
excludeProps = ["width"] |
|
|
|
legend.width(chart.width()) |
|
|
|
} |
|
|
|
|
|
|
|
if(legendProps){ |
|
|
|
bindProps(legend, legendProps, excludeProps) |
|
|
|
} |
|
|
|
|
|
|
|
legendContainer = d3.select(`.${legendClass}`) |
|
|
|
legendContainer.datum(data).call(legend) |
|
|
|
} |
|
|
|
return modifiedProps; |
|
|
|
} |
|
|
|
|
|
|
|
function bindChartEvents() { |
|
|
|
@ -92,32 +111,47 @@ |
|
|
|
} |
|
|
|
|
|
|
|
function bindChartUIProps() { |
|
|
|
const props = Object.entries( |
|
|
|
excludeProps($$props, ["data", "colors", "type", "gradients", "on"]) |
|
|
|
); |
|
|
|
const excludeProps = ["data", "colors", "type", "gradients", "on", "useTooltip", "tooltip", "tooltipProps", "legendProps", "useLegend"] |
|
|
|
|
|
|
|
if (!props.includes("width")) { |
|
|
|
if (!$$props.width) { |
|
|
|
chart.width(chartElement.getBoundingClientRect().width); |
|
|
|
} |
|
|
|
|
|
|
|
bindProps(chart, $$props, excludeProps) |
|
|
|
} |
|
|
|
|
|
|
|
function bindProps(element, elProps, excludeArray) { |
|
|
|
const props = excludeArray ? Object.entries(excludeProps(elProps, excludeArray)) : Object.entries(elProps) |
|
|
|
|
|
|
|
const validElementProps = Object.getOwnPropertyNames(element); |
|
|
|
|
|
|
|
for (let [prop, value] of props) { |
|
|
|
if (validChartProps.includes(prop)) { |
|
|
|
if (validElementProps.includes(prop)) { |
|
|
|
chart[prop](value); |
|
|
|
} else { |
|
|
|
console.warn( |
|
|
|
`${type} chart - ${prop} is an unrecognised prop and wont be applied` |
|
|
|
`${type} - ${prop} is an unrecognised chart prop and wont be applied` |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function excludeProps(props, propsToExclude) { |
|
|
|
const modifiedProps = {}; |
|
|
|
for (const prop in props) { |
|
|
|
if (!propsToExclude.includes(prop)) { |
|
|
|
modifiedProps[prop] = props[prop]; |
|
|
|
} |
|
|
|
} |
|
|
|
return modifiedProps; |
|
|
|
} |
|
|
|
|
|
|
|
$: validChartProps = chart ? Object.getOwnPropertyNames(chart) : null; |
|
|
|
$: canUseTooltip = type === "groupedBar" && tooltipProps; |
|
|
|
$: console.log("VALID CHART PROPS", validChartProps); |
|
|
|
$: canUseTooltip = type === "groupedBar" && tooltipProps && useTooltip; |
|
|
|
|
|
|
|
</script> |
|
|
|
|
|
|
|
<div bind:this={chartElement} class="chart-container" /> |
|
|
|
|
|
|
|
{#if canUseTooltip} |
|
|
|
<div bind:this={tooltipElement} class="tooltip-container" /> |
|
|
|
{/if} |
|
|
|
<div bind:this={chartElement} class={chartClass} /> |
|
|
|
{#if useLegend} |
|
|
|
<div class={legendClass}/> |
|
|
|
{/if} |