@icij/murmur-next 4.0.0

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.
Files changed (296) hide show
  1. package/.github/workflows/deploy-github-pages.yaml +50 -0
  2. package/.storybook/app.scss +14 -0
  3. package/.storybook/doc_variables.scss +20 -0
  4. package/.storybook/main.ts +35 -0
  5. package/.storybook/preview-head.html +2 -0
  6. package/.storybook/preview.ts +32 -0
  7. package/README.md +71 -0
  8. package/deploy.js +15 -0
  9. package/docs/components/ApiTable.vue +171 -0
  10. package/docs/components/App.vue +146 -0
  11. package/docs/components/CollapsibleBlock.vue +122 -0
  12. package/docs/components/DocsHeader.vue +68 -0
  13. package/docs/components/DocsMenu.vue +201 -0
  14. package/docs/components/DocsMenuSection.vue +109 -0
  15. package/docs/components/EditLink.vue +49 -0
  16. package/docs/components/OutboundLink.vue +13 -0
  17. package/docs/components/PalettePresenter.vue +96 -0
  18. package/docs/components/RepositoryLink.vue +28 -0
  19. package/docs/components/SampleCard.vue +119 -0
  20. package/docs/main.js +42 -0
  21. package/docs/pages/components/accordion/doc.md +96 -0
  22. package/docs/pages/components/active-text-truncate/doc.md +44 -0
  23. package/docs/pages/components/advanced-link-form/doc.md +105 -0
  24. package/docs/pages/components/brand/doc.md +30 -0
  25. package/docs/pages/components/brand-expansion/doc.md +70 -0
  26. package/docs/pages/components/confirm-button/doc.md +91 -0
  27. package/docs/pages/components/content-placeholder/doc.md +16 -0
  28. package/docs/pages/components/custom-pagination/doc.md +61 -0
  29. package/docs/pages/components/digits-input/doc.md +28 -0
  30. package/docs/pages/components/donate-form/doc.md +20 -0
  31. package/docs/pages/components/embed-form/doc.md +22 -0
  32. package/docs/pages/components/embeddable-footer/doc.md +60 -0
  33. package/docs/pages/components/follow-us-popover/doc.md +5 -0
  34. package/docs/pages/components/generic-footer/doc.md +21 -0
  35. package/docs/pages/components/generic-header/doc.md +24 -0
  36. package/docs/pages/components/haptic-copy/doc.md +27 -0
  37. package/docs/pages/components/imddb-header/doc.md +23 -0
  38. package/docs/pages/components/ordinal-legend/doc.md +44 -0
  39. package/docs/pages/components/range-picker/doc.md +86 -0
  40. package/docs/pages/components/responsive-iframe/doc.md +13 -0
  41. package/docs/pages/components/scale-legend/doc.md +65 -0
  42. package/docs/pages/components/secret-input/doc.md +12 -0
  43. package/docs/pages/components/selectable-dropdown/doc.md +156 -0
  44. package/docs/pages/components/sharing-options/doc.md +13 -0
  45. package/docs/pages/components/sharing-options-link/doc.md +36 -0
  46. package/docs/pages/components/sign-up-form/doc.md +13 -0
  47. package/docs/pages/components/slide-up-down/doc.md +28 -0
  48. package/docs/pages/components/textured-deck/doc.md +78 -0
  49. package/docs/pages/components/tiny-pagination/doc.md +92 -0
  50. package/docs/pages/datavisualisation/bars/doc.md +110 -0
  51. package/docs/pages/datavisualisation/columns/doc.md +165 -0
  52. package/docs/pages/datavisualisation/lines/doc.md +139 -0
  53. package/docs/pages/datavisualisation/stacked-bar/doc.md +160 -0
  54. package/docs/pages/datavisualisation/stacked-column/doc.md +191 -0
  55. package/docs/pages/getting-started/about-icij/doc.md +13 -0
  56. package/docs/pages/getting-started/custom-bootstrap/doc.md +36 -0
  57. package/docs/pages/getting-started/installation-guide/doc.md +59 -0
  58. package/docs/pages/getting-started/internationalization/doc.md +74 -0
  59. package/docs/pages/maps/choropleth-map/doc.md +420 -0
  60. package/docs/pages/maps/choropleth-map-annotation/doc.md +373 -0
  61. package/docs/pages/maps/symbol-map/doc.md +203 -0
  62. package/docs/pages/structure/breakpoints/doc.md +3 -0
  63. package/docs/pages/structure/grid/doc.md +3 -0
  64. package/docs/pages/utilities/assets/doc.md +138 -0
  65. package/docs/pages/utilities/config/doc.md +52 -0
  66. package/docs/pages/utilities/iframes/doc.md +3 -0
  67. package/docs/pages/visual/colors/doc.md +31 -0
  68. package/docs/pages/visual/iconography/doc.md +56 -0
  69. package/docs/pages/visual/states/doc.md +77 -0
  70. package/docs/pages/visual/themes/doc.md +3 -0
  71. package/docs/pages/visual/typography/doc.md +71 -0
  72. package/docs/routes.js +25 -0
  73. package/docs/store/index.js +21 -0
  74. package/docs/styles/app.scss +36 -0
  75. package/docs/styles/variables.scss +20 -0
  76. package/lib/assets/images/icij-full-white.svg +6 -0
  77. package/lib/assets/images/icij-full.svg +6 -0
  78. package/lib/assets/images/icij.png +0 -0
  79. package/lib/assets/images/icij.svg +46 -0
  80. package/lib/assets/images/icij@2x.png +0 -0
  81. package/lib/assets/images/murmur-dark.png +0 -0
  82. package/lib/assets/images/murmur-dark.svg +79 -0
  83. package/lib/assets/images/murmur-white.png +0 -0
  84. package/lib/assets/images/murmur-white.svg +68 -0
  85. package/lib/components/AccordionStep.vue +128 -0
  86. package/lib/components/AccordionWrapper.vue +138 -0
  87. package/lib/components/ActiveTextTruncate.vue +258 -0
  88. package/lib/components/AdvancedLinkForm.vue +273 -0
  89. package/lib/components/Brand.vue +150 -0
  90. package/lib/components/BrandExpansion.vue +237 -0
  91. package/lib/components/ConfirmButton.vue +204 -0
  92. package/lib/components/ContentPlaceholder.vue +100 -0
  93. package/lib/components/CustomPagination.vue +225 -0
  94. package/lib/components/DigitsInput.vue +180 -0
  95. package/lib/components/DonateForm.vue +367 -0
  96. package/lib/components/EmbedForm.vue +173 -0
  97. package/lib/components/EmbeddableFooter.vue +201 -0
  98. package/lib/components/Fa.js +3 -0
  99. package/lib/components/FollowUsPopover.vue +117 -0
  100. package/lib/components/GenericFooter.vue +218 -0
  101. package/lib/components/GenericHeader.vue +259 -0
  102. package/lib/components/HapticCopy.vue +256 -0
  103. package/lib/components/ImddbHeader.vue +336 -0
  104. package/lib/components/OrdinalLegend.vue +164 -0
  105. package/lib/components/RangePicker.vue +430 -0
  106. package/lib/components/ResponsiveIframe.vue +48 -0
  107. package/lib/components/ScaleLegend.vue +230 -0
  108. package/lib/components/SecretInput.vue +132 -0
  109. package/lib/components/SelectableDropdown.vue +368 -0
  110. package/lib/components/SharingOptions.vue +230 -0
  111. package/lib/components/SharingOptionsLink.vue +259 -0
  112. package/lib/components/SignUpForm.vue +181 -0
  113. package/lib/components/SlideUpDown.vue +131 -0
  114. package/lib/components/TexturedDeck.vue +101 -0
  115. package/lib/components/TinyPagination.vue +268 -0
  116. package/lib/components/index.js +31 -0
  117. package/lib/composables/chart.ts +182 -0
  118. package/lib/composables/resizeObserver.ts +37 -0
  119. package/lib/composables/sendEmail.ts +50 -0
  120. package/lib/config.default.ts +33 -0
  121. package/lib/config.ts +70 -0
  122. package/lib/d3-geo-projection.d.ts +1 -0
  123. package/lib/datavisualisations/BarChart.vue +275 -0
  124. package/lib/datavisualisations/ColumnChart.vue +527 -0
  125. package/lib/datavisualisations/LineChart.vue +274 -0
  126. package/lib/datavisualisations/StackedBarChart.vue +614 -0
  127. package/lib/datavisualisations/StackedColumnChart.vue +640 -0
  128. package/lib/datavisualisations/index.js +5 -0
  129. package/lib/enums.ts +25 -0
  130. package/lib/i18n.ts +16 -0
  131. package/lib/keys.ts +2 -0
  132. package/lib/locales/en.json +140 -0
  133. package/lib/locales/fr.json +117 -0
  134. package/lib/locales/locales/en.json +140 -0
  135. package/lib/locales/locales/fr.json +117 -0
  136. package/lib/main.ts +87 -0
  137. package/lib/maps/ChoroplethMap.vue +825 -0
  138. package/lib/maps/ChoroplethMapAnnotation.vue +336 -0
  139. package/lib/maps/SymbolMap.vue +628 -0
  140. package/lib/maps/index.js +3 -0
  141. package/lib/querystring-es3.d.ts +1 -0
  142. package/lib/shims-bootstrap-vue.d.ts +5 -0
  143. package/lib/shims-tsx.d.ts +11 -0
  144. package/lib/shims-vue.d.ts +14 -0
  145. package/lib/styles/functions.scss +20 -0
  146. package/lib/styles/lib.scss +19 -0
  147. package/lib/styles/mixins.scss +37 -0
  148. package/lib/styles/utilities.scss +18 -0
  149. package/lib/styles/variables.scss +94 -0
  150. package/lib/styles/variables_dark.scss +1 -0
  151. package/lib/types.ts +46 -0
  152. package/lib/utils/animation.ts +24 -0
  153. package/lib/utils/assets.ts +46 -0
  154. package/lib/utils/clipboard.ts +41 -0
  155. package/lib/utils/iframe-resizer.ts +49 -0
  156. package/lib/utils/placeholder.ts +66 -0
  157. package/lib/utils/placeholderTypes.ts +21 -0
  158. package/lib/utils/strings.ts +8 -0
  159. package/loaders/highlight-loader.js +13 -0
  160. package/loaders/markdown-loader.js +91 -0
  161. package/loaders/metadata-loader.js +18 -0
  162. package/loaders/sass-extract-loader.js +14 -0
  163. package/loaders/vue-docgen-loader.js +14 -0
  164. package/package.json +96 -0
  165. package/plugins/MdPluginTypes.ts +10 -0
  166. package/plugins/docs.ts +50 -0
  167. package/plugins/front-matter.ts +36 -0
  168. package/plugins/highlight.ts +27 -0
  169. package/plugins/markdown-it/api-table.ts +25 -0
  170. package/plugins/markdown-it/sample-card.ts +31 -0
  171. package/plugins/plugin-delete.ts +47 -0
  172. package/plugins/plugin-docgen.ts +23 -0
  173. package/plugins/sass-vars.ts +25 -0
  174. package/plugins/vue-docgen.ts +29 -0
  175. package/public/android-chrome-192x192.png +0 -0
  176. package/public/android-chrome-512x512.png +0 -0
  177. package/public/apple-touch-icon.png +0 -0
  178. package/public/assets/img/arrow-bottom.svg +3 -0
  179. package/public/assets/img/texture-brick-black.jpg +0 -0
  180. package/public/assets/img/texture-brick.jpg +0 -0
  181. package/public/assets/img/texture-carbon-black.jpg +0 -0
  182. package/public/assets/img/texture-carbon.jpg +0 -0
  183. package/public/assets/img/texture-crack-black.jpg +0 -0
  184. package/public/assets/img/texture-crack.jpg +0 -0
  185. package/public/assets/img/texture-rock-black.jpg +0 -0
  186. package/public/assets/img/texture-rock.jpg +0 -0
  187. package/public/assets/img/texture-sand-black.jpg +0 -0
  188. package/public/assets/img/texture-sand.jpg +0 -0
  189. package/public/assets/img/texture-silk-black.jpg +0 -0
  190. package/public/assets/img/texture-silk.jpg +0 -0
  191. package/public/assets/topojson/france-departments.json +1 -0
  192. package/public/assets/topojson/paris-arrondissements.json +1 -0
  193. package/public/assets/topojson/world-countries-sans-antarctica.json +1 -0
  194. package/public/favicon-16x16.png +0 -0
  195. package/public/favicon-32x32.png +0 -0
  196. package/public/favicon.ico +0 -0
  197. package/public/site.webmanifest +1 -0
  198. package/stories/assets/code-brackets.svg +1 -0
  199. package/stories/assets/colors.svg +1 -0
  200. package/stories/assets/comments.svg +1 -0
  201. package/stories/assets/direction.svg +1 -0
  202. package/stories/assets/flow.svg +1 -0
  203. package/stories/assets/plugin.svg +1 -0
  204. package/stories/assets/repo.svg +1 -0
  205. package/stories/assets/stackalt.svg +1 -0
  206. package/stories/getting-started/about-icij.mdx +14 -0
  207. package/stories/getting-started/custom-bootstrap.mdx +23 -0
  208. package/stories/getting-started/installation-guide.mdx +62 -0
  209. package/stories/getting-started/internationalization.mdx +63 -0
  210. package/stories/murmur/components/AccordionStep.stories.ts +33 -0
  211. package/stories/murmur/components/AccordionWrapper.stories.ts +69 -0
  212. package/stories/murmur/components/ActiveTextTruncate.stories.ts +32 -0
  213. package/stories/murmur/components/AdvancedLinkForm.stories.ts +77 -0
  214. package/stories/murmur/components/Brand.stories.ts +30 -0
  215. package/stories/murmur/components/BrandExpansion.stories.ts +41 -0
  216. package/stories/murmur/components/ConfirmButton.stories.ts +40 -0
  217. package/stories/murmur/components/ContentPlaceholder.stories.ts +41 -0
  218. package/stories/murmur/components/CustomPagination.stories.ts +42 -0
  219. package/stories/murmur/components/DigitsInput.stories.ts +29 -0
  220. package/stories/murmur/components/DonateForm.stories.ts +29 -0
  221. package/stories/murmur/components/EmbedForm.stories.ts +35 -0
  222. package/stories/murmur/components/EmbeddableFooter.stories.ts +59 -0
  223. package/stories/murmur/components/FollowUsPopover.stories.ts +24 -0
  224. package/stories/murmur/components/GenericFooter.stories.ts +27 -0
  225. package/stories/murmur/components/GenericHeader.stories.ts +27 -0
  226. package/stories/murmur/components/HapticCopy.stories.ts +40 -0
  227. package/stories/murmur/components/ImddbHeader.stories.ts +27 -0
  228. package/stories/murmur/components/OrdinalLegend.stories.ts +49 -0
  229. package/stories/murmur/components/RangePicker.stories.ts +98 -0
  230. package/stories/murmur/components/ResponsiveIframe.stories.ts +24 -0
  231. package/stories/murmur/components/ScaleLegend.stories.ts +65 -0
  232. package/stories/murmur/components/SecretInput.stories.ts +60 -0
  233. package/stories/murmur/components/SelectableDropdown.stories.ts +143 -0
  234. package/stories/murmur/components/SharingOptions.stories.ts +32 -0
  235. package/stories/murmur/components/SharingOptionsLink.stories.ts +53 -0
  236. package/stories/murmur/components/SignUpForm.stories.ts +51 -0
  237. package/stories/murmur/components/SlideUpDown.stories.ts +32 -0
  238. package/stories/murmur/components/TexturedDeck.stories.ts +83 -0
  239. package/stories/murmur/components/TinyPagination.stories.ts +65 -0
  240. package/stories/murmur/datavisualisations/BarChart.stories.ts +54 -0
  241. package/stories/murmur/datavisualisations/ColumnChart.stories.ts +88 -0
  242. package/stories/murmur/datavisualisations/LineChart.stories.ts +139 -0
  243. package/stories/murmur/datavisualisations/StackedBarChart.stories.ts +199 -0
  244. package/stories/murmur/datavisualisations/StackedColumnChart.stories.ts +136 -0
  245. package/stories/murmur/decorators.ts +108 -0
  246. package/stories/murmur/maps/ChoroplethMap.stories.ts +440 -0
  247. package/stories/murmur/maps/ChoroplethMapAnnotation.stories.ts +26 -0
  248. package/stories/murmur/maps/SymbolMap.stories.ts +24 -0
  249. package/stories/murmur/utils.ts +7 -0
  250. package/tests/unit/components/AccordionStep.spec.ts +157 -0
  251. package/tests/unit/components/AccordionWrapper.spec.ts +57 -0
  252. package/tests/unit/components/ActiveTextTruncate.spec.js +30 -0
  253. package/tests/unit/components/AdvancedLinkForm.spec.js +124 -0
  254. package/tests/unit/components/Brand.spec.js +50 -0
  255. package/tests/unit/components/ContentPlaceholder.spec.js +29 -0
  256. package/tests/unit/components/CustomPagination.spec.js +72 -0
  257. package/tests/unit/components/DigitsInput.spec.ts +157 -0
  258. package/tests/unit/components/DonateForm.spec.js +149 -0
  259. package/tests/unit/components/EmbedForm.spec.js +108 -0
  260. package/tests/unit/components/EmbeddableFooter.spec.js +11 -0
  261. package/tests/unit/components/Fa.spec.js +18 -0
  262. package/tests/unit/components/FollowUsPopover.spec.js +29 -0
  263. package/tests/unit/components/GenericFooter.spec.js +29 -0
  264. package/tests/unit/components/GenericHeader.spec.js +104 -0
  265. package/tests/unit/components/HapticCopy.spec.js +123 -0
  266. package/tests/unit/components/ImddbHeader.spec.js +96 -0
  267. package/tests/unit/components/OrdinalLegend.spec.js +120 -0
  268. package/tests/unit/components/RangePicker.spec.ts +87 -0
  269. package/tests/unit/components/ResponsiveIframe.spec.js +20 -0
  270. package/tests/unit/components/ScaleLegend.spec.js +139 -0
  271. package/tests/unit/components/SecretInput.spec.js +81 -0
  272. package/tests/unit/components/SelectableDropdown.spec.js +160 -0
  273. package/tests/unit/components/SharingOptions.spec.js +125 -0
  274. package/tests/unit/components/SharingOptionsLink.spec.js +184 -0
  275. package/tests/unit/components/SignUpForm.spec.js +145 -0
  276. package/tests/unit/components/SlideUpDown.spec.js +59 -0
  277. package/tests/unit/components/TinyPagination.spec.js +46 -0
  278. package/tests/unit/config.spec.js +136 -0
  279. package/tests/unit/datavisualisations/BarChart.spec.js +63 -0
  280. package/tests/unit/datavisualisations/ColumnChart.spec.js +344 -0
  281. package/tests/unit/datavisualisations/LineChart.spec.js +155 -0
  282. package/tests/unit/datavisualisations/StackedBarChart.spec.js +294 -0
  283. package/tests/unit/datavisualisations/StackedColumnChart.spec.js +443 -0
  284. package/tests/unit/i18n.spec.ts +19 -0
  285. package/tests/unit/main.spec.js +82 -0
  286. package/tests/unit/maps/ChoroplethMap.spec.js +214 -0
  287. package/tests/unit/maps/ChoroplethMapAnnotation.spec.ts +186 -0
  288. package/tests/unit/maps/SymbolMap.spec.js +92 -0
  289. package/tests/unit/require.spec.js +22 -0
  290. package/tests/unit/setup.js +13 -0
  291. package/tests/unit/utils/assets.spec.js +61 -0
  292. package/tests/unit/utils/clipboard.spec.js +18 -0
  293. package/tests/unit/utils/iframe-resizer.spec.js +71 -0
  294. package/tsconfig.json +35 -0
  295. package/vite.config.ts +79 -0
  296. package/vitest.config.ts +19 -0
