Merge pull request #817 from Budibase/apex-charts

Apex charts
This commit is contained in:
Andrew Kingston 2020-11-09 08:48:44 +00:00 committed by GitHub
commit 253568fd2d
45 changed files with 1348 additions and 3358 deletions

View File

@ -14,7 +14,7 @@
class="nav-item"
class:border
class:selected
style={`padding-left: ${indentLevel * 18}px`}
style={`padding-left: ${indentLevel * 14}px`}
{draggable}
on:dragend
on:dragstart
@ -65,7 +65,7 @@
}
.content {
padding: 0 var(--spacing-m);
padding: 0 var(--spacing-s);
height: 32px;
display: flex;
flex-direction: row;
@ -97,6 +97,9 @@
flex: 1 1 auto;
font-weight: 500;
font-size: var(--font-size-xs);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.actions {

View File

@ -129,7 +129,7 @@
ondragover="return false"
ondragenter="return false"
class="drop-item"
style="margin-left: {(level + 1) * 18}px" />
style="margin-left: {(level + 1) * 16}px" />
{/if}
<NavItem
@ -160,7 +160,7 @@
ondragover="return false"
ondragenter="return false"
class="drop-item"
style="margin-left: {(level + ($dragDropStore.dropPosition === 'inside' ? 3 : 1)) * 18}px" />
style="margin-left: {(level + ($dragDropStore.dropPosition === 'inside' ? 3 : 1)) * 16}px" />
{/if}
</li>
{/each}
@ -176,6 +176,6 @@
.drop-item {
border-radius: var(--border-radius-m);
height: 32px;
background: var(--blue-light);
background: var(--grey-3);
}
</style>

View File

@ -0,0 +1,42 @@
<script>
import { Multiselect } from "@budibase/bbui"
export let options = []
export let value = []
export let styleBindingProperty
export let onChange = () => {}
let boundValue = getValidOptions(value, options)
$: setValue(boundValue)
$: sanitiseOptions(options)
function getValidOptions(selectedOptions, allOptions) {
// Fix the hardcoded default string value
if (!Array.isArray(selectedOptions)) {
selectedOptions = []
}
return selectedOptions.filter(val => allOptions.indexOf(val) !== -1)
}
function setValue(val) {
onChange(val)
}
function sanitiseOptions(options) {
boundValue = getValidOptions(value, options)
}
</script>
<div>
<Multiselect extraThin secondary bind:value={boundValue}>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</Multiselect>
</div>
<style>
div {
flex: 1 1 auto;
}
</style>

View File

@ -0,0 +1,5 @@
<script>
import TableViewFieldSelect from "./TableViewFieldSelect.svelte"
</script>
<TableViewFieldSelect {...$$props} multiselect />

View File

@ -1,12 +1,12 @@
<script>
import { onMount, beforeUpdate, afterUpdate } from "svelte"
import { onMount } from "svelte"
import Portal from "svelte-portal"
import { buildStyle } from "../../helpers.js"
export let options = []
export let value = ""
export let styleBindingProperty
export let onChange = value => {}
export let onChange = () => {}
let open = null
let rotate = ""

View File

@ -72,7 +72,7 @@
let temp = runtimeToReadableBinding(bindableProperties, value)
return !value && props.defaultValue !== undefined
return value == null && props.defaultValue !== undefined
? props.defaultValue
: temp
}

View File

@ -118,7 +118,7 @@
control={definition.control}
label={definition.label}
key={definition.key}
value={componentInstance[definition.key] || componentInstance[definition.key]?.defaultValue}
value={componentInstance[definition.key] ?? componentInstance[definition.key]?.defaultValue}
{componentInstance}
{onChange}
props={{ ...excludeProps(definition, ['control', 'label']) }} />

View File

@ -1,11 +1,12 @@
<script>
import OptionSelect from "./OptionSelect.svelte"
import { backendUiStore } from "builderStore"
import { onMount } from "svelte"
import MultiOptionSelect from "./MultiOptionSelect.svelte"
export let componentInstance = {}
export let value = ""
export let onChange = (val = {})
export let onChange = () => {}
export let multiselect = false
const tables = $backendUiStore.tables
@ -24,4 +25,8 @@
}
</script>
<OptionSelect {value} {onChange} {options} />
{#if multiselect}
<MultiOptionSelect {value} {onChange} {options} />
{:else}
<OptionSelect {value} {onChange} {options} />
{/if}

View File

@ -1,5 +1,6 @@
import Input from "./PropertyPanelControls/Input.svelte"
import OptionSelect from "./OptionSelect.svelte"
import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte"
import Checkbox from "../common/Checkbox.svelte"
import TableSelect from "components/userInterface/TableSelect.svelte"
import TableViewSelect from "components/userInterface/TableViewSelect.svelte"
@ -423,122 +424,40 @@ export default {
isCategory: true,
children: [
{
name: "Donut",
_component: "@budibase/standard-components/donut",
description: "Donut chart",
icon: "ri-pie-chart-fill",
properties: {
settings: [
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Name Field",
key: "nameKey",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Value Field",
key: "valueKey",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
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: [
"britecharts",
"blueGreen",
"green",
"grey",
"orange",
"pink",
"purple",
"red",
"teal",
"yellow",
],
},
{
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,
},
],
},
},
{
name: "Bar",
name: "Bar Chart",
_component: "@budibase/standard-components/bar",
description: "Bar chart",
icon: "ri-bar-chart-fill",
icon: "ri-bar-chart-line",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Name Label",
key: "nameLabel",
label: "Label Col.",
key: "labelColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Value Label",
key: "valueLabel",
label: "Data Cols.",
key: "valueColumns",
dependsOn: "datasource",
control: TableViewFieldSelect,
control: MultiTableViewFieldSelect,
},
{
label: "Format",
key: "yAxisUnits",
control: OptionSelect,
options: ["Default", "Thousands", "Millions"],
defaultValue: "Default",
},
{
label: "Y Axis Label",
@ -550,56 +469,6 @@ export default {
key: "xAxisLabel",
control: Input,
},
{
label: "X Axis Label Offset",
key: "xAxisLabelOffset",
control: Input,
},
{
label: "Y Axis Label Offset",
key: "yAxisLabelOffset",
control: Input,
},
{
label: "Enable Labels",
key: "enableLabels",
control: Checkbox,
valueKey: "checked",
},
{
label: "Colors",
key: "color",
control: OptionSelect,
options: [
{ label: "Normal", value: "britecharts" },
{ label: "Blue Green", value: "blueGreen" },
{ label: "Green", value: "green" },
{ label: "Grey", value: "grey" },
{ label: "Orange", value: "orange" },
{ label: "Pink", value: "pink" },
{ label: "Purple", value: "purple" },
{ label: "Red", value: "red" },
{ label: "Teal", value: "teal" },
{ label: "Yellow", value: "yellow" },
],
},
{
label: "Gradients",
key: "gradient",
control: OptionSelect,
options: [
{ value: "", label: "None" },
{ value: "bluePurple", label: "Blue Purple" },
{ value: "greenBlue", label: "Green Blue" },
{ value: "orangePink", label: "Orange Pink" },
],
},
{
label: "Highlight Single Bar",
key: "hasSingleBarHighlight",
control: Checkbox,
valueKey: "checked",
},
{
label: "Width",
key: "width",
@ -609,221 +478,92 @@ export default {
label: "Height",
key: "height",
control: Input,
defaultValue: "400",
},
{
label: "Colours",
key: "palette",
control: OptionSelect,
defaultValue: "Palette 1",
options: [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10",
],
},
{
label: "Stacked",
key: "stacked",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Data Labels",
key: "dataLabels",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Animate",
key: "isAnimate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Horizontal",
key: "isHorizontal",
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
},
{
label: "Label Number Format",
key: "labelsNumberFormat",
control: Input,
defaultValue: false,
},
],
},
},
{
name: "Grouped Bar",
_component: "@budibase/standard-components/groupedbar",
description: "Groupedbar chart",
icon: "ri-bar-chart-grouped-fill",
properties: {
settings: [
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Name Label",
key: "nameLabel",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Group Label",
key: "groupLabel",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Value Label",
key: "valueLabel",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Color",
key: "color",
control: OptionSelect,
options: [
"britecharts",
"blueGreen",
"green",
"grey",
"orange",
"pink",
"purple",
"red",
"teal",
"yellow",
],
},
{
label: "Height",
key: "height",
control: Input,
},
{
label: "Width",
key: "width",
control: Input,
},
{
label: "Aspect Ratio",
key: "aspectRatio",
control: Input,
},
{
label: "Grid",
key: "grid",
control: OptionSelect,
options: ["vertical", "horizontal", "full"],
},
{
label: "Value Label",
key: "valueLabel",
control: Input,
},
{
label: "Y Ticks",
key: "yTicks",
control: Input,
},
{
label: "Y Tick Text Offset",
key: "yTickTextOffset",
control: Input,
},
{
label: "Is Animated",
key: "isAnimated",
valueKey: "checked",
control: Checkbox,
},
{
label: "Is Horizontal",
key: "isHorizontal",
valueKey: "checked",
control: Checkbox,
},
{
label: "Tooltip Title",
key: "tooltipTitle",
control: Input,
},
],
},
},
{
name: "Line",
name: "Line Chart",
_component: "@budibase/standard-components/line",
description: "Line chart",
icon: "ri-line-chart-line",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Value Label",
key: "valueLabel",
label: "Label Col.",
key: "labelColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Topic Label",
key: "topicLabel",
label: "Data Cols.",
key: "valueColumns",
dependsOn: "datasource",
control: TableViewFieldSelect,
control: MultiTableViewFieldSelect,
},
{
label: "Date Label",
key: "dateLabel",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Colors",
key: "color",
label: "Format",
key: "yAxisUnits",
control: OptionSelect,
options: [
"britecharts",
"blueGreen",
"green",
"grey",
"orange",
"pink",
"purple",
"red",
"teal",
"yellow",
],
},
{
label: "Gradients",
key: "lineGradient",
control: OptionSelect,
options: [
{ value: "", label: "None" },
{ value: "bluePurple", label: "Blue Purple" },
{ value: "greenBlue", label: "Green Blue" },
{ value: "orangePink", label: "Orange Pink" },
],
},
{
label: "Line Curve",
key: "lineCurve",
control: OptionSelect,
options: [
"linear",
"basis",
"natural",
"monotoneX",
"monotoneY",
"step",
"stepAfter",
"stepBefore",
"cardinal",
"catmullRom",
],
},
{
label: "X Axis Value Type",
key: "xAxisValueType",
control: OptionSelect,
options: ["date", "number"],
},
{
label: "Grid",
key: "grid",
control: OptionSelect,
options: ["vertical", "horizontal", "full"],
},
{
label: "X Axis Label",
key: "xAxisLabel",
control: Input,
options: ["Default", "Thousands", "Millions"],
defaultValue: "Default",
},
{
label: "Y Axis Label",
@ -831,10 +571,9 @@ export default {
control: Input,
},
{
label: "Show All Datapoints",
key: "shouldShowAllDataPoints",
valueKey: "checked",
control: Checkbox,
label: "X Axis Label",
key: "xAxisLabel",
control: Input,
},
{
label: "Width",
@ -845,57 +584,423 @@ export default {
label: "Height",
key: "height",
control: Input,
defaultValue: "400",
},
{
label: "Is Animated",
key: "isAnimated",
control: Checkbox,
valueKey: "checked",
},
{
label: "Locale",
key: "locale",
label: "Curve",
key: "curve",
control: OptionSelect,
options: ["en-GB", "en-US"],
options: ["Smooth", "Straight", "Stepline"],
defaultValue: "Smooth",
},
{
label: "X Axis Value Type",
key: "xAxisValueType",
control: OptionSelect,
options: ["date", "numeric"],
},
{
label: "X Axis Format",
key: "xAxisFormat",
label: "Colours",
key: "palette",
control: OptionSelect,
defaultValue: "Palette 1",
options: [
"day-month",
"minute-hour",
"hour-daymonth",
"month-year",
"custom",
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10",
],
},
{
label: "X Axis Custom Format",
key: "xAxisCustomFormat",
label: "Data Labels",
key: "dataLabels",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Animate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
],
},
},
{
name: "Area Chart",
_component: "@budibase/standard-components/area",
description: "Line chart",
icon: "ri-line-chart-fill",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Tooltip Title",
key: "tooltipTitle",
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Label Col.",
key: "labelColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Data Cols.",
key: "valueColumns",
dependsOn: "datasource",
control: MultiTableViewFieldSelect,
},
{
label: "Format",
key: "yAxisUnits",
control: OptionSelect,
options: ["Default", "Thousands", "Millions"],
defaultValue: "Default",
},
{
label: "Y Label",
key: "yAxisLabel",
control: Input,
},
{
label: "X Ticks",
key: "xTicks",
label: "X Label",
key: "xAxisLabel",
control: Input,
},
{
label: "Y Ticks",
key: "yTicks",
label: "Width",
key: "width",
control: Input,
},
{
label: "Height",
key: "height",
control: Input,
defaultValue: "400",
},
{
label: "Curve",
key: "curve",
control: OptionSelect,
options: ["Smooth", "Straight", "Stepline"],
defaultValue: "Smooth",
},
{
label: "Colours",
key: "palette",
control: OptionSelect,
defaultValue: "Palette 1",
options: [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10",
],
},
{
label: "Data Labels",
key: "dataLabels",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Animate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Stacked",
key: "stacked",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Gradient",
key: "gradient",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
],
},
},
{
name: "Pie Chart",
_component: "@budibase/standard-components/pie",
description: "Pie chart",
icon: "ri-pie-chart-line",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Label Col.",
key: "labelColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Data Col.",
key: "valueColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Width",
key: "width",
control: Input,
},
{
label: "Height",
key: "height",
control: Input,
defaultValue: "200",
},
{
label: "Colours",
key: "palette",
control: OptionSelect,
defaultValue: "Palette 1",
options: [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10",
],
},
{
label: "Data Labels",
key: "dataLabels",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Animate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
],
},
},
{
name: "Donut Chart",
_component: "@budibase/standard-components/donut",
description: "Donut chart",
icon: "ri-donut-chart-line",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Label Col.",
key: "labelColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Data Col.",
key: "valueColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Width",
key: "width",
control: Input,
},
{
label: "Height",
key: "height",
control: Input,
defaultValue: "200",
},
{
label: "Colours",
key: "palette",
control: OptionSelect,
defaultValue: "Palette 1",
options: [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10",
],
},
{
label: "Data Labels",
key: "dataLabels",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
{
label: "Animate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
{
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
],
},
},
{
name: "Candlestick Chart",
_component: "@budibase/standard-components/candlestick",
description: "Candlestick chart",
icon: "ri-stock-line",
properties: {
settings: [
{
label: "Title",
key: "title",
control: Input,
},
{
label: "Data",
key: "datasource",
control: TableViewSelect,
},
{
label: "Date Col.",
key: "dateColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Open Col.",
key: "openColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Close Col.",
key: "closeColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "High Col.",
key: "highColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Low Col.",
key: "lowColumn",
dependsOn: "datasource",
control: TableViewFieldSelect,
},
{
label: "Format",
key: "yAxisUnits",
control: OptionSelect,
options: ["Default", "Thousands", "Millions"],
defaultValue: "Default",
},
{
label: "Y Axis Label",
key: "yAxisLabel",
control: Input,
},
{
label: "X Axis Label",
key: "xAxisLabel",
control: Input,
},
{
label: "Width",
key: "width",
control: Input,
},
{
label: "Height",
key: "height",
control: Input,
defaultValue: "400",
},
{
label: "Animate",
key: "animate",
control: Checkbox,
valueKey: "checked",
defaultValue: true,
},
],
},
},

