Merge pull request #525 from Budibase/britechart/donut-demo

Donut Chart for the demo
This commit is contained in:
Conor_Mack 2020-08-10 14:29:52 +01:00 committed by GitHub
commit c816a77d0b
31 changed files with 2703 additions and 40 deletions

View File

@ -61,9 +61,11 @@
"@budibase/client": "^0.1.1",
"@budibase/colorpicker": "^1.0.1",
"@nx-js/compiler-util": "^2.0.0",
"britecharts": "^2.16.0",
"@sentry/browser": "5.19.1",
"@svelteschool/svelte-forms": "^0.7.0",
"codemirror": "^5.51.0",
"d3-selection": "^1.4.1",
"date-fns": "^1.29.0",
"deepmerge": "^4.2.2",
"feather-icons": "^4.21.0",
@ -73,7 +75,7 @@
"mustache": "^4.0.1",
"posthog-js": "^1.3.1",
"safe-buffer": "^5.1.2",
"shortid": "^2.2.8",
"shortid": "^2.2.15",
"string_decoder": "^1.2.0",
"svelte-portal": "^0.1.0",
"svelte-simple-modal": "^0.4.2",

View File

@ -255,7 +255,7 @@ const setCurrentPage = store => pageName => {
* @param {string} componentToAdd - name of the component to add to the application
* @param {string} presetName - name of the component preset if defined
*/
const addChildComponent = store => (componentToAdd, presetName) => {
const addChildComponent = store => (componentToAdd, presetProps = {}) => {
store.update(state => {
function findSlot(component_array) {
for (let i = 0; i < component_array.length; i += 1) {
@ -278,8 +278,6 @@ const addChildComponent = store => (componentToAdd, presetName) => {
const component = getComponentDefinition(state, componentToAdd)
const presetProps = presetName ? component.presets[presetName] : {}
const instanceId = get(backendUiStore).selectedDatabase._id
const instanceName = get_capitalised_name(componentToAdd)

View File

@ -12,22 +12,24 @@
</script>
<input type="checkbox" class="checkbox" id="_checkbox" />
<label for="_checkbox" class:checked on:click={handleChange}>
<div class="tick_mark" />
</label>
<div on:click={handleChange}>
<div class="check-div" class:checked>
<div class="tick_mark" />
</div>
</div>
<style>
.checkbox {
display: none;
}
label {
.check-div {
position: relative;
width: 20px;
height: 20px;
/* background-color: #5e17e9; */
background-color: var(--grey-2);
transform: translateY(-50%);
/* transform: translateY(-50%); */
cursor: pointer;
transition: 0.2s ease transform, 0.2s ease background-color,
0.2s ease box-shadow;
@ -36,7 +38,7 @@
border-radius: 4px;
}
label:before {
.check-div:before {
content: "";
position: absolute;
top: 50%;
@ -51,7 +53,7 @@
border-radius: 2px;
}
label:active {
.check-div:active {
transform: translateY(-50%) scale(0.9);
}

View File

@ -143,6 +143,7 @@
margin-top: 16px;
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
}
.instance-name {

View File

@ -32,7 +32,7 @@
let selectedCategory = categories[0]
const onComponentChosen = component => {
store.addChildComponent(component._component)
store.addChildComponent(component._component, component.presetProps)
toggleTab("Navigate")

View File

@ -30,6 +30,7 @@
</script>
<div class="root">
{#each screens as screen}
<div
class="budibase__nav-item screen-header-row"

View File

@ -24,7 +24,7 @@
{ value: "active", text: "Active" },
]
$: propertyGroupNames = Object.keys(panelDefinition)
$: propertyGroupNames = panelDefinition ? Object.keys(panelDefinition) : []
</script>
<div class="design-view-container">

View File

@ -9,14 +9,15 @@
export let onChange = () => {}
function handleChange(key, v) {
if (v.target) {
let val = props.valueKey ? v.target[props.valueKey] : v.target.value
onChange(key, val)
} else if (v.detail) {
onChange(key, v.detail)
} else {
onChange(key, v)
let innerVal = v
if (typeof v === "object") {
if ("detail" in v) {
innerVal = v.detail
} else if ("target" in v) {
innerVal = props.valueKey ? v.target[props.valueKey] : v.target.value
}
}
onChange(key, innerVal)
}
const safeValue = () => {
@ -47,6 +48,7 @@
.property-control {
display: flex;
flex-flow: row;
width: 260px;
margin: 8px 0px;
align-items: center;
}
@ -56,6 +58,7 @@
align-items: center;
font-size: 12px;
font-weight: 400;
width: 100px;
text-align: left;
color: var(--ink);
margin-right: auto;

View File

@ -4,6 +4,11 @@ import Checkbox from "../common/Checkbox.svelte"
import ModelSelect from "components/userInterface/ModelSelect.svelte"
import { all } from "./propertyCategories.js"
/*
{ label: "N/A ", value: "N/A" },
{ label: "Flex", value: "flex" },
{ label: "Inline Flex", value: "inline-flex" },
*/
export default {
categories: [
@ -425,37 +430,132 @@ export default {
],
},
{
name: "Chart",
_component: "@budibase/standard-components/datachart",
description: "Shiny chart",
icon: "ri-bar-chart-line",
name: "Donut Chart",
_component: "@budibase/standard-components/donut",
description: "Donut chart",
icon: "ri-pie-chart-fill",
properties: {
design: { ...all },
settings: [
{ label: "Table", key: "model", control: ModelSelect },
{
label: "Chart Type",
key: "type",
label: "Table",
key: "model",
control: ModelSelect,
},
{
label: "Animate Chart",
key: "isAnimated",
valueKey: "checked",
control: Checkbox,
},
{
label: "Hover Highlight",
key: "hasHoverAnimation",
valueKey: "checked",
control: Checkbox,
},
{
label: "Keep Last Hover",
key: "hasLastHoverSliceHighlighted",
valueKey: "checked",
control: Checkbox,
},
{
label: "Colors",
key: "color",
control: OptionSelect,
options: [
"column2d",
"column3d",
"line",
"area2d",
"bar2d",
"bar3d",
"pie2d",
"pie3d",
"doughnut2d",
"doughnut3d",
"pareto2d",
"pareto3d",
"britecharts",
"blueGreen",
"green",
"grey",
"orange",
"pink",
"purple",
"red",
"teal",
"yellow",
],
},
{
label: "Name Field",
key: "nameKey",
control: Input,
},
{
label: "Value Field",
key: "valueKey",
control: Input,
},
{
label: "External Radius",
key: "externalRadius",
control: Input,
},
{
label: "Internal Radius",
key: "internalRadius",
control: Input,
},
{
label: "Radius Offset",
key: "radiusHoverOffset ",
control: Input,
},
{
label: "Show Legend",
key: "useLegend ",
valueKey: "checked",
control: Checkbox,
},
{
label: "Horizontal Legend",
key: "horizontalLegend",
valueKey: "checked",
control: Checkbox,
},
{
label: "Legend Width",
key: "legendWidth",
control: Input,
},
{
label: "Legend Height",
key: "legendHeight",
control: Input,
},
],
},
children: [],
},
{
name: "Data List",
_component: "@budibase/standard-components/datalist",
description: "Shiny list",
icon: "ri-file-list-fill",
properties: {
design: { ...all },
settings: [{ label: "Table", key: "model", control: ModelSelect }],
},
children: [],
},
{
name: "List",
_component: "@budibase/standard-components/list",
description: "Renders all children once per record, of a given table",
icon: "ri-file-list-fill",
properties: {
design: { ...all },
settings: [{ label: "Table", key: "model", control: ModelSelect }],
},
children: [
{
_component: "@budibase/standard-components/heading",
name: "Headline",
description: "A component for displaying heading text",
icon: "ri-heading",
},
],
},
// {
// name: "Data List",
// _component: "@budibase/standard-components/datalist",

View File

@ -275,6 +275,267 @@
"model": "models"
}
},
"donut": {
"description": "Donut Chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "number",
"width": "number",
"hasFixedHighlightedSlice": "bool",
"hasLastHoverSliceHighlighted": "bool",
"hasHoverAnimation": "bool",
"numberFormat": "string",
"nameKey": "string",
"valueKey": "string",
"isAnimated": "bool",
"externalRadius": "number",
"internalRadius": "number",
"radiusHoverOffset": "number",
"percentageFormat": "string",
"useLegend": "bool",
"legendWidth": "number",
"legendHeight": "number"
}
},
"sparkline": {
"description": "Sparkline Chart",
"data": true,
"props": {
"model": "string",
"areaGradient": "string",
"height": "number",
"width": "number",
"dateLabel": "string",
"duration": "string",
"isAnimated": "bool",
"lineGradient": "string",
"titleText": "string",
"valueLabel": "string"
}
},
"stackedbar": {
"description": "Stacked Bar Chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "number",
"width": "number",
"margin": "string",
"aspectRatio": "string",
"betweenBarsPadding": "number",
"grid": "string",
"hasPercentage": "bool",
"hasReversedStacks": "bool",
"isAnimated": "bool",
"isHorizontal": "bool",
"locale": "string",
"nameLabel": "string",
"percentageAxisToMaxRatio": "number",
"stackLabel": "string",
"valueLabel": "string",
"valueLabelFormat": "string",
"xTicks": "number",
"yTicks": "number",
"yAxisLabel": "string",
"yAxisLabelOffset": "number",
"useLegend": "bool"
}
},
"stackarea": {
"description": "Step Chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "number",
"width": "number",
"margin": "string",
"xAxisLabel": "string",
"xAxisLabelOffset": "string",
"yAxisLabel": "string",
"yAxisLabelOffset": "string",
"areaCurve": "number",
"areaOpacity": "number",
"aspectRatio": "number",
"dateLabel": "string",
"grid": "string",
"isAnimated": "bool",
"keyLabel": "string",
"locale": "string",
"tooltipThreshold": "number",
"topicsOrder": "string",
"valueLabel": "string",
"xAxisCustomFormat": "string",
"xAxisFormat": "string",
"xAxisScale": "string",
"xAxisValueType":"string",
"yTicks": "number",
"xTicks": "number",
"yAxisBaseline": "string",
"useLegend": "bool"
}
},
"step": {
"description": "Step Chart",
"data": true,
"props": {
"model": "string",
"height": "number",
"width": "number",
"margin": "string",
"xAxisLabel": "string",
"xAxisLabelOffset": "string",
"yAxisLabel": "string",
"yAxisLabelOffset": "string",
"yTicks": "string"
}
},
"scatterplot": {
"description": "Scatterplot Chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "number",
"width": "number",
"aspectRatio": "string",
"circleOpacity": "string",
"grid": "string",
"hasCrossHairs": "bool",
"isAnimated": "bool",
"maxCircleArea": "number",
"xAxisLabel": "string",
"xAxisLabelOffset": "string",
"xTicks": "string",
"yAxisFormat": "string",
"yAxisLabel": "string",
"yAxisLabelOffset": "string",
"yTicks": "string"
}
},
"bar": {
"description": "Bar Chart",
"data": true,
"props": {
"model": "string",
"betweenBarsPadding": "number",
"gradient": "string",
"color": "string",
"enableLabels": "bool",
"hasSingleBarHighlight": "bool",
"height": "number",
"width": "number",
"isAnimated": "bool",
"isHorizontal": "bool",
"xAxisLabelOffset": "number",
"yAxisLabelOffset": "number",
"labelNumberFormat": "number",
"labelSize": "number",
"locale": "string",
"nameLabel": "string",
"valueLabel": "string",
"numberLabel": "string",
"xAxisLabel": "string",
"yAxisLabel": "string",
"useLegend": "bool",
"xTicks": "number",
"yTicks": "number"
}
},
"line": {
"description": "Line Chart",
"data": true,
"props": {
"model": "string",
"width": "number",
"height": "number",
"axisTimeCombinations": "string",
"color": "string",
"grid": "string",
"aspectRatio": "number",
"dateLabel": "string",
"isAnimated": "bool",
"lineCurve": "string",
"locale": "string",
"numberFormat": "string",
"shouldShowAllDataPoints": "bool",
"topicLabel": "string",
"valueLabel": "string",
"xAxisValueType": "string",
"xAxisScale": "string",
"xAxisFormat": "string",
"xAxisCustomFormat": "string",
"xAxisLabel": "string"
}
},
"brush":{
"description": "brush chart",
"data": true,
"props": {
"model": "string",
"gradient": "string",
"height": "number",
"width": "number",
"margin": "string",
"dateRange": "string",
"locale": "string",
"roundingTimeInterval": "string",
"xAxisFormat": "string",
"xTicks": "number",
"xAxisCustomFormat": "string"
}
},
"heatmap": {
"description": "Groupedbar chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "number",
"width": "number",
"useLegend": "bool",
"yAxisLabel": "string",
"boxSize": "number"
}
},
"groupedbar": {
"description": "Groupedbar chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"height": "string",
"width": "string",
"margin": "string",
"aspectRatio": "number",
"grid":"string",
"groupLabel": "string",
"isAnimated": "bool",
"isHorizontal": "bool",
"nameLabel": "string",
"valueLabel":"string",
"yTicks": "string",
"yTickTextOffset": "string",
"useLegend": "bool"
}
},
"bullet": {
"description": "Bullet chart",
"data": true,
"props": {
"model": "string",
"color": "string",
"customSubtitle": "string",
"customTitle": "string",
"numberFormat": "string",
"paddingBetweenAxisAndChart": "number",
"height": "number",
"width": "number"
}
},
"datachart": {
"description": "shiny chart",
"data": true,

View File

@ -38,6 +38,8 @@
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": {
"@beyonk/svelte-googlemaps": "^2.2.0",
"britecharts": "^2.16.0",
"d3-selection": "^1.4.1",
"fast-sort": "^2.2.0",
"fusioncharts": "^3.15.1-sr.1",
"svelte-fusioncharts": "^1.0.0"

View File

@ -0,0 +1,218 @@
<script>
import { getColorSchema, getChartGradient } from "./Chart.svelte"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
/*
ISSUES:
- x and y axis label set and appear in the dom but do not display next to the axis
- x and y axis label offset - does effect position of labels but does not render text (see above)
- x tick label overlaps bar, seems to be no apu method to change this? Could do it by querying for it in the dom
specifically and doing this: <tspan x="-10" dy="0.32em">4.0</tspan>
*/
let tooltip
const _id = shortid.generate()
const chart = britecharts.bar()
const chartClass = `bar-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
let tooltipContainer = null
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (datapoint, colorMapping, x, y) =>
tooltip.update(datapoint, colorMapping, x, y)
export let customMouseOut = () => tooltip.hide()
export let customClick = null
export let data = []
export let xAxisLabel = ""
export let yAxisLabel = ""
export let betweenBarsPadding = 0.1 //takes decimal values 0.1, 0.5 etc
export let gradient = null
export let color = "britecharts"
export let enableLabels = true
export let hasPercentage = null
export let hasSingleBarHighlight = true
export let highlightBarFunction = null
export let height = 200
export let width = 300
export let labelsMargin = null
export let isAnimated = true
export let isHorizontal = true
export let xAxisLabelOffset = null
export let yAxisLabelOffset = null
export let labelsNumberFormat = null
export let locale = null
export let valueLabel = null
export let nameLabel = null
export let numberFormat = null
export let labelsSize = null
export let xTicks = null
export let yTicks = null
export let percentageAxisToMaxRatio = null
export let useLegend = true
export let _bb
export let model
let store = _bb.store
onMount(async () => {
if (chartElement) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
chart.numberFormat(".1f")
chart.labelsNumberFormat(".1f")
if (color) {
chart.colorSchema(colorSchema)
}
if (gradient) {
chart.chartGradient(chartGradient)
}
if (xAxisLabel) {
chart.xAxisLabel(xAxisLabel)
}
if (yAxisLabel) {
chart.yAxisLabel(yAxisLabel)
}
if (betweenBarsPadding) {
chart.betweenBarsPadding(Number(betweenBarsPadding))
}
if (enableLabels) {
chart.enableLabels(enableLabels)
}
if (hasPercentage) {
chart.hasPercentage(hasPercentage)
}
if (hasSingleBarHighlight) {
chart.hasSingleBarHighlight(hasSingleBarHighlight)
}
if (labelsMargin) {
chart.labelsMargin(labelsMargin)
}
if (height) {
chart.height(height)
}
if (highlightBarFunction) {
chart.highlightBarFunction(highlightBarFunction)
}
if (width) {
chart.width(width)
}
if (isAnimated) {
chart.isAnimated(isAnimated)
}
if (isHorizontal) {
chart.isHorizontal(isHorizontal)
}
if (yAxisLabelOffset) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (xAxisLabelOffset) {
chart.xAxisLabelOffset(Number(xAxisLabelOffset))
}
if (labelsNumberFormat) {
chart.labelsNumberFormat(labelsNumberFormat)
}
if (valueLabel) {
chart.valueLabel(valueLabel)
}
if (locale) {
chart.locale(locale)
}
if (nameLabel) {
chart.nameLabel(nameLabel)
}
if (numberFormat) {
chart.numberFormat(numberFormat)
}
if (labelsSize) {
chart.labelsSize(labelsSize)
}
if (xTicks) {
chart.xTicks(xTicks)
}
if (yTicks) {
chart.yTicks(yTicks)
}
if (percentageAxisToMaxRatio) {
chart.percentageAxisToMaxRatio(percentageAxisToMaxRatio)
}
chartContainer.datum(_data).call(chart)
}
function bindChartEvents() {
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
if (customClick) {
chart.on("customClick", customClick)
}
}
function bindChartTooltip() {
tooltip = britecharts.miniTooltip()
tooltip.numberFormat(".0f")
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
$: chartGradient = getChartGradient(gradient)
</script>
<!-- SVG Test
<svg viewBox="6 -8 200 22">
<text x="5" y="10" class="text-svg">Hello World</text>
</svg>-->
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}
<style>
.text-svg {
font: italic 15px serif;
fill: red;
}
</style>

View File

@ -0,0 +1,118 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
/*
ISSUES
- Chart gradient doesn't seem to do anything
*/
export let _bb
export let model
let store = _bb.store
const _id = shortid.generate()
const chart = britecharts.brush()
const chartClass = `brush-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let customBrushEnd = null
export let customBrushStart = null
export let data = []
export let gradient = null
export let height = 200
export let width = 200
export let margin = { top: 0, right: 0, bottom: 0, left: 0 }
export let dateRange = null
export let locale = null
export let roundingTimeInterval = null
export let xAxisFormat = null
export let xTicks = null
export let xAxisCustomFormat = null
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(gradient)) {
chart.gradient(chartGradient)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.margin(margin)
}
if (notNull(dateRange)) {
chart.dateRange(dateRange)
}
if (notNull(locale)) {
chart.locale(locale)
}
if (notNull(roundingTimeInterval)) {
chart.roundingTimeInterval(roundingTimeInterval)
}
if (notNull(xAxisFormat)) {
chart.xAxisFormat(xAxisFormat)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(xAxisCustomFormat)) {
chart.xAxisCustomFormat(xAxisCustomFormat)
}
}
function bindChartEvents() {
if (customBrushEnd) {
chart.on("customBrushEnd", customBrushEnd)
}
if (customBrushStart) {
chart.on("customBrushStart", customBrushStart)
}
}
$: _data = model ? $store[model] : data
$: chartGradient = getChartGradient(gradient)
$: console.log(chartGradient)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -0,0 +1,103 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.bullet()
const chartClass = `bullet-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let data = []
export let aspectRatio = null
export let color = "britecharts"
export let customSubtitle = null
export let customTitle = null
export let numberFormat = null
export let paddingBetweenAxisAndChart = null
export let startMaxRangeOpacity = null
export let ticks = null
export let isReverse = false
export let height = 200
export let width = 200
export let margin = { top: 0, right: 0, bottom: 0, left: 0 }
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(customSubtitle)) {
chart.customSubtitle(customSubtitle)
}
if (notNull(customTitle)) {
chart.customTitle(customTitle)
}
if (notNull(numberFormat)) {
chart.numberFormat(numberFormat)
}
if (notNull(paddingBetweenAxisAndChart)) {
chart.paddingBetweenAxisAndChart(paddingBetweenAxisAndChart)
}
if (notNull(startMaxRangeOpacity)) {
chart.startMaxRangeOpacity(startMaxRangeOpacity)
}
if (notNull(ticks)) {
chart.ticks(ticks)
}
if (notNull(isReverse)) {
chart.isReverse(isReverse)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -0,0 +1,169 @@
<script context="module">
//expose chart types for use or reference outside compnent
export const chartTypes = britecharts ? Object.keys(britecharts) : null
//expose chart color schemas for use or reference outside compnent
export const colorSchemas = britecharts
? britecharts.colors.colorSchemas
: null
//export color gradients for use or reference outside the component
export const colorGradients = britecharts
? britecharts.colors.colorGradients
: null
export const getColorSchema = color =>
color ? colorSchemas[color] : colorSchemas["britecharts"]
export const getChartGradient = gradient =>
gradient ? colorGradients[gradient] : null
</script>
<script>
import { beforeUpdate } from "svelte"
import britecharts from "britecharts"
import { select } from "d3-selection"
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 tooltip = null //can bind to outside the component and therefore access
let chartElement = null
let chartContainer = null
let tooltipContainer = null
let legendContainer = null
let legend = null
let chart = chartTypes.includes(type) ? britecharts[type]() : null
const chartClass = `chart-container-${_id}`
const legendClass = `legend-container-${_id}`
onMount(() => {
if (chart) {
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
bindChartTooltip()
bindChartLegend()
} else {
console.error("Britecharts could not be found")
}
})
function bindChartTooltip() {
if (useTooltip) {
tooltip = britecharts.miniTooltip()
bindProps(tooltip, tooltipProps)
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
}
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 = select(`.${legendClass}`)
legendContainer.datum(data).call(legend)
}
}
function bindChartEvents() {
if ($$props.on) {
const events = Object.entries($$props.on)
for (let [type, fn] of events) {
if (fn) {
chart.on(type, fn)
}
}
}
}
function bindChartUIProps() {
const excludeProps = [
"data",
"type",
"on",
"useTooltip",
"tooltip",
"tooltipProps",
"legendProps",
"useLegend",
]
if (!$$props.width) {
chart.width(chartElement.getBoundingClientRect().width)
}
bindProps(chart, $$props, excludeProps)
}
function bindProps(element, elProps, excludeArray) {
if (elProps) {
const props = excludeArray
? Object.entries(excludeProps(elProps, excludeArray))
: Object.entries(elProps)
const validElementProps = Object.getOwnPropertyNames(element)
for (let [prop, value] of props) {
if (validElementProps.includes(prop)) {
if (!!value) {
chart[prop](value)
}
} else {
console.warn(
`${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
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,224 @@
<script>
import { getColorSchema, notNull } from "./utils.js"
import Legend from "./Legend.svelte"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
const chart = britecharts.donut()
const chartClass = `donut-container-${_id}`
const legendClass = `legend-container-${_id}`
let legendChart
let chartElement = null
let chartContainer = null
let chartSvgWidth = 0
let chartSvg = null
export let _bb
export let model
let store = _bb.store
export let customMouseMove = null
export let customClick = null
export let orderingFunction = null
let data = []
export let color = "britecharts"
export let height = 200
export let width = 200
export let margin = null
export let centeredTextFunction = null
export let externalRadius = 25
export let percentageFormat = null
export let hasFixedHighlightedSlice = false
export let hasLastHoverSliceHighlighted = false
export let hasHoverAnimation = true
export let highlightSliceById = null
export let numberFormat = null
export let internalRadius = 25
export let isAnimated = true
export let radiusHoverOffset = 0
export let nameKey = null
export let valueKey = null
// export let useLegend = true
export let horizontalLegend = false
export let legendWidth = null
export let legendHeight = null
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
data = checkAndReformatData($store[model])
if (data.length === 0) {
console.error(
"Donut - please provide a valid name and value field for the chart"
)
}
}
chart.emptyDataConfig({
showEmptySlice: true,
emptySliceColor: "#F0F0F0",
})
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
}
})
function checkAndReformatData(data) {
let _data = [...data]
if (valueKey) {
_data = reformatDataKey(_data, valueKey, "quantity")
}
if (nameKey) {
_data = reformatDataKey(_data, nameKey, "name")
}
return _data.every(d => d.quantity) && _data.every(d => d.name) ? _data : []
}
function reformatDataKey(data = [], dataKey = null, formatKey = null) {
let ignoreList = ["_id", "_rev", "id"]
if (dataKey && data.every(d => d[dataKey])) {
return data.map(d => {
let clonedRecord = { ...d }
if (clonedRecord[formatKey]) {
delete clonedRecord[formatKey]
}
let value = clonedRecord[dataKey]
if (!ignoreList.includes(dataKey)) {
delete clonedRecord[dataKey]
}
clonedRecord[formatKey] = value
return clonedRecord
})
} else {
return data
}
}
function bindChartUIProps() {
chart.percentageFormat(".0f")
if (notNull(color)) {
chart.colorSchema(getColorSchema(color))
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.margin(margin)
}
if (notNull(centeredTextFunction)) {
chart.centeredTextFunction(centeredTextFunction)
}
if (notNull(externalRadius)) {
chart.externalRadius(externalRadius)
}
if (notNull(percentageFormat)) {
chart.percentageFormat(percentageFormat)
}
if (notNull(hasFixedHighlightedSlice)) {
chart.hasFixedHighlightedSlice(hasFixedHighlightedSlice)
}
if (notNull(hasLastHoverSliceHighlighted)) {
chart.hasLastHoverSliceHighlighted(hasLastHoverSliceHighlighted)
}
if (notNull(hasHoverAnimation)) {
chart.hasHoverAnimation(hasHoverAnimation)
}
if (notNull(highlightSliceById)) {
chart.highlightSliceById(highlightSliceById)
}
if (notNull(numberFormat)) {
chart.numberFormat(numberFormat)
}
if (notNull(internalRadius)) {
chart.internalRadius(internalRadius)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(radiusHoverOffset)) {
chart.radiusHoverOffset(radiusHoverOffset)
}
if (notNull(orderingFunction)) {
chart.orderingFunction(orderingFunction)
}
chartContainer.datum(data).call(chart)
chartSvg = document.querySelector(`.${chartClass} .britechart`)
}
function bindChartEvents() {
if (customClick) {
chart.on("customClick", customClick)
}
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (legendChart) {
chart.on("customMouseOut", function() {
legendChart.clearHighlight()
})
chart.on("customMouseOver", function(data) {
legendChart.highlight(data.data.id)
})
}
}
$: if (!width && chartSvg) {
width = chartSvg.clientWidth
chart.width(width)
chartContainer.datum(data).call(chart)
}
$: colorSchema = getColorSchema(color)
</script>
<div>
<div bind:this={chartElement} class={chartClass} />
{#if data.length > 0}
<Legend
bind:legend={legendChart}
{colorSchema}
useLegend
isHorizontal={horizontalLegend}
width={legendWidth || width}
height={legendHeight}
{chartClass}
{data} />
{/if}
</div>

View File

@ -0,0 +1,163 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
/*
ISSUES
- Renders but seems to be a problem with tooltip hover
*/
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.groupedBar()
const chartClass = `groupedbar-container-${_id}`
const legendClass = `legend-container-${_id}`
let tooltip
let tooltipContainer
let chartElement = null
let chartContainer = null
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (dataPoint, topicColorMap, dataPointXPosition) =>
tooltip.update(dataPoint, topicColorMap, dataPointXPosition)
export let customMouseOut = () => tooltip.hide()
export let customClick = null
export let data = []
export let color = "britecharts"
export let height = 200
export let width = 200
export let margin = { top: 0, right: 0, bottom: 0, left: 0 }
export let aspectRatio = null
export let grid = null
export let groupLabel = null
export let isAnimated = null
export let isHorizontal = null
export let nameLabel = null
export let valueLabel = null
export let valueLabelFormat = null
export let xTicks = null
export let yAxisLabel = null
export let yAxisLabelOffset = null
export let yTicks = null
export let yTickTextOffset = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
// bindChartEvents()
chartContainer.datum(data).call(chart)
// bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(groupLabel)) {
chart.groupLabel(groupLabel)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(isHorizontal)) {
chart.isHorizontal(isHorizontal)
}
if (notNull(nameLabel)) {
chart.nameLabel(nameLabel)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
if (notNull(valueLabelFormat)) {
chart.valueLabelFormat(valueLabelFormat)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
if (notNull(yTickTextOffset)) {
chart.yTickTextOffset(yTickTextOffset)
}
}
function bindChartTooltip() {
tooltip = britecharts.miniTooltip()
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
function bindChartEvents() {
if (customClick) {
chart.on("customClick", customClick)
}
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,83 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.heatmap()
const chartClass = `heatmap-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let data = []
export let color = "britecharts"
export let height = 200
export let width = 200
export let margin = { top: 0, right: 0, bottom: 0, left: 0 }
export let useLegend = true
export let yAxisLabels = null
export let boxSize = null
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(data).call(chart)
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(boxSize)) {
chart.boxSize(boxSize)
}
if (notNull(yAxisLabels)) {
chart.yAxisLabels(yAxisLabels)
}
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,82 @@
<script>
import britecharts from "britecharts"
import { notNull } from "./utils"
import { select } from "d3-selection"
import { onMount } from "svelte"
export let useLegend = true
export let data = []
export let width = null
export let height = null
export let colorSchema = null
export let highlight = null
export let highlightByEntryId = null
export let isHorizontal = false
export let margin = null
export let marginRatio = null
export let markerSize = null
export let numberFormat = null
export let unit = null
export let legend = britecharts.legend() //exported it can be bound to
let legendContainer = null
let legendElement = null
$: {
if (legendElement) {
legendContainer = select(legendElement)
legend.numberFormat(".0f")
if (width) {
legend.width(width)
}
if (notNull(height)) {
legend.height(height)
}
if (notNull(colorSchema)) {
legend.colorSchema(colorSchema)
}
if (notNull(highlight)) {
legend.highlight(highlight)
}
if (notNull(highlightByEntryId)) {
legend.highlightByEntryId(highlightByEntryId)
}
if (notNull(isHorizontal)) {
legend.isHorizontal(isHorizontal)
}
if (notNull(margin)) {
legend.margin(margin)
}
if (notNull(marginRatio)) {
legend.marginRatio(marginRatio)
}
if (notNull(markerSize)) {
legend.markerSize(markerSize)
}
if (notNull(numberFormat)) {
legend.numberFormat(numberFormat)
}
if (notNull(unit)) {
legend.unit(unit)
}
legendContainer.datum(data).call(legend)
}
}
const legendClass = `legend-container`
</script>
{#if useLegend}
<div bind:this={legendElement} class={legendClass} />
{/if}

View File

@ -0,0 +1,209 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.line()
const chartClass = `line-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement
let chartContainer
let tooltip
let tooltipContainer
export let customMouseHover = null
export let customMouseMove = null
export let customMouseOut = null
export let customDataEntryClick = null
export let customTouchMove = null
export let data = []
export let color = "britecharts"
export let axisTimeCombinations = ""
export let grid = "horizontal"
export let aspectRatio = 0.5
export let dateLabel = "date"
export let width = null
export let height = null
export let isAnimated = true
export let lineCurve = "linear" //see api for possible opts
export let locale = "en-GB"
export let numberFormat = ""
export let shouldShowAllDataPoints = true
export let topicLabel = null
export let valueLabel = null
export let xAxisLabel = ""
export let xAxisValueType = "date"
export let xAxisScale = "linear"
export let xAxisFormat = "day-month"
export let xAxisCustomFormat = "%H"
export let yAxisLabel = null
export let useLegend = true
export let yAxisLabelPadding = null
export let lines = null //not handled by setting prop
export let tooltipThreshold = null
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(axisTimeCombinations)) {
chart.axisTimeCombinations(axisTimeCombinations)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(dateLabel)) {
chart.dateLabel(dateLabel)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(lineCurve)) {
chart.lineCurve(lineCurve)
}
if (notNull(locale)) {
chart.locale(locale)
}
if (notNull(numberFormat)) {
chart.numberFormat(numberFormat)
}
if (notNull(shouldShowAllDataPoints)) {
chart.shouldShowAllDataPoints(shouldShowAllDataPoints)
}
if (notNull(topicLabel)) {
chart.topicLabel(topicLabel)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
if (notNull(xAxisLabel)) {
chart.xAxisLabel(xAxisLabel)
}
if (notNull(xAxisValueType)) {
chart.xAxisValueType(xAxisValueType)
}
if (notNull(xAxisScale)) {
chart.xAxisScale(xAxisScale)
}
if (notNull(xAxisFormat)) {
chart.xAxisFormat(xAxisFormat)
}
if (notNull(xAxisCustomFormat)) {
chart.xAxisCustomFormat(xAxisCustomFormat)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelPadding)) {
chart.yAxisLabelPadding(yAxisLabelPadding)
}
}
function bindChartEvents() {
if (customMouseHover) {
chart.on("customMouseHover", customMouseHover)
}
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customDataEntryClick) {
chart.on("customDataEntryClick", customDataEntryClick)
}
if (customTouchMove) {
chart.on("customTouchMove", customTouchMove)
}
}
function bindChartTooltip() {
tooltip = britecharts.miniTooltip()
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}
<!--
isAnimated={true}
aspectRatio={0.5}
grid='horizontal'
tooltipThreshold={600}
width={600}
dateLabel='fullDate'
{type}
{data}
{colorSchema}
{axisTimeCombinations}
{lineCurve}
{numberFormat}
{height}
{topicLabel}
{shouldShowAllDataPoints}
{xAxisLabel}
{valueLabel}
{xAxisValueType}
{xAxisScale}
{xAxisCustomFormat}
-->

View File

@ -0,0 +1,187 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.scatterPlot()
const chartClass = `scatterplot-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
let tooltip
let tooltipContainer
export let customClick = null
export let customMouseOut = () => tooltip.hide()
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (
dataPoint,
colorMapping,
xPosition,
yPosition = null
) => tooltip.update(dataPoint, colorMapping, xPosition, (yPosition = null))
export let data = []
export let color = "britecharts"
export let height = null
export let width = null
export let margin = null
export let aspectRatio = null
export let circleOpacity = null
export let grid = null
export let hasCrossHairs = null
export let hasHollowCircles = null
export let hasTrendline = null
export let highlightTextLegendOffset = null
export let isAnimated = null
export let maxCircleArea = null
export let xAxisFormat = null
export let xAxisLabel = null
export let xAxisLabelOffset = null
export let xTicks = null
export let yAxisFormat = null
export let yAxisLabel = null
export let yAxisLabelOffset = null
export let yTicks = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.width(margin)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(circleOpacity)) {
chart.circleOpacity(circleOpacity)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(hasCrossHairs)) {
chart.hasCrossHairs(hasCrossHairs)
}
if (notNull(hasHollowCircles)) {
chart.hasHollowCircles(hasHollowCircles)
}
if (notNull(hasTrendline)) {
chart.hasTrendline(hasTrendline)
}
if (notNull(highlightTextLegendOffset)) {
chart.highlightTextLegendOffset(highlightTextLegendOffset)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(maxCircleArea)) {
chart.maxCircleArea(maxCircleArea)
}
if (notNull(xAxisFormat)) {
chart.xAxisFormat(xAxisFormat)
}
if (notNull(xAxisLabel)) {
chart.xAxisLabel(xAxisLabel)
}
if (notNull(xAxisLabelOffset)) {
chart.xAxisLabelOffset(xAxisLabelOffset)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(yAxisFormat)) {
chart.yAxisFormat(yAxisFormat)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
}
function bindChartEvents() {
if (customClick) {
chart.on("customClick", customClick)
}
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
}
function bindChartTooltip() {
//TODO: May be more apt to use tooltip() here. Currently erroring however
tooltip = britecharts.miniTooltip()
tooltipContainer = select(`.${chartClass} .metadata-group`)
// tooltip
// .title("Temperature")
// .valueLabel("y")
// .nameLabel("x")
// .numberFormat("$")
tooltipContainer.datum([]).call(tooltip)
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,103 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.sparkline()
const chartClass = `sparkline-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let data = []
export let areaGradient = null
export let height = null
export let width = null
export let dateLabel = null
export let duration = null
export let isAnimated = null
export let lineGradient = null
export let titleText = null
export let titleTextStyle = null
export let valueLabel = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(areaGradient)) {
chart.areaGradient(aGradient)
}
if (notNull(lineGradient)) {
chart.lineGradient(lGradient)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(dateLabel)) {
chart.dateLabel(dateLabel)
}
if (notNull(duration)) {
chart.duration(duration)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(titleText)) {
chart.titleText(titleText)
}
if (notNull(titleTextStyle)) {
chart.titleTextStyle(titleTextStyle)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
}
$: _data = model ? $store[model] : data
$: aGradient = getChartGradient(areaGradient)
$: lGradient = getChartGradient(lineGradient)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,181 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.stackedArea()
const chartClass = `stackedarea-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (
dataPoint,
colorMapping,
xPosition,
yPosition = null
) => tooltip.update(dataPoint, colorMapping, xPosition, (yPosition = null))
export let customMouseOut = () => tooltip.hide()
export let data = []
export let color = "britecharts"
export let height = null
export let width = null
export let margin = null
export let areaCurve = null
export let areaOpacity = null
export let aspectRatio = null
export let dateLabel = null
export let grid = null
export let isAnimated = null
export let keyLabel = null
export let locale = null
export let tooltipThreshold = null
export let topicsOrder = null
export let valueLabel = null
export let xAxisCustomFormat = null
export let xAxisFormat = null
export let xAxisScale = null
export let xAxisValueType = null
export let xTicks = null
export let yAxisBaseline = null
export let yAxisLabel = null
export let yAxisLabelOffset = null
export let yTicks = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.margin(margin)
}
if (notNull(areaCurve)) {
chart.areaCurve(areaCurve)
}
if (notNull(areaOpacity)) {
chart.areaOpacity(areaOpacity)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(dateLabel)) {
chart.dateLabel(dateLabel)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(keyLabel)) {
chart.keyLabel(keyLabel)
}
if (notNull(locale)) {
chart.locale(locale)
}
if (notNull(tooltipThreshold)) {
chart.tooltipThreshold(tooltipThreshold)
}
if (notNull(topicsOrder)) {
chart.topicsOrder(topicsOrder)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
if (notNull(xAxisCustomFormat)) {
chart.xAxisCustomFormat(xAxisCustomFormat)
}
if (notNull(xAxisFormat)) {
chart.xAxisFormat(xAxisFormat)
}
if (notNull(xAxisScale)) {
chart.xAxisScale(xAxisScale)
}
if (notNull(xAxisValueType)) {
chart.xAxisValueType(xAxisValueType)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(yAxisBaseline)) {
chart.yAxisBaseline(yAxisBaseline)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
}
function bindChartEvents() {
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,176 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
const chart = britecharts.stackedBar()
const chartClass = `stackedbar-container-${_id}`
const legendClass = `legend-container-${_id}`
export let _bb
export let model
let store = _bb.store
let chartElement = null
let chartContainer = null
let tooltip
let tooltipContainer
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (dataPoint, colorMapping, xPosition) =>
tooltip.update(dataPoint, colorMapping, xPosition)
export let customMouseOut = () => tooltip.hide()
export let data = []
export let color = "britecharts"
export let height = null
export let width = null
export let margin = null
export let aspectRatio = null
export let betweenBarsPadding = null
export let grid = null
export let hasPercentage = null
export let hasReversedStacks = null
export let isAnimated = null
export let isHorizontal = null
export let locale = null
export let nameLabel = null
export let percentageAxisToMaxRatio = null
export let stackLabel = null
export let valueLabel = null
export let valueLabelFormat = null
export let xTicks = null
export let yTicks = null
export let yAxisLabel = null
export let yAxisLabelOffset = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
// bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
//UI PROPS
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.margin(margin)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
if (notNull(betweenBarsPadding)) {
chart.betweenBarsPadding(betweenBarsPadding)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(hasPercentage)) {
chart.hasPercentage(hasPercentage)
}
if (notNull(hasReversedStacks)) {
chart.hasReversedStacks(hasReversedStacks)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(isHorizontal)) {
chart.isHorizontal(isHorizontal)
}
if (notNull(locale)) {
chart.locale(locale)
}
if (notNull(nameLabel)) {
chart.nameLabel(nameLabel)
}
if (notNull(percentageAxisToMaxRatio)) {
chart.percentageAxisToMaxRatio(percentageAxisToMaxRatio)
}
if (notNull(stackLabel)) {
chart.stackLabel(stackLabel)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
if (notNull(valueLabelFormat)) {
chart.valueLabelFormat(valueLabelFormat)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
}
function bindChartEvents() {
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
}
function bindChartTooltip() {
tooltip = britecharts.tooltip()
// tooltip.topicLabel("Hi Im the topic")
// tooltip.topicsOrder(["x", "y"])
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,129 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
/*
ISSUES - Doesn't seem to allow color change. Chart is colored black by default
*/
const _id = shortid.generate()
export let _bb
export let model
let store = _bb.store
const chart = britecharts.step()
const chartClass = `step-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
let tooltip
let tooltipContainer
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (
dataPoint,
colorMapping,
xPosition,
yPosition = null
) => tooltip.update(dataPoint, colorMapping, xPosition, (yPosition = null))
export let customMouseOut = () => tooltip.hide()
export let data = []
export let height = null
export let width = null
export let margin = null
export let xAxisLabel = null
export let xAxisLabelOffset = null
export let yAxisLabel = null
export let yAxisLabelOffset = null
export let yTicks = null
export let useLegend = true
onMount(async () => {
if (chart) {
if (model) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[model] = json
return state
})
} else {
throw new Error("Failed to fetch records.", response)
}
}
function bindChartUIProps() {
if (notNull(height)) {
chart.height(height)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(margin)) {
chart.margin(margin)
}
if (notNull(xAxisLabel)) {
chart.xAxisLabel(xAxisLabel)
}
if (notNull(xAxisLabelOffset)) {
chart.xAxisLabelOffset(xAxisLabelOffset)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
}
function bindChartEvents() {
if (customMouseMove) {
chart.on("customMouseMove", customMouseMove)
}
if (customMouseOut) {
chart.on("customMouseOut", customMouseOut)
}
if (customMouseOver) {
chart.on("customMouseOver", customMouseOver)
}
}
function bindChartTooltip() {
tooltip = britecharts.miniTooltip()
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltipContainer.datum([]).call(tooltip)
}
$: _data = model ? $store[model] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,41 @@
<script>
import { getColorSchema, getChartGradient, notNull } from "./utils"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
const chart = britecharts.chartname()
const chartClass = `donut-container-${_id}`
const legendClass = `legend-container-${_id}`
let chartElement = null
let chartContainer = null
export let data = []
export let color = "britecharts"
export let height = 200
export let width = 200
export let margin = { top: 0, right: 0, bottom: 0, left: 0 }
export let useLegend = true
onMount(() => {
if (chart) {
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
bindChartTooltip()
}
})
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -0,0 +1,12 @@
export { default as donut } from "./Donut.svelte"
export { default as bar } from "./Bar.svelte"
export { default as line } from "./Line.svelte"
export { default as brush } from "./Brush.svelte"
export { default as bullet } from "./Bullet.svelte"
export { default as groupedbar } from "./GroupedBar.svelte"
export { default as heatmap } from "./Heatmap.svelte"
export { default as sparkline } from "./Sparkline.svelte"
export { default as scatterplot } from "./ScatterPlot.svelte"
export { default as step } from "./Step.svelte"
export { default as stackedarea } from "./StackedArea.svelte"
export { default as stackedbar } from "./StackedBar.svelte"

View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-selection/1.2.0/d3-selection.js"></script>
<script src="https://cdn.jsdelivr.net/npm/britecharts@2.10.0/dist/umd/bar.min.js"
type="text/javascript"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/britecharts/dist/css/britecharts.min.css" type="text/css" />
</head>
<body>
<article>
<h2 class="tutorial__heading">Bar Chart</h2>
<div class="bar-chart"></div>
</article>
<script>
const dataset = [
{
"name": "Radiating",
"value": 2
},
{
"name": "Opalescent",
"value": 4
},
{
"name": "Shining",
"value": 3
},
{
"name": "Vibrant",
"value": 6
},
{
"name": "Vivid",
"value": 6
},
{
"name": "Brilliant",
"value": 1
}
]
const barContainer = d3.select('.bar-chart');
const barChart = britecharts.bar()
barChart
.width(700)
.height(300)
.enableLabels(true)
.labelsNumberFormat('.0%')
.isAnimated(true)
.yAxisLabel("Quantity")
.xAxisLabel("Color")
.betweenBarsPadding("0.8")
// .on('customMouseOver', tooltip.show)
// .on('customMouseMove', tooltip.update)
// .on('customMouseOut', tooltip.hide);
barContainer.datum(dataset).call(barChart);
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
import britecharts from "britecharts"
export const notNull = value => value || value === false
export const chartTypes = britecharts ? Object.keys(britecharts) : null
//expose chart color schemas for use or reference outside compnent
export const colorSchemas = britecharts ? britecharts.colors.colorSchemas : null
//export color gradients for use or reference outside the component
export const colorGradients = britecharts
? britecharts.colors.colorGradients
: null
export const getColorSchema = color =>
color ? colorSchemas[color] : colorSchemas["britecharts"]
export const getChartGradient = gradient =>
gradient ? colorGradients[gradient] : null

View File

@ -23,6 +23,8 @@
},
}
$: console.log("CHART CONFIGS", chartConfigs)
async function fetchData() {
const FETCH_RECORDS_URL = `/api/views/all_${model}`
const response = await _bb.api.get(FETCH_RECORDS_URL)

View File

@ -24,3 +24,4 @@ export { default as datasearch } from "./DataSearch.svelte"
export { default as embed } from "./Embed.svelte"
export { default as stackedlist } from "./StackedList.svelte"
export { default as recorddetail } from "./RecordDetail.svelte"
export * from "./Chart"