wip
This commit is contained in:
parent
d0fd19a0bc
commit
ab40e3babd
|
@ -9,6 +9,8 @@
|
||||||
export let options = []
|
export let options = []
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = option => option
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = option => option
|
||||||
|
export let getOptionsIcon = () => null
|
||||||
|
export let getOptionsIconToolip = () => null
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let autocomplete = false
|
export let autocomplete = false
|
||||||
export let sort = false
|
export let sort = false
|
||||||
|
@ -80,6 +82,8 @@
|
||||||
|
|
||||||
<Picker
|
<Picker
|
||||||
on:loadMore
|
on:loadMore
|
||||||
|
{getOptionsIcon}
|
||||||
|
{getOptionsIconTooltip}
|
||||||
{id}
|
{id}
|
||||||
{disabled}
|
{disabled}
|
||||||
{readonly}
|
{readonly}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = option => option
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = option => option
|
||||||
export let getOptionIcon = () => null
|
export let getOptionIcon = () => null
|
||||||
|
export let getOptionIconTooltip = () => null
|
||||||
export let useOptionIconImage = false
|
export let useOptionIconImage = false
|
||||||
export let getOptionColour = () => null
|
export let getOptionColour = () => null
|
||||||
export let getOptionSubtitle = () => null
|
export let getOptionSubtitle = () => null
|
||||||
|
@ -202,7 +203,7 @@
|
||||||
>
|
>
|
||||||
{#if getOptionIcon(option, idx)}
|
{#if getOptionIcon(option, idx)}
|
||||||
<span class="option-extra icon">
|
<span class="option-extra icon">
|
||||||
{#if useOptionIconImage}
|
{#if useoptioniconimage}
|
||||||
<img
|
<img
|
||||||
src={getOptionIcon(option, idx)}
|
src={getOptionIcon(option, idx)}
|
||||||
alt="icon"
|
alt="icon"
|
||||||
|
|
|
@ -9,8 +9,10 @@ import TableSelect from "./controls/TableSelect.svelte"
|
||||||
import ColorPicker from "./controls/ColorPicker.svelte"
|
import ColorPicker from "./controls/ColorPicker.svelte"
|
||||||
import { IconSelect } from "./controls/IconSelect"
|
import { IconSelect } from "./controls/IconSelect"
|
||||||
import FieldSelect from "./controls/FieldSelect.svelte"
|
import FieldSelect from "./controls/FieldSelect.svelte"
|
||||||
|
import ChartFieldSelect from "./controls/ChartFieldSelect.svelte"
|
||||||
import SortableFieldSelect from "./controls/SortableFieldSelect.svelte"
|
import SortableFieldSelect from "./controls/SortableFieldSelect.svelte"
|
||||||
import MultiFieldSelect from "./controls/MultiFieldSelect.svelte"
|
import MultiFieldSelect from "./controls/MultiFieldSelect.svelte"
|
||||||
|
import ChartMultiFieldSelect from "./controls/ChartMultiFieldSelect.svelte"
|
||||||
import SearchFieldSelect from "./controls/SearchFieldSelect.svelte"
|
import SearchFieldSelect from "./controls/SearchFieldSelect.svelte"
|
||||||
import SchemaSelect from "./controls/SchemaSelect.svelte"
|
import SchemaSelect from "./controls/SchemaSelect.svelte"
|
||||||
import SectionSelect from "./controls/SectionSelect.svelte"
|
import SectionSelect from "./controls/SectionSelect.svelte"
|
||||||
|
@ -46,7 +48,9 @@ const componentMap = {
|
||||||
color: ColorPicker,
|
color: ColorPicker,
|
||||||
icon: IconSelect,
|
icon: IconSelect,
|
||||||
field: FieldSelect,
|
field: FieldSelect,
|
||||||
|
chartfield: ChartFieldSelect,
|
||||||
multifield: MultiFieldSelect,
|
multifield: MultiFieldSelect,
|
||||||
|
chartmultifield: ChartMultiFieldSelect,
|
||||||
searchfield: SearchFieldSelect,
|
searchfield: SearchFieldSelect,
|
||||||
options: OptionsEditor,
|
options: OptionsEditor,
|
||||||
schema: SchemaSelect,
|
schema: SchemaSelect,
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<script>
|
||||||
|
import { Select } from "@budibase/bbui"
|
||||||
|
import {
|
||||||
|
getDatasourceForProvider,
|
||||||
|
getSchemaForDatasource,
|
||||||
|
} from "dataBinding"
|
||||||
|
import { selectedScreen } from "stores/builder"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let componentInstance = {}
|
||||||
|
export let value = ""
|
||||||
|
export let placeholder
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
||||||
|
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
||||||
|
$: options = Object.keys(schema || {}).filter(key => {
|
||||||
|
return (
|
||||||
|
schema[key].type !== "json" &&
|
||||||
|
schema[key].type !== "array" &&
|
||||||
|
schema[key].type !== "attachment" &&
|
||||||
|
schema[key].type !== "barcodeqr" &&
|
||||||
|
schema[key].type !== "link" &&
|
||||||
|
schema[key].type !== "bb_reference"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$: boundValue = getValidValue(value, options)
|
||||||
|
|
||||||
|
const getValidValue = (value, options) => {
|
||||||
|
// Reset value if there aren't any options
|
||||||
|
if (!Array.isArray(options)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset value if the value isn't found in the options
|
||||||
|
if (options.indexOf(value) === -1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = value => {
|
||||||
|
boundValue = getValidValue(value.detail, options)
|
||||||
|
dispatch("change", boundValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
console.log(options, schema);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select {placeholder} value={boundValue} on:change={onChange} {options} />
|
|
@ -0,0 +1,48 @@
|
||||||
|
<script>
|
||||||
|
import { Multiselect } from "@budibase/bbui"
|
||||||
|
import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding"
|
||||||
|
import { selectedScreen } from "stores/builder"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
|
export let componentInstance = {}
|
||||||
|
export let value = ""
|
||||||
|
export let placeholder
|
||||||
|
export let fieldValidator
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
$: datasource = getDatasourceForProvider($selectedScreen, componentInstance)
|
||||||
|
$: schema = getSchemaForDatasource($selectedScreen, datasource).schema
|
||||||
|
|
||||||
|
const getOptions = (schema, fieldValidator) => {
|
||||||
|
if (fieldValidator != null) {
|
||||||
|
return Object.keys(schema || {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: options = Object.keys(schema || {}).filter(key => {
|
||||||
|
return (
|
||||||
|
schema[key].type !== "json" &&
|
||||||
|
schema[key].type !== "array" &&
|
||||||
|
schema[key].type !== "attachment" &&
|
||||||
|
schema[key].type !== "barcodeqr" &&
|
||||||
|
schema[key].type !== "link" &&
|
||||||
|
schema[key].type !== "bb_reference"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$: boundValue = getValidOptions(value, options)
|
||||||
|
|
||||||
|
const getValidOptions = (selectedOptions, allOptions) => {
|
||||||
|
// Fix the hardcoded default string value
|
||||||
|
if (!Array.isArray(selectedOptions)) {
|
||||||
|
selectedOptions = []
|
||||||
|
}
|
||||||
|
return selectedOptions.filter(val => allOptions.indexOf(val) !== -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setValue = value => {
|
||||||
|
boundValue = getValidOptions(value.detail, options)
|
||||||
|
dispatch("change", boundValue)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Multiselect {placeholder} value={boundValue} on:change={setValue} {options} />
|
|
@ -0,0 +1,42 @@
|
||||||
|
export const unsupported = Symbol("values-validator-unsupported")
|
||||||
|
export const partialSupport = Symbol("values-validator-partial-support")
|
||||||
|
export const supported = Symbol("values-validator-supported")
|
||||||
|
|
||||||
|
const validatorMap = {
|
||||||
|
chart: (fieldSchema) => {
|
||||||
|
if (
|
||||||
|
fieldSchema.type === "json" ||
|
||||||
|
fieldSchema.type === "array" ||
|
||||||
|
fieldSchema.type === "attachment" ||
|
||||||
|
fieldSchema.type === "barcodeqr" ||
|
||||||
|
fieldSchema.type === "link" ||
|
||||||
|
fieldSchema.type === "bb_reference"
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
support: unsupported,
|
||||||
|
message: "This field cannot be used as a chart value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldSchema.type === "string") {
|
||||||
|
return {
|
||||||
|
support: partialSupport,
|
||||||
|
message: "This field can be used as a chart value, but non-numeric values will not be parsed correctly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldSchema.type === "number") {
|
||||||
|
return {
|
||||||
|
support: supported,
|
||||||
|
message: "This field can be used for chart values"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
support: partialSupport,
|
||||||
|
message: "This field can be used as a chart value, but it may not be parsed correctly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default validatorMap;
|
||||||
|
|
|
@ -191,6 +191,9 @@
|
||||||
// Number fields
|
// Number fields
|
||||||
min: setting.min ?? null,
|
min: setting.min ?? null,
|
||||||
max: setting.max ?? null,
|
max: setting.max ?? null,
|
||||||
|
|
||||||
|
// Field select settings
|
||||||
|
fieldValidator: setting.fieldValidator,
|
||||||
}}
|
}}
|
||||||
{bindings}
|
{bindings}
|
||||||
{componentBindings}
|
{componentBindings}
|
||||||
|
|
|
@ -1629,10 +1629,11 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
"fieldValidator": "chart",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1787,7 +1788,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
@ -1940,7 +1941,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
@ -2105,8 +2106,8 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Data columns",
|
"label": "Data column",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"required": true
|
"required": true
|
||||||
|
@ -2234,7 +2235,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
@ -2363,28 +2364,28 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Open column",
|
"label": "Open column",
|
||||||
"key": "openColumn",
|
"key": "openColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Close column",
|
"label": "Close column",
|
||||||
"key": "closeColumn",
|
"key": "closeColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "High column",
|
"label": "High column",
|
||||||
"key": "highColumn",
|
"key": "highColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Low column",
|
"label": "Low column",
|
||||||
"key": "lowColumn",
|
"key": "lowColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
@ -2448,7 +2449,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Data column",
|
"label": "Data column",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataProvider",
|
"dependsOn": "dataProvider",
|
||||||
|
@ -5265,7 +5266,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Data column",
|
"label": "Data column",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5290,7 +5291,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Data column",
|
"label": "Data column",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5315,7 +5316,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5362,7 +5363,7 @@
|
||||||
},
|
},
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Value column",
|
"label": "Value column",
|
||||||
"key": "valueColumn",
|
"key": "valueColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5410,7 +5411,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5459,7 +5460,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "multifield",
|
"type": "chartmultifield",
|
||||||
"label": "Data columns",
|
"label": "Data columns",
|
||||||
"key": "valueColumns",
|
"key": "valueColumns",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
@ -5520,28 +5521,28 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Open column",
|
"label": "Open column",
|
||||||
"key": "openColumn",
|
"key": "openColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Close column",
|
"label": "Close column",
|
||||||
"key": "closeColumn",
|
"key": "closeColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "High column",
|
"label": "High column",
|
||||||
"key": "highColumn",
|
"key": "highColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "chartfield",
|
||||||
"label": "Low column",
|
"label": "Low column",
|
||||||
"key": "lowColumn",
|
"key": "lowColumn",
|
||||||
"dependsOn": "dataSource",
|
"dependsOn": "dataSource",
|
||||||
|
|
|
@ -32,11 +32,12 @@
|
||||||
"@spectrum-css/tag": "^3.1.4",
|
"@spectrum-css/tag": "^3.1.4",
|
||||||
"@spectrum-css/typography": "^3.0.2",
|
"@spectrum-css/typography": "^3.0.2",
|
||||||
"@spectrum-css/vars": "^3.0.1",
|
"@spectrum-css/vars": "^3.0.1",
|
||||||
"apexcharts": "^3.22.1",
|
"apexcharts": "^3.45.2",
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
"downloadjs": "1.4.7",
|
"downloadjs": "1.4.7",
|
||||||
"html5-qrcode": "^2.2.1",
|
"html5-qrcode": "^2.2.1",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"sanitize-html": "^2.7.0",
|
"sanitize-html": "^2.7.0",
|
||||||
"screenfull": "^6.0.1",
|
"screenfull": "^6.0.1",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
|
|
|
@ -283,6 +283,9 @@
|
||||||
const dependsOnKey = setting.dependsOn.setting || setting.dependsOn
|
const dependsOnKey = setting.dependsOn.setting || setting.dependsOn
|
||||||
const dependsOnValue = setting.dependsOn.value
|
const dependsOnValue = setting.dependsOn.value
|
||||||
const realDependentValue = instance[dependsOnKey]
|
const realDependentValue = instance[dependsOnKey]
|
||||||
|
if (dependsOnValue === undefined && realDependentValue) {
|
||||||
|
return missing
|
||||||
|
}
|
||||||
if (dependsOnValue == null && realDependentValue == null) {
|
if (dependsOnValue == null && realDependentValue == null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,104 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { chart } from "svelte-apexcharts"
|
import ApexCharts from 'apexcharts'
|
||||||
import Placeholder from "../Placeholder.svelte"
|
import { Icon } from "@budibase/bbui"
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
|
||||||
const { styleable, builderStore } = getContext("sdk")
|
const { styleable, builderStore } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
export let options
|
export let options
|
||||||
|
/*
|
||||||
|
export let invalid = false
|
||||||
|
|
||||||
|
const parseValue = (value) => {
|
||||||
|
// A value like [10, 11, 12] actually would be output by parseInt as `10`, but this behaviour is odd and not something a
|
||||||
|
// reasonable user would expect.
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedValue = parseInt(value, 10);
|
||||||
|
|
||||||
|
if (Number.isNaN(parsedValue)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseOptions = (options) => {
|
||||||
|
const parsedOptions = { series: [], ...cloneDeep(options)}
|
||||||
|
|
||||||
|
// Object form of series, used by most charts
|
||||||
|
if (parsedOptions.series.some(entry => Array.isArray(entry?.data))) {
|
||||||
|
parsedOptions.series = parsedOptions.series.map(entry => ({ ...entry, data: parseValue})parseValue);
|
||||||
|
} else {
|
||||||
|
// Scalar form of series, used by non-axis charts like pie and donut
|
||||||
|
parsedOptions.series = parsedOptions.series.map(parseValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: parsedOptions = parseOptions(options);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let chartElement;
|
||||||
|
let chart;
|
||||||
|
|
||||||
|
const updateChart = async (newOptions) => {
|
||||||
|
try {
|
||||||
|
await chart?.updateOptions(newOptions)
|
||||||
|
} catch(e) {
|
||||||
|
//console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderChart = async (newChartElement) => {
|
||||||
|
try {
|
||||||
|
await chart?.destroy()
|
||||||
|
chart = new ApexCharts(newChartElement, options)
|
||||||
|
await chart.render()
|
||||||
|
} catch(e) {
|
||||||
|
//console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSeriesValid = (series) => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
$: noData = options == null || options?.series?.length === 0
|
||||||
|
$: hide = noData || !seriesValid
|
||||||
|
|
||||||
|
// Call render chart upon changes to hide, as apex charts has issues with rendering upon changes automatically
|
||||||
|
// if the chart is hidden.
|
||||||
|
$: renderChart(chartElement, hide)
|
||||||
|
$: updateChart(options)
|
||||||
|
$: seriesValid = isSeriesValid(options?.series || [])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if options}
|
{#key options?.customColor}
|
||||||
{#key options.customColor}
|
<div class:hide use:styleable={$component.styles} bind:this={chartElement} />
|
||||||
<div use:chart={options} use:styleable={$component.styles} />
|
{#if $builderStore.inBuilder && noData }
|
||||||
{/key}
|
<div class="component-placeholder" use:styleable={{ ...$component.styles, normal: {}, custom: null, empty: true }}>
|
||||||
{:else if $builderStore.inBuilder}
|
<Icon name="Alert" color="var(--spectrum-global-color-static-red-600)" />
|
||||||
<div use:styleable={$component.styles}>
|
Add rows to your data source to start using your component
|
||||||
<Placeholder />
|
</div>
|
||||||
</div>
|
{:else if $builderStore.inBuilder && !seriesValid}
|
||||||
{/if}
|
<div class="component-placeholder" use:styleable={{ ...$component.styles, normal: {}, custom: null, empty: true }}>
|
||||||
|
<Icon name="Alert" color="var(--spectrum-global-color-static-red-600)" />
|
||||||
|
Your selected data cannot be displayed in this chart
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{/key}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
div :global(.apexcharts-legend-series) {
|
div :global(.apexcharts-legend-series) {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
|
@ -59,4 +138,25 @@
|
||||||
) {
|
) {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--spectrum-global-color-gray-600);
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
padding: var(--spacing-xs);
|
||||||
|
gap: var(--spacing-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common styles for all error states to use */
|
||||||
|
.component-placeholder :global(mark) {
|
||||||
|
background-color: var(--spectrum-global-color-gray-400);
|
||||||
|
padding: 0 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
.component-placeholder :global(.spectrum-Link) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,6 +7,9 @@ export class ApexOptionsBuilder {
|
||||||
}
|
}
|
||||||
this.options = {
|
this.options = {
|
||||||
series: [],
|
series: [],
|
||||||
|
noData:{
|
||||||
|
text: "no data to show"
|
||||||
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: false,
|
show: false,
|
||||||
position: "top",
|
position: "top",
|
||||||
|
@ -99,7 +102,8 @@ export class ApexOptionsBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
series(series) {
|
series(series) {
|
||||||
return this.setOption(["series"], series)
|
const foo = this.setOption(["series"], series)
|
||||||
|
return foo;
|
||||||
}
|
}
|
||||||
|
|
||||||
horizontal(horizontal) {
|
horizontal(horizontal) {
|
||||||
|
@ -161,6 +165,15 @@ export class ApexOptionsBuilder {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
candleStick() {
|
||||||
|
//this.options.xaxis.convertedCatToNumeric = false;
|
||||||
|
this.options.xaxis.labels.formatter = (epoch) => {
|
||||||
|
return (new Date(epoch)).toDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
clearXFormatter() {
|
clearXFormatter() {
|
||||||
delete this.options.xaxis.labels
|
delete this.options.xaxis.labels
|
||||||
return this
|
return this
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
|
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
|
||||||
import ApexChart from "./ApexChart.svelte"
|
import ApexChart from "./ApexChart.svelte"
|
||||||
|
import { get } from "lodash";
|
||||||
|
|
||||||
export let title
|
export let title
|
||||||
export let dataProvider
|
export let dataProvider
|
||||||
|
@ -71,9 +72,8 @@
|
||||||
|
|
||||||
// Fetch data
|
// Fetch data
|
||||||
const { schema, rows } = dataProvider
|
const { schema, rows } = dataProvider
|
||||||
const reducer = row => (valid, column) => valid && row[column] != null
|
|
||||||
const hasAllColumns = row => allCols.reduce(reducer(row), true)
|
const data = rows.slice(0, 100)
|
||||||
const data = rows.filter(row => hasAllColumns(row)).slice(0, 100)
|
|
||||||
if (!schema || !data.length) {
|
if (!schema || !data.length) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -105,11 +105,21 @@
|
||||||
}
|
}
|
||||||
useDates = labelFieldType === "datetime"
|
useDates = labelFieldType === "datetime"
|
||||||
}
|
}
|
||||||
const series = valueColumns.map(column => ({
|
const series = (valueColumns ?? []).map(column => ({
|
||||||
name: column,
|
name: column,
|
||||||
data: data.map(row => {
|
data: data.map(row => {
|
||||||
if (!useDates) {
|
if (!useDates) {
|
||||||
return row[column]
|
const value = get(row, column);
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number.isNaN(parseInt(value, 10))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
} else {
|
} else {
|
||||||
return [row[labelColumn], row[column]]
|
return [row[labelColumn], row[column]]
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,14 +76,16 @@
|
||||||
.animate(animate)
|
.animate(animate)
|
||||||
.yUnits(yAxisUnits)
|
.yUnits(yAxisUnits)
|
||||||
.yTooltip(true)
|
.yTooltip(true)
|
||||||
.xType("datetime")
|
//.xType("datetime")
|
||||||
|
.candleStick()
|
||||||
|
|
||||||
// Add data
|
// Add data
|
||||||
|
//const parseDate = d => d
|
||||||
const parseDate = d => (isNaN(d) ? Date.parse(d).valueOf() : parseInt(d))
|
const parseDate = d => (isNaN(d) ? Date.parse(d).valueOf() : parseInt(d))
|
||||||
const chartData = data.map(row => ({
|
const chartData = data.map(row => ([
|
||||||
x: parseDate(row[dateColumn]),
|
parseDate(row[dateColumn]),
|
||||||
y: [row[openColumn], row[highColumn], row[lowColumn], row[closeColumn]],
|
row[openColumn], row[highColumn], row[lowColumn], row[closeColumn]
|
||||||
}))
|
]))
|
||||||
builder = builder.series([{ data: chartData }])
|
builder = builder.series([{ data: chartData }])
|
||||||
|
|
||||||
// Build chart options
|
// Build chart options
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
|
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
|
||||||
import ApexChart from "./ApexChart.svelte"
|
import ApexChart from "./ApexChart.svelte"
|
||||||
|
import { get } from "lodash";
|
||||||
|
|
||||||
// Common props
|
// Common props
|
||||||
export let title
|
export let title
|
||||||
|
@ -80,9 +81,7 @@
|
||||||
|
|
||||||
// Fetch, filter and sort data
|
// Fetch, filter and sort data
|
||||||
const { schema, rows } = dataProvider
|
const { schema, rows } = dataProvider
|
||||||
const reducer = row => (valid, column) => valid && row[column] != null
|
const data = rows
|
||||||
const hasAllColumns = row => allCols.reduce(reducer(row), true)
|
|
||||||
const data = rows.filter(row => hasAllColumns(row))
|
|
||||||
if (!schema || !data.length) {
|
if (!schema || !data.length) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -112,11 +111,21 @@
|
||||||
builder = builder.xType(labelFieldType)
|
builder = builder.xType(labelFieldType)
|
||||||
useDates = labelFieldType === "datetime"
|
useDates = labelFieldType === "datetime"
|
||||||
}
|
}
|
||||||
const series = valueColumns.map(column => ({
|
const series = (valueColumns ?? []).map(column => ({
|
||||||
name: column,
|
name: column,
|
||||||
data: data.map(row => {
|
data: data.map(row => {
|
||||||
if (!useDates) {
|
if (!useDates) {
|
||||||
return row[column]
|
const value = get(row, column);
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number.isNaN(parseInt(value, 10))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
} else {
|
} else {
|
||||||
return [row[labelColumn], row[column]]
|
return [row[labelColumn], row[column]]
|
||||||
}
|
}
|
||||||
|
|
20
yarn.lock
20
yarn.lock
|
@ -6605,6 +6605,11 @@
|
||||||
js-yaml "^3.10.0"
|
js-yaml "^3.10.0"
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@yr/monotone-cubic-spline@^1.0.3":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz#7272d89f8e4f6fb7a1600c28c378cc18d3b577b9"
|
||||||
|
integrity sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==
|
||||||
|
|
||||||
"@zerodevx/svelte-json-view@^1.0.7":
|
"@zerodevx/svelte-json-view@^1.0.7":
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1"
|
resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1"
|
||||||
|
@ -6907,7 +6912,7 @@ anymatch@^3.0.3, anymatch@~3.1.2:
|
||||||
normalize-path "^3.0.0"
|
normalize-path "^3.0.0"
|
||||||
picomatch "^2.0.4"
|
picomatch "^2.0.4"
|
||||||
|
|
||||||
apexcharts@^3.19.2, apexcharts@^3.22.1:
|
apexcharts@^3.19.2:
|
||||||
version "3.37.1"
|
version "3.37.1"
|
||||||
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.37.1.tgz#50443d302fc7fc72aace9c6c4074baae017c6950"
|
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.37.1.tgz#50443d302fc7fc72aace9c6c4074baae017c6950"
|
||||||
integrity sha512-fmQ5Updeb/LASl+S1+mIxXUFxzY0Fa7gexfCs4o+OPP9f2NEBNjvybOtPrah44N4roK7U5o5Jis906QeEQu0cA==
|
integrity sha512-fmQ5Updeb/LASl+S1+mIxXUFxzY0Fa7gexfCs4o+OPP9f2NEBNjvybOtPrah44N4roK7U5o5Jis906QeEQu0cA==
|
||||||
|
@ -6919,6 +6924,19 @@ apexcharts@^3.19.2, apexcharts@^3.22.1:
|
||||||
svg.resize.js "^1.4.3"
|
svg.resize.js "^1.4.3"
|
||||||
svg.select.js "^3.0.1"
|
svg.select.js "^3.0.1"
|
||||||
|
|
||||||
|
apexcharts@^3.45.2:
|
||||||
|
version "3.48.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.48.0.tgz#cf0e18f4551b04a242d81942c965c15547f5f1b6"
|
||||||
|
integrity sha512-Lhpj1Ij6lKlrUke8gf+P+SE6uGUn+Pe1TnCJ+zqrY0YMvbqM3LMb1lY+eybbTczUyk0RmMZomlTa2NgX2EUs4Q==
|
||||||
|
dependencies:
|
||||||
|
"@yr/monotone-cubic-spline" "^1.0.3"
|
||||||
|
svg.draggable.js "^2.2.2"
|
||||||
|
svg.easing.js "^2.0.0"
|
||||||
|
svg.filter.js "^2.0.2"
|
||||||
|
svg.pathmorphing.js "^0.1.3"
|
||||||
|
svg.resize.js "^1.4.3"
|
||||||
|
svg.select.js "^3.0.1"
|
||||||
|
|
||||||
apidoc@0.50.4:
|
apidoc@0.50.4:
|
||||||
version "0.50.4"
|
version "0.50.4"
|
||||||
resolved "https://registry.yarnpkg.com/apidoc/-/apidoc-0.50.4.tgz#52ff8fb4d067a73faf544455031f44459bd68d75"
|
resolved "https://registry.yarnpkg.com/apidoc/-/apidoc-0.50.4.tgz#52ff8fb4d067a73faf544455031f44459bd68d75"
|
||||||
|
|
Loading…
Reference in New Issue