View File

@ -28,6 +28,7 @@ html, body {
margin: 0;
height: 100%;
width: 100%;
background-color: var(--background);
}
#app {

View File

@ -69,7 +69,7 @@
display: flex;
flex-direction: column;
gap: var(--spacing-l);
padding: var(--spacing-l) var(--spacing-xl);
padding: var(--spacing-l) var(--spacing-xl) 60px var(--spacing-xl);
overflow-y: auto;
}

View File

@ -80,27 +80,30 @@ const makeRowRequestBody = (parameters, state) => {
if (body._table) delete body._table
// then override with supplied parameters
for (let fieldName of Object.keys(parameters.fields)) {
const field = parameters.fields[fieldName]
if (parameters.fields) {
for (let fieldName of Object.keys(parameters.fields)) {
const field = parameters.fields[fieldName]
// ensure fields sent are of the correct type
if (field.type === "boolean") {
if (field.value === "true") body[fieldName] = true
if (field.value === "false") body[fieldName] = false
} else if (field.type === "number") {
const val = parseFloat(field.value)
if (!isNaN(val)) {
body[fieldName] = val
// ensure fields sent are of the correct type
if (field.type === "boolean") {
if (field.value === "true") body[fieldName] = true
if (field.value === "false") body[fieldName] = false
} else if (field.type === "number") {
const val = parseFloat(field.value)
if (!isNaN(val)) {
body[fieldName] = val
}
} else if (field.type === "datetime") {
const date = new Date(field.value)
if (!isNaN(date.getTime())) {
body[fieldName] = date.toISOString()
}
} else {
body[fieldName] = field.value
}
} else if (field.type === "datetime") {
const date = new Date(field.value)
if (!isNaN(date.getTime())) {
body[fieldName] = date.toISOString()
}
} else {
body[fieldName] = field.value
}
}
return body
}

View File

@ -396,286 +396,283 @@
}
}
},
"datamap": {
"description": "shiny chart",
"data": true,
"props": {
"table": "tables"
}
},
"donut": {
"description": "Donut Chart",
"data": true,
"props": {
"datasource": "string",
"data": "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": {
"table": "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": {
"datasource": "tables",
"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": {
"table": "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": {
"table": "string",
"height": "number",
"width": "number",
"margin": "string",
"xAxisLabel": "string",
"xAxisLabelOffset": "string",
"yAxisLabel": "string",
"yAxisLabelOffset": "string",
"yTicks": "string"
}
},
"scatterplot": {
"description": "Scatterplot Chart",
"data": true,
"props": {
"table": "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": {
"title": "string",
"datasource": "tables",
"nameLabel": "string",
"valueLabel": "string",
"betweenBarsPadding": "number",
"gradient": "string",
"color": "string",
"hasSingleBarHighlight": "bool",
"height": "number",
"width": "number",
"isAnimated": "bool",
"isHorizontal": "bool",
"labelNumberFormat": "number",
"locale": "string",
"labelColumn": "string",
"valueColumns": "string",
"height": {
"type": "string",
"default": "400"
},
"width": "string",
"dataLabels": "bool",
"animate": {
"type": "bool",
"default": true
},
"xAxisLabel": "string",
"yAxisLabel": "string",
"useLegend": "bool",
"xTicks": "number",
"yTicks": "number"
"legend": "bool",
"stacked": "bool",
"yAxisUnits": {
"type": "options",
"default": "Default",
"options": [
"Default", "Thousands", "Millions"
]
},
"palette": {
"type": "options",
"default": "Palette 1",
"options": [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10"
]
}
}
},
"line": {
"description": "Line Chart",
"data": true,
"props": {
"title": "string",
"datasource": "tables",
"width": "number",
"height": "number",
"axisTimeCombinations": "string",
"color": "string",
"grid": {
"labelColumn": "string",
"valueColumns": "string",
"height": {
"type": "string",
"default": "horizontal"
"default": "400"
},
"aspectRatio": "number",
"dateLabel": "string",
"isAnimated": {
"width": "string",
"dataLabels": {
"type": "bool",
"default": false
},
"animate": {
"type": "bool",
"default": true
},
"lineCurve": "string",
"locale": "string",
"numberFormat": "string",
"shouldShowAllDataPoints": {
"type": "bool",
"default": true
},
"topicLabel": "string",
"valueLabel": "string",
"xAxisValueType": {
"type": "string",
"default": "date"
},
"xAxisScale": "string",
"xAxisFormat": {
"type": "string",
"default": "custom"
},
"xAxisCustomFormat": "string",
"xAxisLabel": "string",
"yAxisLabel": "string",
"tooltipTitle": "string",
"xTicks": "number",
"yTicks": "number"
"curve": {
"type": "options",
"options": [
"Smooth",
"Straight",
"Stepline"
],
"default": "Smooth"
},
"legend": "bool",
"yAxisUnits": {
"type": "options",
"default": "Default",
"options": [
"Default", "Thousands", "Millions"
]
},
"palette": {
"type": "options",
"default": "Palette 1",
"options": [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10"
]
}
}
},
"brush": {
"description": "brush chart",
"data": true,
"props": {
"table": "string",
"gradient": "string",
"height": "number",
"width": "number",
"margin": "string",
"dateRange": "string",
"locale": "string",
"roundingTimeInterval": "string",
"xAxisFormat": "string",
"xTicks": "number",
"xAxisCustomFormat": "string"
}
},
"heatmap": {
"description": "Heatmap chart",
"data": true,
"props": {
"table": "string",
"color": "string",
"height": "number",
"width": "number",
"useLegend": "bool",
"yAxisLabel": "string",
"boxSize": "number"
}
},
"groupedbar": {
"description": "Groupedbar chart",
"area": {
"description": "Area Chart",
"data": true,
"props": {
"title": "string",
"datasource": "tables",
"nameLabel": "string",
"valueLabel": "string",
"color": "string",
"height": "string",
"labelColumn": "string",
"valueColumns": "string",
"height": {
"type": "string",
"default": "400"
},
"width": "string",
"margin": "string",
"grid": "string",
"groupLabel": "string",
"isAnimated": "bool",
"isHorizontal": "bool",
"yTicks": "string",
"useLegend": "bool",
"tooltipTitle": "string"
"dataLabels": {
"type": "bool",
"default": false
},
"animate": {
"type": "bool",
"default": true
},
"xAxisLabel": "string",
"yAxisLabel": "string",
"curve": {
"type": "options",
"options": [
"Smooth",
"Straight",
"Stepline"
],
"default": "Smooth"
},
"legend": "bool",
"stacked": {
"type": "bool",
"default": true
},
"gradient": "bool",
"yAxisUnits": {
"type": "options",
"default": "Default",
"options": [
"Default", "Thousands", "Millions"
]
},
"palette": {
"type": "options",
"default": "Palette 1",
"options": [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10"
]
}
}
},
"bullet": {
"description": "Bullet chart",
"pie": {
"description": "Pie Chart",
"data": true,
"props": {
"table": "string",
"color": "string",
"customSubtitle": "string",
"customTitle": "string",
"numberFormat": "string",
"paddingBetweenAxisAndChart": "number",
"height": "number",
"width": "number"
"title": "string",
"datasource": "tables",
"labelColumn": "string",
"valueColumn": "string",
"height": {
"type": "string",
"default": "200"
},
"width": "string",
"dataLabels": "bool",
"animate": {
"type": "bool",
"default": true
},
"legend": {
"type": "bool",
"default": true
},
"palette": {
"type": "options",
"default": "Palette 1",
"options": [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10"
]
}
}
},
"donut": {
"description": "Donut Chart",
"data": true,
"props": {
"title": "string",
"datasource": "tables",
"labelColumn": "string",
"valueColumn": "string",
"height": {
"type": "string",
"default": "200"
},
"width": "string",
"dataLabels": "bool",
"animate": {
"type": "bool",
"default": true
},
"legend": {
"type": "bool",
"default": true
},
"palette": {
"type": "options",
"default": "Palette 1",
"options": [
"Palette 1",
"Palette 2",
"Palette 3",
"Palette 4",
"Palette 5",
"Palette 6",
"Palette 7",
"Palette 8",
"Palette 9",
"Palette 10"
]
}
}
},
"candlestick": {
"description": "Candlestick Chart",
"data": true,
"props": {
"title": "string",
"datasource": "tables",
"dateColumn": "string",
"openColumn": "string",
"closeColumn": "string",
"highColumn": "string",
"lowColumn": "string",
"height": {
"type": "string",
"default": "400"
},
"width": "string",
"animate": {
"type": "bool",
"default": true
},
"xAxisLabel": "string",
"yAxisLabel": "string",
"yAxisUnits": {
"type": "options",
"default": "Default",
"options": [
"Default", "Thousands", "Millions"
]
}
}
},
"datepicker": {
@ -686,30 +683,6 @@
"placeholder": "string"
}
},
"datachart": {
"description": "shiny chart",
"data": true,
"props": {
"table": "tables",
"type": {
"type": "options",
"default": "column2d",
"options": [
"column3d",
"line",
"area2d",
"bar2d",
"bar3d",
"pie2d",
"pie3d",
"doughnut2d",
"doughnut3d",
"pareto2d",
"pareto3d"
]
}
}
},
"link": {
"name": "Link",
"description": "an HTML anchor <a> tag",

View File

@ -35,18 +35,15 @@
"license": "MIT",
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": {
"@beyonk/svelte-googlemaps": "^2.2.0",
"@budibase/bbui": "^1.50.1",
"@budibase/svelte-ag-grid": "^0.0.13",
"@fortawesome/fontawesome-free": "^5.14.0",
"@svelteschool/svelte-forms": "^0.7.0",
"britecharts": "^2.16.1",
"d3-selection": "^1.4.2",
"apexcharts": "^3.22.1",
"fast-sort": "^2.2.0",
"flatpickr": "^4.6.6",
"fusioncharts": "^3.15.1-sr.1",
"lodash.debounce": "^4.0.8",
"svelte-flatpickr": "^3.1.0",
"svelte-fusioncharts": "^1.0.0"
"svelte-apexcharts": "^1.0.2",
"svelte-flatpickr": "^3.1.0"
}
}

View File

@ -0,0 +1,18 @@
<script>
import { chart } from "svelte-apexcharts"
export let options
</script>
{#if options}
<div use:chart={options} />
{:else if options === false}
<div>Invalid chart options</div>
{/if}
<style>
div :global(.apexcharts-legend-series) {
display: flex !important;
text-transform: capitalize;
}
</style>

View File

@ -0,0 +1,154 @@
export class ApexOptionsBuilder {
formatters = {
["Default"]: val => Math.round(val * 100) / 100,
["Thousands"]: val => `${Math.round(val / 1000)}K`,
["Millions"]: val => `${Math.round(val / 1000000)}M`,
}
options = {
series: [],
legend: {
show: false,
position: "top",
horizontalAlign: "right",
showForSingleSeries: true,
showForNullSeries: true,
showForZeroSeries: true,
},
chart: {
toolbar: {
show: false,
},
zoom: {
enabled: false,
},
},
yaxis: {
labels: {
formatter: this.formatters.Default,
},
},
}
setOption(path, value) {
if (value == null || value === "") {
return this
}
let tmp = this.options
for (let i = 0; i < path.length - 1; i++) {
const step = path[i]
if (!tmp[step]) {
tmp[step] = {}
}
tmp = tmp[step]
}
tmp[path[path.length - 1]] = value
return this
}
getOptions() {
return this.options
}
type(type) {
return this.setOption(["chart", "type"], type)
}
title(title) {
return this.setOption(["title", "text"], title)
}
color(color) {
return this.setOption(["colors"], [color])
}
width(width) {
return this.setOption(["chart", "width"], width || undefined)
}
height(height) {
return this.setOption(["chart", "height"], height || undefined)
}
xLabel(label) {
return this.setOption(["xaxis", "title", "text"], label)
}
yLabel(label) {
return this.setOption(["yaxis", "title", "text"], label)
}
categories(categories) {
return this.setOption(["xaxis", "categories"], categories)
}
series(series) {
return this.setOption(["series"], series)
}
horizontal(horizontal) {
return this.setOption(["plotOptions", "bar", "horizontal"], horizontal)
}
dataLabels(dataLabels) {
return this.setOption(["dataLabels", "enabled"], dataLabels)
}
animate(animate) {
return this.setOption(["chart", "animations", "enabled"], animate)
}
curve(curve) {
return this.setOption(["stroke", "curve"], curve)
}
gradient(gradient) {
const fill = {
type: "gradient",
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 90, 100],
},
}
return this.setOption(["fill"], gradient ? fill : undefined)
}
legend(legend) {
return this.setOption(["legend", "show"], legend)
}
legendPosition(position) {
return this.setOption(["legend", "position"], position)
}
stacked(stacked) {
return this.setOption(["chart", "stacked"], stacked)
}
labels(labels) {
return this.setOption(["labels"], labels)
}
yUnits(units) {
return this.setOption(
["yaxis", "labels", "formatter"],
this.formatters[units || "Default"]
)
}
xType(type) {
return this.setOption(["xaxis", "type"], type)
}
yTooltip(yTooltip) {
return this.setOption(["yaxis", "tooltip", "enabled"], yTooltip)
}
palette(palette) {
return this.setOption(
["theme", "palette"],
palette.toLowerCase().replace(/[\W]/g, "")
)
}
}

View File

@ -0,0 +1,5 @@
<script>
import LineChart from "./LineChart.svelte"
</script>
<LineChart {...$$props} area />

View File

@ -1,187 +0,0 @@
<script>
import {
getColorSchema,
getChartGradient,
notNull,
hasProp,
} from "./utils.js"
import britecharts from "britecharts"
import fetchData from "../fetchData.js"
import { onMount } from "svelte"
import { isEmpty } from "lodash/fp"
import { select } from "d3-selection"
import shortid from "shortid"
let tooltip
const _id = shortid.generate()
const chart = britecharts.bar()
const chartClass = `bar-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
let data = []
export let datasource = null
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 = false
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
onMount(async () => {
if (!isEmpty(datasource)) {
data = await fetchData(datasource)
if (schemaIsValid()) {
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
bindChartTooltip()
} else {
console.error("Bar Chart - Please provide a valid name and value label")
}
}
})
const schemaIsValid = () =>
(hasProp(data, "name") || hasProp(data, nameLabel)) &&
(hasProp(data, "value") || hasProp(data, valueLabel))
function bindChartUIProps() {
chart.numberFormat(".0f")
chart.labelsNumberFormat(".1f")
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(gradient)) {
chart.chartGradient(chartGradient)
}
if (notNull(xAxisLabel)) {
chart.xAxisLabel(xAxisLabel)
}
if (notNull(yAxisLabel)) {
chart.yAxisLabel(yAxisLabel)
}
if (notNull(betweenBarsPadding)) {
chart.betweenBarsPadding(Number(betweenBarsPadding))
}
if (notNull(enableLabels)) {
chart.enableLabels(enableLabels)
}
if (notNull(hasPercentage)) {
chart.hasPercentage(hasPercentage)
}
if (notNull(hasSingleBarHighlight)) {
chart.hasSingleBarHighlight(hasSingleBarHighlight)
}
if (notNull(labelsMargin)) {
chart.labelsMargin(labelsMargin)
}
if (notNull(height)) {
chart.height(height)
}
if (notNull(highlightBarFunction)) {
chart.highlightBarFunction(highlightBarFunction)
}
if (notNull(width)) {
chart.width(width)
}
if (notNull(isAnimated)) {
chart.isAnimated(isAnimated)
}
if (notNull(isHorizontal)) {
chart.isHorizontal(isHorizontal)
}
if (notNull(yAxisLabelOffset)) {
chart.yAxisLabelOffset(yAxisLabelOffset)
}
if (notNull(xAxisLabelOffset)) {
chart.xAxisLabelOffset(Number(xAxisLabelOffset))
}
if (notNull(labelsNumberFormat)) {
chart.labelsNumberFormat(labelsNumberFormat)
}
if (notNull(valueLabel)) {
chart.valueLabel(valueLabel)
}
if (notNull(locale)) {
chart.locale(locale)
}
if (notNull(nameLabel)) {
chart.nameLabel(nameLabel)
}
if (notNull(numberFormat)) {
chart.numberFormat(numberFormat)
}
if (notNull(labelsSize)) {
chart.labelsSize(labelsSize)
}
if (notNull(xTicks)) {
chart.xTicks(xTicks)
}
if (notNull(yTicks)) {
chart.yTicks(yTicks)
}
if (notNull(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)
}
$: colorSchema = getColorSchema(color)
$: chartGradient = getChartGradient(gradient)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -0,0 +1,99 @@
<script>
import { onMount } from "svelte"
import fetchData, { fetchSchema } from "../fetchData"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
import ApexChart from "./ApexChart.svelte"
import { isEmpty } from "lodash/fp"
import {
closeColumn,
dateColumn,
highColumn,
lowColumn,
openColumn,
} from "./CandleStickChart.svelte"
export let _bb
export let title
export let datasource
export let labelColumn
export let valueColumns
export let xAxisLabel
export let yAxisLabel
export let height
export let width
export let color
export let dataLabels
export let animate
export let legend
export let stacked
export let yAxisUnits
export let palette
const store = _bb.store
let options
// Fetch data on mount
onMount(async () => {
const allCols = [labelColumn, ...(valueColumns || [])]
if (isEmpty(datasource) || allCols.find(x => x == null)) {
options = false
return
}
// Fetch, filter and sort data
const schema = await fetchSchema(datasource.tableId)
const result = await fetchData(datasource, $store)
const reducer = row => (valid, column) => valid && row[column] != null
const hasAllColumns = row => allCols.reduce(reducer(row), true)
const data = result
.filter(row => hasAllColumns(row))
.slice(0, 20)
.sort((a, b) => (a[labelColumn] > b[labelColumn] ? 1 : -1))
if (!schema || !data.length) {
options = false
return
}
// Initialise default chart
let builder = new ApexOptionsBuilder()
.type("bar")
.title(title)
.width(width)
.height(height)
.xLabel(xAxisLabel)
.yLabel(yAxisLabel)
.dataLabels(dataLabels)
.animate(animate)
.legend(legend)
.stacked(stacked)
.yUnits(yAxisUnits)
.palette(palette)
// Add data
let useDates = false
if (datasource.type !== "view" && schema[labelColumn]) {
const labelFieldType = schema[labelColumn].type
builder = builder.xType(labelFieldType)
useDates = labelFieldType === "datetime"
}
const series = valueColumns.map(column => ({
name: column,
data: data.map(row => {
if (!useDates) {
return row[column]
} else {
return [row[labelColumn], row[column]]
}
}),
}))
builder = builder.series(series)
if (!useDates) {
builder = builder.categories(data.map(row => row[labelColumn]))
}
// Build chart options
options = builder.getOptions()
})
</script>
<ApexChart {options} />

View File

@ -1,118 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: chartGradient = getChartGradient(gradient)
$: console.log(chartGradient)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -1,103 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -0,0 +1,74 @@
<script>
import { onMount } from "svelte"
import fetchData, { fetchSchema } from "../fetchData"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
import ApexChart from "./ApexChart.svelte"
import { isEmpty } from "lodash/fp"
export let _bb
export let title
export let datasource
export let dateColumn
export let openColumn
export let highColumn
export let lowColumn
export let closeColumn
export let xAxisLabel
export let yAxisLabel
export let height
export let width
export let animate
export let yAxisUnits
const store = _bb.store
let options
// Fetch data on mount
onMount(async () => {
const allCols = [dateColumn, openColumn, highColumn, lowColumn, closeColumn]
if (isEmpty(datasource) || allCols.find(x => x == null)) {
options = false
return
}
// Fetch, filter and sort data
const schema = await fetchSchema(datasource.tableId)
const result = await fetchData(datasource, $store)
const reducer = row => (valid, column) => valid && row[column] != null
const hasAllColumns = row => allCols.reduce(reducer(row), true)
const data = result
.filter(row => hasAllColumns(row))
.slice(0, 100)
.sort((a, b) => (a[dateColumn] > b[dateColumn] ? 1 : -1))
if (!schema || !data.length) {
options = false
return
}
// Initialise default chart
let builder = new ApexOptionsBuilder()
.type("candlestick")
.title(title)
.width(width)
.height(height)
.xLabel(xAxisLabel)
.yLabel(yAxisLabel)
.animate(animate)
.yUnits(yAxisUnits)
.yTooltip(true)
.xType("datetime")
// Add data
const parseDate = d => (isNaN(d) ? Date.parse(d).valueOf() : parseInt(d))
const chartData = data.map(row => ({
x: parseDate(row[dateColumn]),
y: [row[openColumn], row[highColumn], row[lowColumn], row[closeColumn]],
}))
builder = builder.series([{ data: chartData }])
// Build chart options
options = builder.getOptions()
})
</script>
<ApexChart {options} />

View File

@ -1,169 +0,0 @@
<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

@ -1,213 +0,0 @@
<script>
import { getColorSchema, notNull } from "./utils.js"
import fetchData from "../fetchData.js"
import Legend from "./Legend.svelte"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { isEmpty } from "lodash/fp"
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
let store = _bb.store
export let customMouseMove = null
export let customClick = null
export let orderingFunction = null
let data = []
export let datasource = {}
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
onMount(async () => {
if (chart) {
if (!isEmpty(datasource)) {
let _data = await fetchData(datasource)
data = checkAndReformatData(_data)
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 && valueKey !== "quantity") {
_data = reformatDataKey(_data, valueKey, "quantity")
}
if (nameKey && nameKey !== "name") {
_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 clonedRow = { ...d }
if (clonedRow[formatKey]) {
delete clonedRow[formatKey]
}
let value = clonedRow[dataKey]
if (!ignoreList.includes(dataKey)) {
delete clonedRow[dataKey]
}
clonedRow[formatKey] = value
return clonedRow
})
} 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,5 @@
<script>
import PieChart from "./PieChart.svelte"
</script>
<PieChart {...$$props} donut />

View File

@ -1,145 +0,0 @@
<script>
import { getColorSchema, getChartGradient, notNull, hasProp } from "./utils"
import Tooltip from "./Tooltip.svelte"
import fetchData from "../fetchData.js"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { select } from "d3-selection"
import shortid from "shortid"
import { isEmpty } from "lodash/fp"
const _id = shortid.generate()
const chart = britecharts.groupedBar()
const chartClass = `groupedbar-container-${_id}`
const legendClass = `legend-container-${_id}`
let tooltip = britecharts.tooltip()
let tooltipContainer
let chartElement = null
let chartContainer = null
export let customClick = null
let data = []
export let datasource = {}
export let color = "britecharts"
export let height = 200
export let width = 200
export let margin = null
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 tooltipTitle = ""
const schemaIsValid = () =>
(hasProp(data, "name") || hasProp(data, nameLabel)) &&
(hasProp(data, "group") || hasProp(data, groupLabel)) &&
(hasProp(data, "value") || hasProp(data, valueLabel))
onMount(async () => {
if (!isEmpty(datasource)) {
data = await fetchData(datasource)
if (schemaIsValid()) {
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
bindTooltip()
} else {
console.error(
"Grouped bar - Please provide valid name, value and group labels"
)
}
}
})
function bindTooltip() {
tooltipContainer = select(`.${chartClass} .metadata-group`)
tooltip.topicLabel("values")
tooltip.shouldShowDateInTitle(false)
tooltipContainer.datum([]).call(tooltip)
}
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(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)
}
if (notNull(tooltipTitle)) {
tooltip.title(tooltipTitle)
} else if (datasource.label) {
tooltip.title(datasource.label)
}
}
function bindChartEvents() {
if (customClick) {
chart.on("customClick", customClick)
}
chart.on("customMouseMove", tooltip.update)
chart.on("customMouseOut", tooltip.hide)
chart.on("customMouseOver", tooltip.show)
}
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -1,83 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(data).call(chart)
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,86 +0,0 @@
<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}
style={`width: ${width}px`}
class={legendClass} />
{/if}

View File

@ -1,256 +0,0 @@
<script>
import { getColorSchema, getChartGradient, notNull, hasProp } from "./utils"
import fetchData from "../fetchData.js"
import britecharts from "britecharts"
import { onMount } from "svelte"
import { isEmpty } from "lodash/fp"
import { select } from "d3-selection"
import shortid from "shortid"
const _id = shortid.generate()
export let datasource = {}
const chart = britecharts.line()
const chartClass = `line-container-${_id}`
let data = { dataByTopic: [] }
let chartElement
let chartContainer
let tooltipContainer
let tooltip = britecharts.tooltip()
export let customMouseOver = () => tooltip.show()
export let customMouseMove = (
dataPoint,
topicColorMap,
dataPointXPosition,
yPosition
) => {
tooltip.update(dataPoint, topicColorMap, dataPointXPosition, yPosition)
}
export let customMouseOut = () => tooltip.hide()
export let customDataEntryClick = null
export let customTouchMove = null
export let color = "britecharts"
export let axisTimeCombinations = ""
export let grid = "horizontal"
export let aspectRatio = 0.5
export let width = null
export let height = null
export let isAnimated = true
export let lineCurve = "linear" //see api for possible opts
export let lineGradient = null
export let locale = "en-GB"
export let numberFormat = ""
export let shouldShowAllDataPoints = true
export let topicLabel = null
export let dateLabel = "date"
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 yAxisLabelPadding = null
export let lines = null //not handled by setting prop
export let tooltipThreshold = null
export let tooltipTitle = ""
export let xTicks = ""
export let yTicks = ""
onMount(async () => {
if (!isEmpty(datasource)) {
data = await getAndPrepareData()
if (data.dataByTopic.length > 0) {
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(data).call(chart)
// Hack 🤮 X Axis Label and last tick label gets cut off unless we do this 👇
const chartSvg = document.querySelector(`.${chartClass} .britechart`)
if (chartSvg) {
let height = chartSvg.getAttribute("height")
let width = chartSvg.getAttribute("width")
height = parseInt(height) + 35
width = parseInt(width) + 15
chartSvg.setAttribute("height", height)
chartSvg.setAttribute("width", width)
}
bindTooltip()
} else {
console.error(
"Line Chart - Please provide valid name, value and topic labels"
)
}
}
})
function bindTooltip() {
tooltipContainer = select(
`.${chartClass} .metadata-group .vertical-marker-container`
)
tooltip.topicLabel("topics")
tooltipContainer.datum([]).call(tooltip)
}
const schemaIsValid = data =>
hasProp(data, valueLabel) &&
hasProp(data, dateLabel) &&
hasProp(data, topicLabel)
async function getAndPrepareData() {
let dataByTopic = []
let _data = []
if (!topicLabel) {
topicLabel = "topicName"
}
if (!valueLabel) {
valueLabel = "value"
}
if (!dateLabel) {
dateLabel = "date"
}
_data = await fetchData(datasource)
if (schemaIsValid(_data)) {
_data.forEach((data, idx, arr) => {
let topicName = data[topicLabel]
if (!dataByTopic.some(dt => dt.topicName === topicName)) {
let d = {
topicName,
topic: dataByTopic.length + 1,
dates: arr
.filter(d => d[topicLabel] === topicName)
.map(d => ({
date: new Date(d[dateLabel]),
value: d[valueLabel],
}))
.sort((a, b) => a.date - b.date),
}
dataByTopic.push(d)
}
})
}
return { dataByTopic }
}
function bindChartUIProps() {
chart.tooltipThreshold(800)
chart.aspectRatio(0.5)
chart.xAxisCustomFormat("%e %b %Y")
chart.xTicks(data.dataByTopic.length)
if (notNull(color)) {
chart.colorSchema(colorSchema)
}
if (notNull(lineGradient)) {
chart.lineGradient(chartGradient)
}
if (notNull(axisTimeCombinations)) {
chart.axisTimeCombinations(axisTimeCombinations)
}
if (notNull(grid)) {
chart.grid(grid)
}
if (notNull(aspectRatio)) {
chart.aspectRatio(aspectRatio)
}
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(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)
}
if (notNull(tooltipThreshold)) {
chart.tooltipThreshold(tooltipThreshold)
}
if (notNull(lines)) {
chart.lines(lines)
}
if (notNull(xTicks)) {
chart.xTicks(Number(xTicks))
}
if (notNull(yTicks)) {
chart.yTicks(Number(yTicks))
}
if (notNull(tooltipTitle)) {
tooltip.title(tooltipTitle)
} else if (datasource.label) {
tooltip.title(datasource.label)
}
}
function bindChartEvents() {
if (customMouseOver) {
chart.on("customMouseOver", tooltip.show)
}
if (customMouseMove) {
chart.on("customMouseMove", tooltip.update)
}
if (customMouseOut) {
chart.on("customMouseOut", tooltip.hide)
}
if (customDataEntryClick) {
chart.on("customDataEntryClick", customDataEntryClick)
}
if (customTouchMove) {
chart.on("customTouchMove", customTouchMove)
}
}
$: colorSchema = getColorSchema(color)
$: chartGradient = getChartGradient(lineGradient)
</script>
<div bind:this={chartElement} class={chartClass} />

View File

@ -0,0 +1,100 @@
<script>
import { onMount } from "svelte"
import fetchData, { fetchSchema } from "../fetchData"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
import ApexChart from "./ApexChart.svelte"
import { isEmpty } from "lodash/fp"
// Common props
export let _bb
export let title
export let datasource
export let labelColumn
export let valueColumns
export let xAxisLabel
export let yAxisLabel
export let height
export let width
export let color
export let animate
export let dataLabels
export let curve
export let legend
export let yAxisUnits
export let palette
// Area specific props
export let area
export let stacked
export let gradient
const store = _bb.store
let options
// Fetch data on mount
onMount(async () => {
const allCols = [labelColumn, ...(valueColumns || [])]
if (isEmpty(datasource) || allCols.find(x => x == null)) {
options = false
return
}
// Fetch, filter and sort data
const schema = await fetchSchema(datasource.tableId)
const result = await fetchData(datasource, $store)
const reducer = row => (valid, column) => valid && row[column] != null
const hasAllColumns = row => allCols.reduce(reducer(row), true)
const data = result
.filter(row => hasAllColumns(row))
.slice(0, 100)
.sort((a, b) => (a[labelColumn] > b[labelColumn] ? 1 : -1))
if (!schema || !data.length) {
options = false
return
}
// Initialise default chart
let builder = new ApexOptionsBuilder()
.title(title)
.type(area ? "area" : "line")
.width(width)
.height(height)
.xLabel(xAxisLabel)
.yLabel(yAxisLabel)
.dataLabels(dataLabels)
.animate(animate)
.curve(curve.toLowerCase())
.gradient(gradient)
.stacked(stacked)
.legend(legend)
.yUnits(yAxisUnits)
.palette(palette)
// Add data
let useDates = false
if (datasource.type !== "view" && schema[labelColumn]) {
const labelFieldType = schema[labelColumn].type
builder = builder.xType(labelFieldType)
useDates = labelFieldType === "datetime"
}
const series = valueColumns.map(column => ({
name: column,
data: data.map(row => {
if (!useDates) {
return row[column]
} else {
return [row[labelColumn], row[column]]
}
}),
}))
builder = builder.series(series)
if (!useDates) {
builder = builder.categories(data.map(row => row[labelColumn]))
}
// Build chart options
options = builder.getOptions()
})
</script>
<ApexChart {options} />

View File

@ -0,0 +1,66 @@
<script>
import { onMount } from "svelte"
import fetchData, { fetchSchema } from "../fetchData"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
import ApexChart from "./ApexChart.svelte"
import { isEmpty } from "lodash/fp"
export let _bb
export let title
export let datasource
export let labelColumn
export let valueColumn
export let height
export let width
export let color
export let dataLabels
export let animate
export let legend
export let donut
export let palette
const store = _bb.store
let options
// Fetch data on mount
onMount(async () => {
if (isEmpty(datasource) || !labelColumn || !valueColumn) {
options = false
return
}
// Fetch, filter and sort data
const schema = await fetchSchema(datasource.tableId)
const result = await fetchData(datasource, $store)
const data = result
.filter(row => row[labelColumn] != null && row[valueColumn] != null)
.slice(0, 20)
.sort((a, b) => (a[labelColumn] > b[labelColumn] ? 1 : -1))
if (!schema || !data.length) {
options = false
return
}
// Initialise default chart
let builder = new ApexOptionsBuilder()
.title(title)
.type(donut ? "donut" : "pie")
.width(width)
.height(height)
.dataLabels(dataLabels)
.animate(animate)
.legend(legend)
.legendPosition("right")
.palette(palette)
// Add data if valid datasource
const series = data.map(row => parseFloat(row[valueColumn]))
const labels = data.map(row => row[labelColumn])
builder = builder.series(series).labels(labels)
// Build chart options
options = builder.getOptions()
})
</script>
<ApexChart {options} />

View File

@ -1,187 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,103 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
chartContainer.datum(_data).call(chart)
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: aGradient = getChartGradient(areaGradient)
$: lGradient = getChartGradient(lineGradient)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,181 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,176 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
// bindChartTooltip()
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,129 +0,0 @@
<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 table
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 (table) {
await fetchData()
}
chartContainer = select(`.${chartClass}`)
bindChartUIProps()
bindChartEvents()
chartContainer.datum(_data).call(chart)
bindChartTooltip()
}
})
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", 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 = table ? $store[table] : data
$: colorSchema = getColorSchema(color)
</script>
<div bind:this={chartElement} class={chartClass} />
{#if useLegend}
<div class={legendClass} />
{/if}

View File

@ -1,41 +0,0 @@
<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

@ -1,81 +0,0 @@
<script>
import { notNull } from "./utils"
import { onMount } from "svelte"
import { select } from "d3-selection"
import britecharts from "britecharts"
export const tooltip = britecharts.tooltip()
export let chartClass = ""
let tooltipContainer
export let axisTimeCombinations = null
export let dateCustomFormat = null
export let dateFormat = null
export let dateLabel = null
export let locale = null
export let nameLabel = null
export let numberFormat = null
export let shouldShowDateInTitle = false
export let title = "My Tooltip"
export let tooltipOffset = null
export let topicLabel = "values"
export let topicsOrder = null
export let valueLabel = null
export let xAxisValueType = null
onMount(() => {
tooltipContainer = select(
`.${chartClass} .metadata-group .vertical-marker-container`
)
tooltipContainer.datum([]).call(tooltip)
})
$: if (tooltipContainer) {
if (notNull(axisTimeCombinations)) {
tooltip.axisTimeCombinations(axisTimeCombinations)
}
if (notNull(dateCustomFormat)) {
tooltip.dateCustomFormat(dateCustomFormat)
}
if (notNull(dateFormat)) {
tooltip.dateFormat(dateFormat)
}
if (notNull(dateLabel)) {
tooltip.dateLabel(dateLabel)
}
if (notNull(locale)) {
tooltip.locale(locale)
}
if (notNull(nameLabel)) {
tooltip.nameLabel(nameLabel)
}
if (notNull(numberFormat)) {
tooltip.numberFormat(numberFormat)
}
if (notNull(shouldShowDateInTitle)) {
tooltip.shouldShowDateInTitle(shouldShowDateInTitle)
}
if (notNull(title)) {
tooltip.title(title)
}
if (notNull(tooltipOffset)) {
tooltip.tooltipOffset(tooltipOffset)
}
if (notNull(topicLabel)) {
tooltip.topicLabel(topicLabel)
}
if (notNull(topicsOrder)) {
tooltip.topicsOrder(topicsOrder)
}
if (notNull(valueLabel)) {
tooltip.valueLabel(valueLabel)
}
if (notNull(xAxisValueType)) {
tooltip.xAxisValueType(xAxisValueType)
}
tooltipContainer.datum([]).call(tooltip)
}
</script>

View File

@ -1,14 +1,6 @@
import "britecharts/dist/css/britecharts.min.css"
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"
export { default as bar } from "./BarChart.svelte"
export { default as line } from "./LineChart.svelte"
export { default as pie } from "./PieChart.svelte"
export { default as donut } from "./DonutChart.svelte"
export { default as area } from "./AreaChart.svelte"
export { default as candlestick } from "./CandleStickChart.svelte"

View File

@ -1,72 +0,0 @@
<!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="../../../node_modules/britecharts/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

@ -1,235 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML Line</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/line.min.js"
type="text/javascript"></script> -->
<script src="../../../node_modules/britecharts/dist/umd/line.min.js" type="text/javascript"></script>
<script src="../../../node_modules/britecharts/dist/umd/tooltip.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>
<div class="js-line-chart-container line-chart-container card--chart"></div>
</article>
<script>
const testData = {
data: [
{
amount: 8,
audited: new Date("2020-01-01T16:00:00-08:00"),
city: "Belfast",
name: 1,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "ceb87054790f480e80512368545755bb",
_rev: "2-56e401ebaf59e6310b85fb0c6c2fece5",
},
{
amount: 12,
audited: new Date("2020-01-03T16:00:00-08:00"),
city: "Belfast",
name: 1,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "0a36103b55124f348a23d10b2f3ed0e3",
_rev: "2-50d62530b2edfc63d5fd0b3719dbb286",
},
{
amount: 6,
audited: new Date("2020-01-04T16:00:00-08:00"),
city: "Belfast",
name: 1,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "68ade2bb94754caa8fc62c7084e3cef7",
_rev: "2-a03fe02f3595920adfbcd9c70564fe9d",
},
{
amount: 2,
audited: new Date("2020-01-01T16:00:00-08:00"),
city: "Dublin",
name: 2,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "2ab6dabf833f4d99b3438fa4353ba429",
_rev: "2-45b190489e76842981902cc9f04369ec",
},
{
amount: 16,
audited: new Date("2020-01-02T16:00:00-08:00"),
city: "Dublin",
name: 2,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "1b2ca36db1724427a98ba95547f946e0",
_rev: "2-c43def17ada959948b9af5484ad5b6b7",
},
{
amount: 7,
audited: new Date("2020-01-03T16:00:00-08:00"),
city: "Dublin",
name: 2,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "d9235d884a224ca68ac30cefdbb8ae53",
_rev: "2-695e426a261a25474cbf6b1f069dccb4",
},
{
amount: 3,
audited: new Date("2020-01-04T16:00:00-08:00"),
city: "Dublin",
name: 2,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "9f8bc39a9cfb4f779da8c998d7622927",
_rev: "2-8ae1aff82e1ffc6ffa75f6b9d074e003",
},
{
amount: 4,
audited: new Date("2020-01-02T16:00:00-08:00"),
city: "London",
name: 3,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "75274e906073493bbf75cda8656e8db0",
_rev: "2-6cfc6bb2fccb83c92b50aa5507f2a092"
},
{
amount: 22,
audited: new Date("2020-01-06T16:00:00-08:00"),
city: "London",
name: 3,
tableId: "2334751ac0764c1a931bff5b6b6767eb",
type: "row",
_id: "da3d4b151bc641f4ace487a2314d2550",
_rev: "2-ac18490eaa016be0e71bd4c4ea332981",
}
]
}
const topicLabel = "city"
const valueLabel = "amount"
const dateLabel = "audited"
function prepareData() {
let dataByTopic = []
testData.data.forEach((data, idx, arr) => {
let topicName = data[topicLabel]
if(!dataByTopic.some(dt => dt.topicName === topicName)) {
let d = {topicName, topic: dataByTopic.length + 1, dates: arr.filter(d => d[topicLabel] === topicName).map(d => ({date: d[dateLabel], value: d[valueLabel]}))}
dataByTopic.push(d)
}
})
return {dataByTopic}
}
const newData = prepareData()
const dataByTopic = {
dataByTopic: [
{
topicName: 'San Francisco',
topic: 123,
dates: [
{
date: '2017-01-16T16:00:00-08:00',
value: 1
},
{
date: '2017-01-16T17:00:00-08:00',
value: 2
}
]
},
{
topicName: 'Belfast',
topic: 456,
dates: [
{
date: '2017-01-16T16:00:00-08:00',
value: 5
},
{
date: '2017-01-16T17:00:00-08:00',
value: 8
}
]
}
]
}
const data = {
data: [
{
topicName: "Oakland",
name: 2,
date: "2017-01-16T16:00:00-08:00",
value: 3,
},
{
topicName: "Oakland",
name: 2,
date: "2017-01-17T16:00:00-08:00",
value: 7,
},
{
topicName: "Oakland",
name: 2,
date: "2017-01-18T16:00:00-08:00",
value: 5,
},
{
topicName: "Oakland",
name: 2,
date: "2017-01-19T16:00:00-08:00",
value: 6,
},
{
topicName: "Oakland",
name: 2,
date: "2017-01-20T16:00:00-08:00",
value: 1,
},
],
}
const lineContainer = d3.select('.js-line-chart-container');
const lineChart = britecharts.line()
const tooltip = britecharts.tooltip()
lineChart.grid("horizontal").aspectRatio(0.5).isAnimated(true).shouldShowAllDataPoints(true)
lineContainer.datum(newData).call(lineChart);
const tooltipContainer = d3.select(`.js-line-chart-container .metadata-group .vertical-marker-container`)
tooltip.title("yeooo")
tooltip.topicLabel("topics")
lineChart.on("customMouseOver", tooltip.show)
lineChart.on("customMouseMove", tooltip.update)
lineChart.on("customMouseOut", tooltip.hide)
tooltipContainer.datum([]).call(tooltip)
</script>
</body>
</html>

View File

@ -1,41 +0,0 @@
import britecharts from "britecharts"
export const notNull = value => value || value === false
export const hasProp = (data, prop) => data.every(d => prop in d)
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
export function reformatDataKey(data = [], dataKey = null, formatKey = null) {
let ignoreList = ["_id", "_rev", "id"]
if (dataKey && data.every(d => d[dataKey])) {
return data.map(d => {
let clonedRow = { ...d }
if (clonedRow[formatKey]) {
delete clonedRow[formatKey]
}
let value = clonedRow[dataKey]
if (!ignoreList.includes(dataKey)) {
delete clonedRow[dataKey]
}
clonedRow[formatKey] = value
return clonedRow
})
} else {
return data
}
}

View File

@ -1,49 +0,0 @@
<script>
import { onMount } from "svelte"
import FusionCharts from "fusioncharts"
import Charts from "fusioncharts/fusioncharts.charts"
import FusionTheme from "fusioncharts/themes/fusioncharts.theme.fusion"
import SvelteFC, { fcRoot } from "svelte-fusioncharts"
fcRoot(FusionCharts, Charts, FusionTheme)
export let _bb
export let table
export let type = "column2d"
let store = _bb.store
$: chartConfigs = {
type,
width: "600",
height: "400",
dataFormat: "json",
dataSource: {
data: $store[table] || [],
},
}
$: console.log("CHART CONFIGS", chartConfigs)
async function fetchData() {
const FETCH_ROWS_URL = `/api/views/all_${table}`
const response = await _bb.api.get(FETCH_ROWS_URL)
if (response.status === 200) {
const json = await response.json()
store.update(state => {
state[table] = json
return state
})
} else {
throw new Error("Failed to fetch rows.", response)
}
}
onMount(async () => {
await fetchData()
})
</script>
<div id="container">
<SvelteFC {...chartConfigs} />
</div>

View File

@ -14,12 +14,12 @@ export default async function fetchData(datasource, store) {
}
// Fetch table schema so we can check for linked rows
if (rows && rows.length) {
const table = await fetchTable()
const keys = Object.keys(table.schema)
if (rows && rows.length && datasource.tableId) {
const schema = await fetchSchema(datasource.tableId)
const keys = Object.keys(schema)
rows.forEach(row => {
for (let key of keys) {
const type = table.schema[key].type
const type = schema[key].type
if (type === "link") {
row[`${key}_count`] = Array.isArray(row[key]) ? row[key].length : 0
} else if (type === "attachment") {
@ -38,12 +38,6 @@ export default async function fetchData(datasource, store) {
return []
}
async function fetchTable() {
const FETCH_TABLE_URL = `/api/tables/${datasource.tableId}`
const response = await api.get(FETCH_TABLE_URL)
return await response.json()
}
async function fetchTableData() {
if (!name.startsWith("all_")) {
throw new Error("Incorrect table convention - must begin with all_")
@ -85,3 +79,9 @@ export default async function fetchData(datasource, store) {
return row[datasource.fieldName]
}
}
export async function fetchSchema(id) {
const FETCH_TABLE_URL = `/api/tables/${id}`
const response = await api.get(FETCH_TABLE_URL)
return (await response.json()).schema
}

View File

@ -5,7 +5,6 @@ export { default as text } from "./Text.svelte"
export { default as heading } from "./Heading.svelte"
export { default as input } from "./Input.svelte"
export { default as textfield } from "./Textfield.svelte"
export { default as button } from "./Button.svelte"
export { default as login } from "./Login.svelte"
export { default as saveRowButton } from "./Templates/saveRowButton"
@ -15,7 +14,6 @@ export { default as Navigation } from "./Navigation.svelte"
export { default as datagrid } from "./DataGrid/Component.svelte"
export { default as dataform } from "./DataForm.svelte"
export { default as dataformwide } from "./DataFormWide.svelte"
export { default as datachart } from "./DataChart.svelte"
export { default as datalist } from "./DataList.svelte"
export { default as list } from "./List.svelte"
export { default as datasearch } from "./DataSearch.svelte"
@ -26,5 +24,5 @@ export { default as cardhorizontal } from "./CardHorizontal.svelte"
export { default as rowdetail } from "./RowDetail.svelte"
export { default as newrow } from "./NewRow.svelte"
export { default as datepicker } from "./DatePicker.svelte"
export * from "./Chart"
export { default as icon } from "./Icon.svelte"
export * from "./Chart"