@icij/murmur-next 4.0.18 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/composables/chart.d.ts +3 -2
- package/dist/lib/composables/queryObserver.d.ts +6 -0
- package/dist/lib/datavisualisations/BarChart.vue.d.ts +3 -3
- package/dist/lib/datavisualisations/ColumnChart.vue.d.ts +4 -3
- package/dist/lib/datavisualisations/LineChart.vue.d.ts +1 -1
- package/dist/lib/datavisualisations/StackedBarChart.vue.d.ts +6 -8
- package/dist/lib/datavisualisations/StackedColumnChart.vue.d.ts +7 -6
- package/dist/lib/murmur.css +1 -1
- package/dist/lib/murmur.js +9779 -9756
- package/dist/lib/murmur.js.map +1 -1
- package/dist/lib/murmur.umd.cjs +38 -38
- package/dist/lib/murmur.umd.cjs.map +1 -1
- package/lib/components/TinyPagination.vue +5 -1
- package/lib/composables/chart.ts +57 -38
- package/lib/composables/queryObserver.ts +66 -0
- package/lib/datavisualisations/ColumnChart.vue +13 -18
- package/lib/datavisualisations/StackedBarChart.vue +63 -101
- package/lib/datavisualisations/StackedColumnChart.vue +56 -40
- package/package.json +1 -1
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
<script lang="ts">
|
|
64
64
|
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
|
|
65
|
-
import { defineComponent, PropType, ref, computed, onBeforeMount } from 'vue'
|
|
65
|
+
import { defineComponent, PropType, ref, computed, onBeforeMount, watch } from 'vue'
|
|
66
66
|
import { useI18n } from 'vue-i18n'
|
|
67
67
|
|
|
68
68
|
import { library, default as Fa } from './Fa'
|
|
@@ -187,6 +187,10 @@ export default defineComponent({
|
|
|
187
187
|
|
|
188
188
|
const currentPageInput = ref<number | string>(pageValue.value)
|
|
189
189
|
|
|
190
|
+
watch(() => props.modelValue, (value) => {
|
|
191
|
+
currentPageInput.value = value
|
|
192
|
+
})
|
|
193
|
+
|
|
190
194
|
function applyPageForm(): void {
|
|
191
195
|
if (!isNaN(currentPageInput.value as number)) {
|
|
192
196
|
emit('update:modelValue', +currentPageInput.value)
|
package/lib/composables/chart.ts
CHANGED
|
@@ -4,14 +4,15 @@ import isObject from 'lodash/isObject'
|
|
|
4
4
|
import isString from 'lodash/isString'
|
|
5
5
|
import max from 'lodash/max'
|
|
6
6
|
import some from 'lodash/some'
|
|
7
|
-
import { ComponentPublicInstance, computed,
|
|
7
|
+
import { ComponentPublicInstance, computed, toRef, toValue, ref, watch, onMounted, nextTick } from 'vue'
|
|
8
8
|
import { isUrl } from '@/utils/strings'
|
|
9
9
|
import { Ref, SetupContext } from '@vue/runtime-core'
|
|
10
10
|
import useResizeObserver from '@/composables/resizeObserver'
|
|
11
|
-
import { watchEffect } from 'vue'
|
|
12
11
|
|
|
13
12
|
type ChartContext<T extends string[]> = SetupContext<[...T, ...string[]]>
|
|
13
|
+
|
|
14
14
|
type ChartEmit = Pick<ChartContext<['resized', 'loaded']>, 'emit'>
|
|
15
|
+
|
|
15
16
|
type ChartProps = {
|
|
16
17
|
chartHeightRatio: { type: NumberConstructor }
|
|
17
18
|
data: {
|
|
@@ -28,13 +29,13 @@ type ChartProps = {
|
|
|
28
29
|
socialModeRatio: { default: number; type: NumberConstructor }
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export function getChartProps(props: any):
|
|
32
|
+
export function getChartProps(props: any): any {
|
|
32
33
|
return {
|
|
33
|
-
chartHeightRatio: props
|
|
34
|
-
data: props
|
|
35
|
-
dataUrlType: props
|
|
36
|
-
socialMode: props
|
|
37
|
-
socialModeRatio: props
|
|
34
|
+
chartHeightRatio: toRef(props, 'chartHeightRatio'),
|
|
35
|
+
data: toRef(props, 'data'),
|
|
36
|
+
dataUrlType: toRef(props, 'dataUrlType'),
|
|
37
|
+
socialMode: toRef(props, 'socialMode'),
|
|
38
|
+
socialModeRatio: toRef(props, 'socialModeRatio')
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -76,10 +77,13 @@ export const chartProps = (): ChartProps => ({
|
|
|
76
77
|
default: 5 / 4
|
|
77
78
|
}
|
|
78
79
|
})
|
|
80
|
+
|
|
79
81
|
export const chartEmits = ['resized', 'loaded']
|
|
82
|
+
|
|
80
83
|
type Chart = {
|
|
81
84
|
dataHasHighlights: any
|
|
82
85
|
loadedData: any
|
|
86
|
+
mounted: Ref<boolean>,
|
|
83
87
|
xAxisYearFormat: (year: number | string) => number | string
|
|
84
88
|
elementsMaxBBox: ({
|
|
85
89
|
selector,
|
|
@@ -93,42 +97,51 @@ type Chart = {
|
|
|
93
97
|
d3Formatter: any
|
|
94
98
|
baseHeightRatio: any
|
|
95
99
|
}
|
|
100
|
+
|
|
96
101
|
export function useChart(
|
|
97
102
|
resizableRef: Ref<ComponentPublicInstance<HTMLElement> | null>,
|
|
98
|
-
props:
|
|
103
|
+
props: any,
|
|
99
104
|
{ emit }: ChartEmit,
|
|
100
105
|
isLoaded: Ref<boolean>,
|
|
101
106
|
onResized?: ()=>void,
|
|
102
107
|
afterLoaded?: () => Promise<any>
|
|
103
108
|
): Chart {
|
|
109
|
+
|
|
104
110
|
const { resizeRef, resizeState } = useResizeObserver(resizableRef)
|
|
105
111
|
const loadedData = ref<unknown|unknown[]>([])
|
|
112
|
+
const mounted = ref<boolean>(false)
|
|
113
|
+
const dataRef = toRef(props.data)
|
|
114
|
+
const dataUrlTypeRef = toRef(props.dataUrlType)
|
|
115
|
+
|
|
116
|
+
onMounted(() => {
|
|
117
|
+
nextTick(() => {
|
|
118
|
+
mounted.value = true
|
|
119
|
+
})
|
|
120
|
+
})
|
|
106
121
|
|
|
107
|
-
|
|
122
|
+
watch([dataRef, dataUrlTypeRef], async () => {
|
|
108
123
|
await document.fonts?.ready
|
|
124
|
+
|
|
125
|
+
const data = toValue(dataRef)
|
|
126
|
+
const dataUrlType = toValue(dataUrlTypeRef)
|
|
109
127
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
onResized()
|
|
128
|
-
emit('resized')
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
})
|
|
128
|
+
if (isString(data)) {
|
|
129
|
+
// @ts-expect-error introspection in typescript is tricky
|
|
130
|
+
loadedData.value = await d3[dataUrlType](data)
|
|
131
|
+
} else {
|
|
132
|
+
loadedData.value = data as unknown as []
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await afterLoaded?.()
|
|
136
|
+
isLoaded.value = true
|
|
137
|
+
emit('loaded')
|
|
138
|
+
|
|
139
|
+
if (onResized) {
|
|
140
|
+
onResized()
|
|
141
|
+
emit('resized')
|
|
142
|
+
}
|
|
143
|
+
}, { immediate: true })
|
|
144
|
+
|
|
132
145
|
function elementsMaxBBox({
|
|
133
146
|
selector = 'text',
|
|
134
147
|
defaultWidth = null,
|
|
@@ -160,9 +173,11 @@ export function useChart(
|
|
|
160
173
|
// previously using narrowWidth but it is automatically updated through resizeObserver state reactivity
|
|
161
174
|
return resizeState.narrowWidth ? '’' + String(year).slice(2, 4) : year
|
|
162
175
|
}
|
|
176
|
+
|
|
163
177
|
function highlighted(datum: { highlight: boolean }) {
|
|
164
178
|
return datum.highlight
|
|
165
179
|
}
|
|
180
|
+
|
|
166
181
|
function d3Formatter(value: any, formatter: any) {
|
|
167
182
|
if (isFunction(formatter)) {
|
|
168
183
|
return formatter(value)
|
|
@@ -171,15 +186,18 @@ export function useChart(
|
|
|
171
186
|
}
|
|
172
187
|
return value
|
|
173
188
|
}
|
|
189
|
+
|
|
174
190
|
const baseHeightRatio = computed(() => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
191
|
+
const chartHeightRatio = toValue(props.chartHeightRatio)
|
|
192
|
+
const socialMode = toValue(props.socialMode)
|
|
193
|
+
const socialModeRatio = toValue(props.socialModeRatio)
|
|
194
|
+
return chartHeightRatio || (socialMode ? socialModeRatio : 9 / 16)
|
|
179
195
|
})
|
|
196
|
+
|
|
180
197
|
const dataHasHighlights = computed(() => {
|
|
181
|
-
|
|
182
|
-
|
|
198
|
+
const data = toValue(dataRef)
|
|
199
|
+
if (Array.isArray(data)) {
|
|
200
|
+
return some(data, highlighted)
|
|
183
201
|
}
|
|
184
202
|
return false
|
|
185
203
|
})
|
|
@@ -193,6 +211,7 @@ export function useChart(
|
|
|
193
211
|
|
|
194
212
|
return {
|
|
195
213
|
loadedData,
|
|
214
|
+
mounted,
|
|
196
215
|
elementsMaxBBox,
|
|
197
216
|
xAxisYearFormat,
|
|
198
217
|
d3Formatter,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import get from 'lodash/get'
|
|
2
|
+
import first from 'lodash/first'
|
|
3
|
+
|
|
4
|
+
import { Ref, reactive } from 'vue'
|
|
5
|
+
|
|
6
|
+
type ElementMap = {
|
|
7
|
+
[selector: string]: HTMLElement[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type ObserverMap = {
|
|
11
|
+
[selector: string]: MutationObserver
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useQueryObserver(rootRef: Ref<HTMLElement | null>) {
|
|
15
|
+
const elements = reactive<ElementMap>({})
|
|
16
|
+
const observers = reactive<ObserverMap>({})
|
|
17
|
+
|
|
18
|
+
const hasElements = (selector: string): boolean => {
|
|
19
|
+
return get(elements, [selector, 'length'], 0) > 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const hasObserver = (selector: string): boolean => {
|
|
23
|
+
return selector in observers
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const updateElements = (selector: string): HTMLElement[] | null => {
|
|
27
|
+
// We search for the give selector until element are found
|
|
28
|
+
if (rootRef.value && !hasElements(selector)) {
|
|
29
|
+
elements[selector] = Array.from(rootRef.value.querySelectorAll(selector))
|
|
30
|
+
}
|
|
31
|
+
return elements[selector] ?? null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const observerCallback = (selector: string) => {
|
|
35
|
+
return () => {
|
|
36
|
+
updateElements(selector)
|
|
37
|
+
if (hasElements(selector)) {
|
|
38
|
+
observers[selector].disconnect()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const observe = (selector: string) => {
|
|
44
|
+
updateElements(selector)
|
|
45
|
+
// Wait for the root ref to exist and only create the observer once by selector
|
|
46
|
+
if (rootRef.value && !hasObserver(selector)) {
|
|
47
|
+
observers[selector] = new MutationObserver(observerCallback(selector))
|
|
48
|
+
observers[selector].observe(rootRef.value, { childList: true, subtree: true, })
|
|
49
|
+
}
|
|
50
|
+
return observers[selector]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const querySelector = (selector: string) => {
|
|
54
|
+
return first(querySelectorAll(selector))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const querySelectorAll = (selector: string) => {
|
|
58
|
+
observe(selector)
|
|
59
|
+
return get(elements, selector, [])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
querySelector,
|
|
64
|
+
querySelectorAll,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
ComponentPublicInstance,
|
|
4
|
-
computed,
|
|
5
|
-
defineComponent,
|
|
6
|
-
PropType,
|
|
7
|
-
ref,
|
|
8
|
-
watchEffect,
|
|
9
|
-
onMounted
|
|
10
|
-
} from 'vue'
|
|
2
|
+
import { ComponentPublicInstance, computed, defineComponent, PropType, ref, watch } from 'vue'
|
|
11
3
|
import { identity, iteratee, sortBy } from 'lodash'
|
|
12
4
|
import * as d3 from 'd3'
|
|
13
5
|
import { chartProps, getChartProps, useChart } from '@/composables/chart'
|
|
@@ -19,11 +11,9 @@ type ColumnBar = {
|
|
|
19
11
|
x: number
|
|
20
12
|
y: number
|
|
21
13
|
}
|
|
22
|
-
//import chart from '../mixins/chart'
|
|
23
14
|
|
|
24
15
|
export default defineComponent({
|
|
25
16
|
name: 'ColumnChart',
|
|
26
|
-
//mixins: [chart],
|
|
27
17
|
props: {
|
|
28
18
|
/**
|
|
29
19
|
* Color of each column (uses the CSS variable --column-color by default)
|
|
@@ -177,6 +167,7 @@ export default defineComponent({
|
|
|
177
167
|
const isLoaded = ref(false)
|
|
178
168
|
const {
|
|
179
169
|
loadedData,
|
|
170
|
+
mounted,
|
|
180
171
|
elementsMaxBBox,
|
|
181
172
|
d3Formatter,
|
|
182
173
|
baseHeightRatio,
|
|
@@ -341,9 +332,12 @@ export default defineComponent({
|
|
|
341
332
|
}
|
|
342
333
|
|
|
343
334
|
function update() {
|
|
344
|
-
if (!
|
|
335
|
+
if (!mounted.value) {
|
|
345
336
|
return
|
|
346
337
|
}
|
|
338
|
+
|
|
339
|
+
d3.select('.column-chart__axis > *').remove()
|
|
340
|
+
|
|
347
341
|
d3.select(el.value)
|
|
348
342
|
.select('.column-chart__axis--x')
|
|
349
343
|
.call(xAxis.value as any)
|
|
@@ -368,10 +362,9 @@ export default defineComponent({
|
|
|
368
362
|
datum.highlight || props.highlights.includes(datum[props.timeseriesKey])
|
|
369
363
|
)
|
|
370
364
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
})
|
|
365
|
+
|
|
366
|
+
watch([width, height, loadedData, mounted], update.bind(this), { immediate: true})
|
|
367
|
+
watch(() => props.socialMode, update.bind(this), { immediate: true})
|
|
375
368
|
|
|
376
369
|
return {
|
|
377
370
|
el,
|
|
@@ -380,6 +373,7 @@ export default defineComponent({
|
|
|
380
373
|
height,
|
|
381
374
|
margin,
|
|
382
375
|
padded,
|
|
376
|
+
isLoaded,
|
|
383
377
|
shownTooltip,
|
|
384
378
|
bars,
|
|
385
379
|
select,
|
|
@@ -399,7 +393,8 @@ export default defineComponent({
|
|
|
399
393
|
'column-chart--has-highlights': dataHasHighlights,
|
|
400
394
|
'column-chart--hover': hover,
|
|
401
395
|
'column-chart--stripped': stripped,
|
|
402
|
-
'column-chart--social-mode': socialMode
|
|
396
|
+
'column-chart--social-mode': socialMode,
|
|
397
|
+
'column-chart--loaded': isLoaded
|
|
403
398
|
}"
|
|
404
399
|
:style="{
|
|
405
400
|
'--column-color': columnColor,
|
|
@@ -493,7 +488,7 @@ export default defineComponent({
|
|
|
493
488
|
|
|
494
489
|
&__columns__item {
|
|
495
490
|
fill: var(--column-color, var(--dark, $dark));
|
|
496
|
-
|
|
491
|
+
|
|
497
492
|
&--highlight {
|
|
498
493
|
fill: var(--column-highlight-color, var(--primary, $primary));
|
|
499
494
|
}
|
|
@@ -7,16 +7,9 @@ import kebabCase from 'lodash/kebabCase'
|
|
|
7
7
|
import keys from 'lodash/keys'
|
|
8
8
|
import without from 'lodash/without'
|
|
9
9
|
import sortBy from 'lodash/sortBy'
|
|
10
|
-
import {
|
|
11
|
-
ComponentPublicInstance,
|
|
12
|
-
computed,
|
|
13
|
-
defineComponent,
|
|
14
|
-
nextTick,
|
|
15
|
-
PropType,
|
|
16
|
-
ref,
|
|
17
|
-
watch
|
|
18
|
-
} from 'vue'
|
|
10
|
+
import { ComponentPublicInstance, computed, defineComponent, PropType, ref, watch } from 'vue'
|
|
19
11
|
import { chartProps, getChartProps, useChart } from '@/composables/chart.js'
|
|
12
|
+
import { useQueryObserver } from '@/composables/queryObserver.js'
|
|
20
13
|
import { isArray } from 'lodash'
|
|
21
14
|
|
|
22
15
|
export default defineComponent({
|
|
@@ -147,8 +140,14 @@ export default defineComponent({
|
|
|
147
140
|
const highlightTimeout = ref<NodeJS.Timeout | undefined>(undefined)
|
|
148
141
|
const isLoaded = ref(false)
|
|
149
142
|
const el = ref<ComponentPublicInstance<HTMLElement> | null>(null)
|
|
150
|
-
const {
|
|
151
|
-
|
|
143
|
+
const {
|
|
144
|
+
loadedData,
|
|
145
|
+
mounted,
|
|
146
|
+
baseHeightRatio,
|
|
147
|
+
d3Formatter,
|
|
148
|
+
dataHasHighlights
|
|
149
|
+
} = useChart(el, getChartProps(props), { emit }, isLoaded)
|
|
150
|
+
const { querySelectorAll } = useQueryObserver(el)
|
|
152
151
|
|
|
153
152
|
const hasConstraintHeight = computed(() => {
|
|
154
153
|
return props.fixedHeight !== null || props.socialMode
|
|
@@ -162,6 +161,7 @@ export default defineComponent({
|
|
|
162
161
|
? loadedData.value
|
|
163
162
|
: sortBy(loadedData.value, props.sortBy)
|
|
164
163
|
})
|
|
164
|
+
|
|
165
165
|
const discoveredKeys = computed((): any[] => {
|
|
166
166
|
if (props.keys.length) {
|
|
167
167
|
return props.keys
|
|
@@ -177,22 +177,30 @@ export default defineComponent({
|
|
|
177
177
|
.domain(discoveredKeys.value)
|
|
178
178
|
.range(props.barColors)
|
|
179
179
|
})
|
|
180
|
+
|
|
180
181
|
const maxValue = computed(() => {
|
|
181
182
|
return d3.max(loadedData.value || [], (datum, i) => {
|
|
182
183
|
return totalRowValue(i)
|
|
183
184
|
})
|
|
184
185
|
})
|
|
186
|
+
|
|
185
187
|
const hasHighlights = computed(() => {
|
|
186
188
|
return !!highlightedKeys.value.length
|
|
187
189
|
})
|
|
190
|
+
|
|
188
191
|
const hasRowHighlights = computed(() => {
|
|
189
192
|
return !!props.rowHighlights.length
|
|
190
193
|
})
|
|
194
|
+
|
|
195
|
+
const hasAnyHighlights = computed(() => {
|
|
196
|
+
return hasHighlights.value || hasRowHighlights.value || dataHasHighlights.value
|
|
197
|
+
})
|
|
198
|
+
|
|
191
199
|
const height = computed(() => {
|
|
192
200
|
if (props.fixedHeight !== null) {
|
|
193
201
|
return `${props.fixedHeight}px`
|
|
194
202
|
}
|
|
195
|
-
return props.socialMode && el.value
|
|
203
|
+
return props.socialMode && mounted.value && el.value
|
|
196
204
|
? `${el.value.offsetWidth * baseHeightRatio.value}px`
|
|
197
205
|
: 'auto'
|
|
198
206
|
})
|
|
@@ -258,14 +266,10 @@ export default defineComponent({
|
|
|
258
266
|
return { width, backgroundColor }
|
|
259
267
|
}
|
|
260
268
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
// }
|
|
264
|
-
async function stackBarAndValue(i: number | string) {
|
|
265
|
-
if (!sortedData.value) {
|
|
269
|
+
function stackBarAndValue(i: number | string) {
|
|
270
|
+
if (!mounted.value) {
|
|
266
271
|
return []
|
|
267
272
|
}
|
|
268
|
-
await nextTick()
|
|
269
273
|
// Collect sizes first
|
|
270
274
|
const stack = discoveredKeys.value.map((key: string) => {
|
|
271
275
|
const { bar, row, value } = queryBarAndValue(i as number, key)
|
|
@@ -276,31 +280,34 @@ export default defineComponent({
|
|
|
276
280
|
const barWidth = bar.offsetWidth
|
|
277
281
|
const rowEdge = row.getBoundingClientRect().left + row.offsetWidth
|
|
278
282
|
const valueWidth = value.offsetWidth
|
|
279
|
-
|
|
283
|
+
const overflow = false
|
|
284
|
+
const pushed = false
|
|
285
|
+
return { key, barEdge, barWidth, rowEdge, valueWidth, overflow, pushed }
|
|
280
286
|
})
|
|
281
287
|
// Infer value's display
|
|
282
288
|
return stack.map((desc, index) => {
|
|
289
|
+
// Value must be visible out of the bar (overflow) if the size of the value label is bigger than the bar
|
|
283
290
|
desc.overflow = desc.valueWidth >= desc.barWidth
|
|
284
|
-
|
|
291
|
+
// If the value not out of the bar, we must ensure its predecesor isn't.
|
|
292
|
+
if (!desc.overflow && index > 0) {
|
|
285
293
|
const prevDesc = stack[index - 1]
|
|
286
294
|
const bothValuesWidth = desc.valueWidth + prevDesc.valueWidth
|
|
287
|
-
desc.overflow =
|
|
288
|
-
desc.overflow ||
|
|
289
|
-
(prevDesc.overflow && desc.barWidth < bothValuesWidth)
|
|
295
|
+
desc.overflow = prevDesc.overflow && desc.barWidth < bothValuesWidth
|
|
290
296
|
}
|
|
291
|
-
|
|
292
|
-
|
|
297
|
+
// Value must be pushed to the other side (left) if the value label is outside of the bar (overflow)
|
|
298
|
+
// and if the size of the value label isn't fitting in the row
|
|
299
|
+
desc.pushed = desc.overflow && desc.barEdge + desc.valueWidth > desc.rowEdge
|
|
293
300
|
return desc
|
|
294
301
|
})
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
function queryBarAndValue(i: number, key: string) {
|
|
298
|
-
if (!
|
|
305
|
+
if (!mounted.value) {
|
|
299
306
|
return {}
|
|
300
307
|
}
|
|
301
308
|
const barClass = 'stacked-bar-chart__groups__item__bars__item'
|
|
302
309
|
const rowSelector = '.stacked-bar-chart__groups__item'
|
|
303
|
-
const row =
|
|
310
|
+
const row = querySelectorAll(rowSelector)[i] as HTMLElement
|
|
304
311
|
const normalizedKey = normalizeKey(key)
|
|
305
312
|
const barSelector = `.${barClass}--${normalizedKey}`
|
|
306
313
|
const bar = row?.querySelector(barSelector) as HTMLElement
|
|
@@ -309,24 +316,32 @@ export default defineComponent({
|
|
|
309
316
|
return { bar, row, value }
|
|
310
317
|
}
|
|
311
318
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
319
|
+
function hasValueOverflow(i: number | string, key: string) {
|
|
320
|
+
try {
|
|
321
|
+
const stack = stackBarAndValue(i)
|
|
322
|
+
return find(stack, { key })?.overflow
|
|
323
|
+
} catch {
|
|
324
|
+
return false
|
|
325
|
+
}
|
|
315
326
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
327
|
+
|
|
328
|
+
function hasValuePushed(i: number | string, key: string) {
|
|
329
|
+
try {
|
|
330
|
+
const stack = stackBarAndValue(i)
|
|
331
|
+
return find(stack, { key })?.pushed
|
|
332
|
+
} catch {
|
|
333
|
+
return false
|
|
334
|
+
}
|
|
320
335
|
}
|
|
321
336
|
|
|
322
|
-
|
|
337
|
+
function hasValueHidden(i: number | string, key: string) {
|
|
323
338
|
const keyIndex = discoveredKeys.value.indexOf(key)
|
|
324
339
|
const nextKey = discoveredKeys.value[keyIndex + 1]
|
|
325
340
|
if (!nextKey) {
|
|
326
341
|
return false
|
|
327
342
|
}
|
|
328
|
-
const keyC =
|
|
329
|
-
const keyN =
|
|
343
|
+
const keyC = hasValueOverflow(i, key)
|
|
344
|
+
const keyN = hasValueOverflow(i, nextKey)
|
|
330
345
|
return keyC && keyN
|
|
331
346
|
}
|
|
332
347
|
|
|
@@ -334,47 +349,20 @@ export default defineComponent({
|
|
|
334
349
|
return props.hideEmptyValues && !sortedData.value[i][key]
|
|
335
350
|
}
|
|
336
351
|
|
|
337
|
-
// async function barItemClasses(i,key){
|
|
338
|
-
// const stack = await stackBarAndValue(i)
|
|
339
|
-
// const hasOv = get(find(stack, {key}), 'overflow')
|
|
340
|
-
// const hasPu = get(find(stack, {key}), 'pushed')
|
|
341
|
-
//
|
|
342
|
-
// const keyIndex = discoveredKeys.value.indexOf(key)
|
|
343
|
-
// const nextKey = discoveredKeys.value[keyIndex + 1]
|
|
344
|
-
// let hasNextOv= false
|
|
345
|
-
// if(nextKey){
|
|
346
|
-
// const stackNext = await stackBarAndValue(keyIndex + 1)
|
|
347
|
-
// hasNextOv = get(find(stackNext, {key}), 'overflow')
|
|
348
|
-
// }
|
|
349
|
-
// const hasHiddenV = hasOv && hasNextOv
|
|
350
|
-
// const classes = {
|
|
351
|
-
// hiddenValue:isHidden(keyIndex, key),
|
|
352
|
-
// overflow:hasOv,
|
|
353
|
-
// pushed:hasPu,
|
|
354
|
-
// hidden:hasHiddenV
|
|
355
|
-
// }
|
|
356
|
-
// return classes
|
|
357
|
-
// }
|
|
358
|
-
|
|
359
352
|
function formatXDatum(d: string) {
|
|
360
353
|
return d3Formatter(d, props.xAxisTickFormat)
|
|
361
354
|
}
|
|
362
355
|
|
|
363
|
-
watch(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
highlightedKeys.value = newHighlights
|
|
367
|
-
}
|
|
368
|
-
)
|
|
356
|
+
watch(() => props.highlights, (newHighlights) => {
|
|
357
|
+
highlightedKeys.value = newHighlights
|
|
358
|
+
})
|
|
369
359
|
|
|
370
360
|
return {
|
|
371
361
|
colorScale,
|
|
372
|
-
dataHasHighlights,
|
|
373
362
|
discoveredKeys,
|
|
374
363
|
el,
|
|
375
364
|
hasConstraintHeight,
|
|
376
|
-
|
|
377
|
-
hasRowHighlights,
|
|
365
|
+
hasAnyHighlights,
|
|
378
366
|
height,
|
|
379
367
|
sortedData,
|
|
380
368
|
barStyle,
|
|
@@ -392,24 +380,6 @@ export default defineComponent({
|
|
|
392
380
|
restoreHighlights
|
|
393
381
|
}
|
|
394
382
|
}
|
|
395
|
-
|
|
396
|
-
// watch: {
|
|
397
|
-
// relative() {
|
|
398
|
-
// this.$nextTick(this.$forceUpdate)
|
|
399
|
-
// },
|
|
400
|
-
// height() {
|
|
401
|
-
// this.$nextTick(this.$forceUpdate)
|
|
402
|
-
// },
|
|
403
|
-
// sortBy() {
|
|
404
|
-
// this.$nextTick(this.$forceUpdate)
|
|
405
|
-
// },
|
|
406
|
-
// highlights:{
|
|
407
|
-
// deep:true,
|
|
408
|
-
// handler() {
|
|
409
|
-
// this.highlightedKeys = this.highlights
|
|
410
|
-
// }
|
|
411
|
-
// }
|
|
412
|
-
// },
|
|
413
383
|
})
|
|
414
384
|
</script>
|
|
415
385
|
<template>
|
|
@@ -418,8 +388,7 @@ export default defineComponent({
|
|
|
418
388
|
:class="{
|
|
419
389
|
'stacked-bar-chart--social-mode': socialMode,
|
|
420
390
|
'stacked-bar-chart--label-above': labelAbove,
|
|
421
|
-
'stacked-bar-chart--has-highlights':
|
|
422
|
-
hasHighlights || hasRowHighlights || dataHasHighlights,
|
|
391
|
+
'stacked-bar-chart--has-highlights': hasAnyHighlights,
|
|
423
392
|
'stacked-bar-chart--has-constraint-height': hasConstraintHeight,
|
|
424
393
|
'stacked-bar-chart--has-label-above': labelAbove
|
|
425
394
|
}"
|
|
@@ -456,7 +425,7 @@ export default defineComponent({
|
|
|
456
425
|
<div
|
|
457
426
|
v-for="(datum, i) in sortedData"
|
|
458
427
|
:key="i"
|
|
459
|
-
:class="{ 'flex-column': labelAbove }"
|
|
428
|
+
:class="{ 'flex-column': labelAbove, }"
|
|
460
429
|
class="stacked-bar-chart__groups__item border-bottom flex-fill d-flex align-items-center"
|
|
461
430
|
>
|
|
462
431
|
<div
|
|
@@ -474,18 +443,11 @@ export default defineComponent({
|
|
|
474
443
|
:class="{
|
|
475
444
|
[`stacked-bar-chart__groups__item__bars__item--${normalizeKey(key)}`]: true,
|
|
476
445
|
[`stacked-bar-chart__groups__item__bars__item--${j}n`]: true,
|
|
477
|
-
'stacked-bar-chart__groups__item__bars__item--highlighted':
|
|
478
|
-
|
|
479
|
-
'stacked-bar-chart__groups__item__bars__item--
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
),
|
|
483
|
-
'stacked-bar-chart__groups__item__bars__item--value-overflow':
|
|
484
|
-
hasValueOverflow(i, key),
|
|
485
|
-
'stacked-bar-chart__groups__item__bars__item--value-pushed':
|
|
486
|
-
hasValuePushed(i, key),
|
|
487
|
-
'stacked-bar-chart__groups__item__bars__item--value-hidden':
|
|
488
|
-
hasValueHidden(i, key)
|
|
446
|
+
'stacked-bar-chart__groups__item__bars__item--highlighted': isHighlighted(key) || isRowHighlighted(i),
|
|
447
|
+
'stacked-bar-chart__groups__item__bars__item--hidden': isHidden(i, key),
|
|
448
|
+
'stacked-bar-chart__groups__item__bars__item--value-overflow': hasValueOverflow(i, key),
|
|
449
|
+
'stacked-bar-chart__groups__item__bars__item--value-pushed': hasValuePushed(i, key),
|
|
450
|
+
'stacked-bar-chart__groups__item__bars__item--value-hidden': hasValueHidden(i, key)
|
|
489
451
|
}"
|
|
490
452
|
:style="barStyle(i, key)"
|
|
491
453
|
class="stacked-bar-chart__groups__item__bars__item"
|