@@ -0,0 +1,640 @@
1
+
2
+
3
+ <script lang="ts">
4
+ // import { VBTooltip } from 'bootstrap-vue/esm/directives/tooltip/tooltip'
5
+ import * as d3 from 'd3'
6
+ import keys from 'lodash/keys'
7
+ import find from 'lodash/find'
8
+ import get from 'lodash/get'
9
+ import identity from 'lodash/identity'
10
+ import sortBy from 'lodash/sortBy'
11
+ import without from 'lodash/without'
12
+ import {ComponentPublicInstance, computed, defineComponent, ref, nextTick, watch} from 'vue'
13
+ import {chartProps, getChartProps, useChart} from "@/composables/chart.js";
14
+
15
+ export default defineComponent({
16
+ name: 'StackedColumnChart',
17
+ // directives: {
18
+ // 'b-tooltip': VBTooltip
19
+ // },
20
+ //mixins: [chart],
21
+ props: {
22
+ /**
23
+ * Field of each object containing data (for each group)
24
+ */
25
+ keys: {
26
+ type: Array,
27
+ default: () => []
28
+ },
29
+ /**
30
+ * Group name to display in the legend
31
+ */
32
+ groups: {
33
+ type: Array,
34
+ default: () => []
35
+ },
36
+ /**
37
+ * Colors of each bar group
38
+ */
39
+ barColors: {
40
+ type: Array,
41
+ default: () => []
42
+ },
43
+ /**
44
+ * Max with of each bar.
45
+ */
46
+ barMaxWidth: {
47
+ type: String,
48
+ default: '100%'
49
+ },
50
+ /**
51
+ * Hide bars that have no values.
52
+ */
53
+ hideEmptyValues: {
54
+ type: Boolean
55
+ },
56
+ /**
57
+ * Hide the legend.
58
+ */
59
+ hideLegend: {
60
+ type: Boolean
61
+ },
62
+ /**
63
+ * Enforce the height of the chart (regardless of the width or number of row)
64
+ */
65
+ fixedHeight: {
66
+ type: Number,
67
+ default: null
68
+ },
69
+ /**
70
+ * Function to apply to format x axis ticks
71
+ */
72
+ xAxisTickFormat: {
73
+ type: [Function, String],
74
+ default: ()=>identity
75
+ },
76
+ /**
77
+ * Function to apply to format y axis ticks (bars value). It can be a
78
+ * function returning the formatted value or a d3's formatter string.
79
+ */
80
+ yAxisTickFormat: {
81
+ type: [Function, String],
82
+ default: ()=>identity
83
+ },
84
+ /**
85
+ * Padding on y axis ticks
86
+ */
87
+ yAxisTickPadding: {
88
+ type: Number,
89
+ default: 10
90
+ },
91
+ /**
92
+ * Field containing the label for each column
93
+ */
94
+ labelField: {
95
+ type: String,
96
+ default: 'date'
97
+ },
98
+ /**
99
+ * Sort groups by one or several keys.
100
+ */
101
+ sortBy: {
102
+ type: [Array, String],
103
+ default: null
104
+ },
105
+ /**
106
+ * Column height is relative to each group's total
107
+ */
108
+ relative: {
109
+ type: Boolean,
110
+ default: false
111
+ },
112
+ /**
113
+ * A list of highlighted groups
114
+ */
115
+ highlights: {
116
+ type: Array,
117
+ default: () => []
118
+ },
119
+ /**
120
+ * Delay to apply when set the first highlight
121
+ */
122
+ highlightDelay: {
123
+ type: Number,
124
+ default: 400
125
+ },
126
+ /**
127
+ * A list of entire column to highlight
128
+ */
129
+ columnHighlights: {
130
+ type: Array,
131
+ default: () => []
132
+ },
133
+ /**
134
+ * Delay to apply when restoring highlights to initial state
135
+ */
136
+ restoreHighlightDelay: {
137
+ type: Number,
138
+ default: 50
139
+ },
140
+ /**
141
+ * Deactivate direct labeling on bars
142
+ */
143
+ noDirectLabeling: {
144
+ type: Boolean
145
+ },
146
+ /**
147
+ * Set max value instead of extracting it from the data.
148
+ */
149
+ maxValue: {
150
+ type: Number,
151
+ default: null
152
+ },
153
+ /**
154
+ * Function to define tooltip content.
155
+ */
156
+ tooltipDisplay: {
157
+ type: Function,
158
+ default: ({ formattedKey, formattedValue }:{formattedKey:string, formattedValue:string}):string => {
159
+ return `<h6 class="mb-0">${formattedKey}</h6><div>${formattedValue}</div>`
160
+ }
161
+ },
162
+ /**
163
+ * Hide bar tooltips
164
+ */
165
+ noTooltips: {
166
+ type: Boolean
167
+ },
168
+ ...chartProps()
169
+ },
170
+ setup(props,{emit}){
171
+ const width = ref(0)
172
+ const height = ref(0)
173
+ const leftAxisHeight = ref(0)
174
+ const highlightedKeys = ref(props.highlights)
175
+ const highlightTimeout = ref<NodeJS.Timeout | undefined>(undefined)
176
+ const isLoaded = ref(false)
177
+ const el = ref<ComponentPublicInstance<HTMLElement> | null>(null)
178
+
179
+ const {
180
+ elementsMaxBBox,
181
+ baseHeightRatio,
182
+ loadedData,
183
+ d3Formatter,
184
+ dataHasHighlights
185
+ } = useChart(el, getChartProps(props), {emit}, isLoaded, setSizes)
186
+ const sortedData = computed(() => {
187
+ if (!isLoaded.value) {
188
+ return []
189
+ }
190
+ return !props.sortBy ? loadedData.value : sortBy(loadedData.value, props.sortBy)
191
+ })
192
+
193
+ const discoveredKeys = computed((): any[] => {
194
+ if (props.keys.length) {
195
+ return props.keys
196
+ }
197
+ if (!loadedData.value) {
198
+ return []
199
+ }
200
+ return without(keys(loadedData.value[0]), props.labelField)
201
+ })
202
+ const colorScale = computed(() => {
203
+ return d3.scaleOrdinal().domain(discoveredKeys.value).range(props.barColors)
204
+ })
205
+
206
+ const hasHighlights = computed(() => {
207
+ return !!highlightedKeys.value.length
208
+ })
209
+
210
+ // different
211
+
212
+ const hasColumnHighlights= computed(() => {
213
+ return !!props.columnHighlights.length
214
+ })
215
+ const leftScale= computed(() =>{
216
+ return d3.scaleLinear().domain([0, maxRowValue.value]).range([leftAxisHeight.value, 0])
217
+ })
218
+
219
+ const leftAxis= computed(() =>{
220
+ return d3
221
+ .axisLeft(leftScale.value)
222
+ .tickFormat((d) => d3Formatter(d, props.yAxisTickFormat))
223
+ .tickSize(width.value - leftAxisLabelsWidth.value)
224
+ .tickPadding(props.yAxisTickPadding)
225
+ }/*, {cache: false}*/)
226
+ const leftAxisLabelsWidth= computed(() => {
227
+ const selector = '.stacked-column-chart__left-axis__canvas .tick text'
228
+ const defaultWidth = 0
229
+ return elementsMaxBBox({ selector, defaultWidth }).width + props.yAxisTickPadding
230
+ }/*, {cache: false}*/)
231
+
232
+ const leftAxisCanvas= computed(() => {
233
+ return d3.select(el.value).select('.stacked-column-chart__left-axis__canvas')
234
+ })
235
+ const paddedStyle= computed(() => {
236
+ return {
237
+ marginLeft: props.noDirectLabeling ? `${leftAxisLabelsWidth.value + props.yAxisTickPadding}px` : 0
238
+ }
239
+ })
240
+ const barTooltipDelay = computed(() => {
241
+ return hasHighlights.value ? 0 : props.highlightDelay
242
+ })
243
+ const maxRowValue = computed(() => {
244
+ return (
245
+ props.maxValue ||
246
+ d3.max(loadedData.value || [], (datum, i) => {
247
+ return totalRowValue(i)
248
+ }) as number
249
+ )
250
+ })
251
+
252
+ function setSizes() {
253
+ if(!el.value ){
254
+ return
255
+ }
256
+ width.value = el.value.offsetWidth
257
+ height.value = props.fixedHeight !== null ? props.fixedHeight : width.value * baseHeightRatio.value
258
+ }
259
+ function groupName(key:string) {
260
+ const index = discoveredKeys.value.indexOf(key)
261
+ return props.groups[index] || key
262
+ }
263
+
264
+ function highlight(key:string) {
265
+ highlightedKeys.value = [key]
266
+ }
267
+
268
+ function restoreHighlights() {
269
+ clearTimeout(highlightTimeout.value)
270
+ const delay = props.restoreHighlightDelay
271
+ // Delay the restoration so it can be cancelled by a new highlight
272
+ highlightTimeout.value = setTimeout(() => (highlightedKeys.value = props.highlights), delay)
273
+ }
274
+
275
+ function delayHighlight(key:string) {
276
+ clearTimeout(highlightTimeout.value)
277
+ // Reduce the delay to zero if there is already an highlighted key
278
+ const isDelayed = !hasHighlights.value
279
+ const delay = isDelayed ? props.highlightDelay : 0
280
+ highlightTimeout.value = setTimeout(() => highlight(key), delay)
281
+ }
282
+
283
+ function isHighlighted(key:string) {
284
+ return highlightedKeys.value.indexOf(key) > -1
285
+ }
286
+
287
+ function isColumnHighlighted(i:string|number) {
288
+ const column = get(sortedData.value, [i, props.labelField], null)
289
+ return props.columnHighlights.includes(column) && !highlightedKeys.value.length
290
+ }
291
+
292
+ function totalRowValue(i:string|number) {
293
+ return d3.sum(discoveredKeys.value, (key:string) => {
294
+ return sortedData.value[i][key]
295
+ })
296
+ }
297
+
298
+ function barStyle(i:string|number, key:string) {
299
+ const value = sortedData.value[i][key]
300
+ let totalWidth = props.relative ? totalRowValue(i) : maxRowValue.value
301
+ if(!totalWidth){
302
+ console.error("totalWidth as divider cannot be "+totalWidth)
303
+ totalWidth = 100
304
+ }
305
+ const height = `${100 * (value / totalWidth)}%`
306
+ const backgroundColor = colorScale.value(key)
307
+ const maxWidth = props.barMaxWidth
308
+ return { maxWidth, height, backgroundColor }
309
+ }
310
+
311
+ function barTitle(i:string|number, key:string) {
312
+ const value = sortedData.value[i][key]
313
+ const formattedValue = d3Formatter(value, props.yAxisTickFormat)
314
+ const formattedKey = groupName(key)
315
+ return props.tooltipDisplay({ value, formattedValue, key, formattedKey })
316
+ }
317
+
318
+ async function stackBarAndValue(i:string|number) {
319
+ if (!sortedData.value) {
320
+ return []
321
+ }
322
+ await nextTick()
323
+
324
+ // Collect sizes first
325
+ const stack = discoveredKeys.value.map((key:string) => {
326
+ const { bar, row, value } = queryBarAndValue(i as number, key)
327
+ if(!bar || !row || !value){
328
+ throw new Error("Empty values for bar, row or value")
329
+ }
330
+ const barEdge = bar.getBoundingClientRect().top + bar.offsetHeight
331
+ const barHeight = bar.offsetHeight
332
+ const rowEdge = row.getBoundingClientRect().top + row.offsetHeight
333
+ const valueHeight = value.offsetHeight
334
+ return { key, barEdge, barHeight, rowEdge, valueHeight, overflow:false, pushed:false }
335
+ })
336
+ // Infer value's display
337
+ return stack.map((desc, index) => {
338
+ desc.overflow = desc.valueHeight >= desc.barHeight
339
+ if (index > 0) {
340
+ const prevDesc = stack[index - 1]
341
+ const bothValuesHeight = desc.valueHeight + prevDesc.valueHeight
342
+ desc.overflow = desc.overflow || (prevDesc.overflow && desc.barHeight < bothValuesHeight)
343
+ }
344
+ desc.pushed = desc.barEdge + desc.valueHeight > desc.rowEdge && desc.overflow
345
+ return desc
346
+ })
347
+ }
348
+
349
+ function queryBarAndValue(i:number, key:string) {
350
+ if (!sortedData.value) {
351
+ return {}
352
+ }
353
+ const rowSelector = '.stacked-column-chart__groups__item'
354
+ const row = el.value?.querySelectorAll(rowSelector)[i] as HTMLElement
355
+ const barSelector = `.stacked-column-chart__groups__item__bars__item--${key}`
356
+ const bar = row.querySelector(barSelector) as HTMLElement
357
+ const valueSelector = '.stacked-column-chart__groups__item__bars__item__value'
358
+ const value = bar.querySelector(valueSelector) as HTMLElement
359
+ return { bar, row, value }
360
+ }
361
+
362
+ function isHidden(i:string|number, key:string) {
363
+ return props.hideEmptyValues && !sortedData.value[i][key]
364
+ }
365
+
366
+ function hasValueOverflow(i:string|number, key:string) {
367
+ const stack = stackBarAndValue(i)
368
+ return find(stack, { key })?.overflow
369
+ }
370
+
371
+ function hasValuePushed(i:string|number, key:string) {
372
+ const stack = stackBarAndValue(i)
373
+ return find(stack, { key })?.pushed
374
+ }
375
+
376
+ function hasValueHidden(i:string|number, key:string) {
377
+ const keyIndex = discoveredKeys.value.indexOf(key)
378
+ const nextKey = discoveredKeys.value[keyIndex + 1]
379
+ if (!nextKey) {
380
+ return false
381
+ }
382
+ return hasValueOverflow(i, key) && hasValueOverflow(i, nextKey)
383
+ }
384
+ function formatXDatum(d: string) {
385
+ return d3Formatter(d, props.yAxisTickFormat)
386
+ }
387
+ function formatYDatum(d: string) {
388
+ return d3Formatter(d, props.yAxisTickFormat)
389
+ }
390
+ watch(() => props.highlights, (newHighlights) => {
391
+ highlightedKeys.value = newHighlights
392
+ })
393
+ watch(sortedData, async (newVal)=>{
394
+ await nextTick()
395
+ // This must be set after the column have been rendered
396
+ const element = el.value?.querySelector('.stacked-column-chart__groups__item__bars')
397
+ leftAxisHeight.value = (element as HTMLElement).offsetHeight
398
+ //@ts-ignore
399
+ leftAxisCanvas.value.call(leftAxis.value)
400
+ })
401
+
402
+ return {
403
+ barTooltipDelay,
404
+ colorScale,
405
+ dataHasHighlights,
406
+ discoveredKeys,
407
+ el,
408
+ hasColumnHighlights,
409
+ hasHighlights,
410
+ height,
411
+ loadedData,
412
+ paddedStyle,
413
+ sortedData,
414
+ width,
415
+ barTitle,
416
+ barStyle,
417
+ delayHighlight,
418
+ formatXDatum,
419
+ formatYDatum,
420
+ groupName,
421
+ hasValueHidden,
422
+ hasValueOverflow,
423
+ hasValuePushed,
424
+ isColumnHighlighted,
425
+ isHidden,
426
+ isHighlighted,
427
+ restoreHighlights
428
+ }
429
+ }
430
+
431
+ })
432
+ </script>
433
+ <template>
434
+ <div
435
+ ref="el"
436
+ :style="{ height: `${height}px` }"
437
+ class="stacked-column-chart d-flex flex-column"
438
+ :class="{
439
+ 'stacked-column-chart--social-mode': socialMode,
440
+ 'stacked-column-chart--has-highlights': hasHighlights || hasColumnHighlights,
441
+ 'stacked-column-chart--no-direct-labeling': noDirectLabeling
442
+ }"
443
+ >
444
+ <ul v-if="!hideLegend" class="stacked-column-chart__legend list-inline">
445
+ <li
446
+ v-for="key in discoveredKeys"
447
+ :key="key"
448
+ class="stacked-column-chart__legend__item list-inline-item d-inline-flex"
449
+ :class="{
450
+ 'stacked-column-chart__legend__item--highlighted': isHighlighted(key)
451
+ }"
452
+ @mouseover="delayHighlight(key)"
453
+ @mouseleave="restoreHighlights()"
454
+ >
455
+ <span class="stacked-column-chart__legend__item__box" :style="{ 'background-color': colorScale(key) }" />
456
+ {{ groupName(key) }}
457
+ </li>
458
+ </ul>
459
+ <div class="d-flex flex-grow-1 position-relative overflow-hidden">
460
+ <svg
461
+ v-show="noDirectLabeling"
462
+ :width="width + 'px'"
463
+ :height="height + 'px'"
464
+ class="stacked-column-chart__left-axis"
465
+ >
466
+ <g class="stacked-column-chart__left-axis__canvas" :transform="`translate(${width}, 0)`" />
467
+ </svg>
468
+ <div class="stacked-column-chart__groups d-flex flex-grow-1" :style="paddedStyle">
469
+ <div
470
+ v-for="(datum, i) in sortedData"
471
+ :key="i"
472
+ class="stacked-column-chart__groups__item flex-grow-1 d-flex flex-column text-center"
473
+ >
474
+ <div
475
+ class="stacked-column-chart__groups__item__bars flex-grow-1 d-flex flex-column-reverse px-1 justify-content-start align-items-center"
476
+ >
477
+ <div
478
+ v-for="(key, j) in discoveredKeys"
479
+ :key="j"
480
+ v-b-tooltip.html="{ delay: barTooltipDelay, disabled: noTooltips, title: barTitle(i, key) }"
481
+ :style="barStyle(i, key)"
482
+ class="stacked-column-chart__groups__item__bars__item"
483
+ :class="{
484
+ [`stacked-column-chart__groups__item__bars__item--${key}`]: true,
485
+ [`stacked-column-chart__groups__item__bars__item--${j}n`]: true,
486
+ 'stacked-column-chart__groups__item__bars__item--hidden': isHidden(i, key),
487
+ 'stacked-column-chart__groups__item__bars__item--highlighted':
488
+ isHighlighted(key) || isColumnHighlighted(i),
489
+ 'stacked-column-chart__groups__item__bars__item--value-overflow': hasValueOverflow(i, key),
490
+ 'stacked-column-chart__groups__item__bars__item--value-pushed': hasValuePushed(i, key),
491
+ 'stacked-column-chart__groups__item__bars__item--value-hidden': hasValueHidden(i, key)
492
+ }"
493
+ @mouseover="delayHighlight(key)"
494
+ @mouseleave="restoreHighlights()"
495
+ >
496
+ <div v-show="!noDirectLabeling" class="stacked-column-chart__groups__item__bars__item__value">
497
+ {{ formatYDatum(datum[key]) }}
498
+ </div>
499
+ </div>
500
+ </div>
501
+ <div class="stacked-column-chart__groups__item__label small py-2">
502
+ {{ formatXDatum(datum[labelField]) }}
503
+ </div>
504
+ </div>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ </template>
509
+ <style lang="scss">
510
+ @use 'sass:math';
511
+ @import '../styles/lib';
512
+
513
+ .stacked-column-chart {
514
+ $muted-group-opacity: 0.2;
515
+ $muted-group-filter: grayscale(30%) brightness(10%);
516
+ $muted-group-transition: opacity 0.3s, filter 0.3s;
517
+ $colors: $primary, $info, $warning;
518
+ $quantile: 3;
519
+
520
+ @each $start-color in $colors {
521
+ $i: index($colors, $start-color) - 1;
522
+ $end-color: mix($start-color, text-contrast($start-color), 20%);
523
+
524
+ @for $j from ($quantile * $i) through ($quantile * $i + $quantile - 1) {
525
+ $amount: ($j % $quantile) * math.div(100%, $quantile);
526
+ --group-color-#{$j}n: #{mix($end-color, $start-color, $amount)};
527
+ }
528
+ }
529
+
530
+ &__legend {
531
+ &__item {
532
+ display: inline-flex;
533
+ flex-direction: row;
534
+ align-items: center;
535
+ padding-right: $spacer * 0.5;
536
+
537
+ @for $i from 0 through ($quantile * length($colors)) {
538
+ &:nth-child(#{$i + 1}n) &__box {
539
+ background-color: var(--group-color-#{$i}n);
540
+ }
541
+ }
542
+
543
+ .stacked-column-chart--has-highlights &:not(&--highlighted) {
544
+ opacity: $muted-group-opacity;
545
+ filter: $muted-group-filter;
546
+ }
547
+
548
+ &__box {
549
+ height: 1em;
550
+ width: 1em;
551
+ border-radius: 0.5em;
552
+ display: inline-block;
553
+ margin-right: $spacer * 0.5;
554
+ }
555
+ }
556
+ }
557
+
558
+ &__left-axis {
559
+ position: absolute;
560
+ top: 0;
561
+ left: 0;
562
+
563
+ path {
564
+ display: none;
565
+ }
566
+
567
+ .tick {
568
+ line {
569
+ stroke: $border-color;
570
+ }
571
+
572
+ text {
573
+ font-family: $font-family-base;
574
+ font-size: $font-size-sm;
575
+ fill: currentColor;
576
+ }
577
+ }
578
+ }
579
+
580
+ &__groups {
581
+ &__item {
582
+ &__bars {
583
+ &__item {
584
+ width: 100%;
585
+ position: relative;
586
+ min-height: 1px;
587
+
588
+ @for $i from 0 through ($quantile * length($colors)) {
589
+ &--#{$i}n {
590
+ background: var(--group-color-#{$i}n);
591
+ }
592
+ }
593
+
594
+ &__value {
595
+ position: absolute;
596
+ top: 0;
597
+ left: 0;
598
+ width: 100%;
599
+ text-align: center;
600
+ white-space: nowrap;
601
+ color: #fff;
602
+ }
603
+
604
+ .stacked-column-chart--has-highlights &:not(&--highlighted) {
605
+ opacity: $muted-group-opacity;
606
+ filter: $muted-group-filter;
607
+ }
608
+
609
+ .stacked-column-chart--has-highlights &:not(&--highlighted) &__value {
610
+ visibility: hidden;
611
+ }
612
+
613
+ .stacked-column-chart:not(.stacked-column-chart--has-highlights) &--value-hidden &__value,
614
+ .stacked-column-chart:not(.stacked-column-chart--has-highlights) &--value-pushed &__value {
615
+ visibility: hidden;
616
+ }
617
+
618
+ &--hidden {
619
+ display: none;
620
+ }
621
+
622
+ &--value-overflow &__value {
623
+ color: $body-color;
624
+ transform: translateY(-100%);
625
+ }
626
+
627
+ &--value-pushed {
628
+ direction: ltr;
629
+ }
630
+
631
+ &--value-pushed &__value {
632
+ color: $body-color;
633
+ transform: translateY(100%);
634
+ }
635
+ }
636
+ }
637
+ }
638
+ }
639
+ }
640
+ </style>
@@ -0,0 +1,5 @@
1
+ export { default as BarChart } from './BarChart.vue'
2
+ export { default as ColumnChart } from './ColumnChart.vue'
3
+ export { default as LineChart } from './LineChart.vue'
4
+ export { default as StackedBarChart } from './StackedBarChart.vue'
5
+ export { default as StackedColumnChart } from './StackedColumnChart.vue'
package/lib/enums.ts ADDED
@@ -0,0 +1,25 @@
1
+ export enum BrandMode {
2
+ Short = 'short', Medium = 'medium', Long = 'long'
3
+ }
4
+
5
+ export enum TooltipPlacement {
6
+ Top = 'top', Topleft = 'topleft', Topright = 'topright',
7
+ Right = 'right', Righttop = 'righttop', Rightbottom = 'rightbottom',
8
+ Bottom = 'bottom', Bottomleft = 'bottomleft', Bottomright = 'bottomright',
9
+ Left = 'left', Lefttop = 'lefttop', Leftbottom = 'leftbottom'
10
+ }
11
+
12
+ export enum DeckTexture {
13
+ Silk = 'silk',
14
+ Brick = 'brick',
15
+ Rock = 'rock',
16
+ Sand = 'sand',
17
+ Crack = 'crack',
18
+ Carbon = 'carbon'
19
+ }
20
+
21
+ export enum Size {
22
+ sm = 'sm',
23
+ md = 'md',
24
+ lg = 'lg',
25
+ }
package/lib/i18n.ts ADDED
@@ -0,0 +1,16 @@
1
+ import {createI18n,I18n} from 'vue-i18n'
2
+
3
+ import fr from '@/locales/fr.json'
4
+ import en from '@/locales/en.json'
5
+
6
+ export const locale: string = 'en'
7
+ export const fallbackLocale: string = 'en'
8
+ // https://vue-i18n.intlify.dev/guide/advanced/composition.html#implicit-with-injected-properties-and-functions
9
+ export const i18n: I18n = createI18n({
10
+ warnHtmlMessage:false,
11
+ globalInjection: true,
12
+ legacy:false,
13
+ locale,
14
+ fallbackLocale,
15
+ messages: { fr, en }
16
+ })
package/lib/keys.ts ADDED
@@ -0,0 +1,2 @@
1
+ export const AccordionKey = Symbol('Accordion');
2
+ export const ParentKey = Symbol('Parent');