@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.
- package/.github/workflows/deploy-github-pages.yaml +50 -0
- package/.storybook/app.scss +14 -0
- package/.storybook/doc_variables.scss +20 -0
- package/.storybook/main.ts +35 -0
- package/.storybook/preview-head.html +2 -0
- package/.storybook/preview.ts +32 -0
- package/README.md +71 -0
- package/deploy.js +15 -0
- package/docs/components/ApiTable.vue +171 -0
- package/docs/components/App.vue +146 -0
- package/docs/components/CollapsibleBlock.vue +122 -0
- package/docs/components/DocsHeader.vue +68 -0
- package/docs/components/DocsMenu.vue +201 -0
- package/docs/components/DocsMenuSection.vue +109 -0
- package/docs/components/EditLink.vue +49 -0
- package/docs/components/OutboundLink.vue +13 -0
- package/docs/components/PalettePresenter.vue +96 -0
- package/docs/components/RepositoryLink.vue +28 -0
- package/docs/components/SampleCard.vue +119 -0
- package/docs/main.js +42 -0
- package/docs/pages/components/accordion/doc.md +96 -0
- package/docs/pages/components/active-text-truncate/doc.md +44 -0
- package/docs/pages/components/advanced-link-form/doc.md +105 -0
- package/docs/pages/components/brand/doc.md +30 -0
- package/docs/pages/components/brand-expansion/doc.md +70 -0
- package/docs/pages/components/confirm-button/doc.md +91 -0
- package/docs/pages/components/content-placeholder/doc.md +16 -0
- package/docs/pages/components/custom-pagination/doc.md +61 -0
- package/docs/pages/components/digits-input/doc.md +28 -0
- package/docs/pages/components/donate-form/doc.md +20 -0
- package/docs/pages/components/embed-form/doc.md +22 -0
- package/docs/pages/components/embeddable-footer/doc.md +60 -0
- package/docs/pages/components/follow-us-popover/doc.md +5 -0
- package/docs/pages/components/generic-footer/doc.md +21 -0
- package/docs/pages/components/generic-header/doc.md +24 -0
- package/docs/pages/components/haptic-copy/doc.md +27 -0
- package/docs/pages/components/imddb-header/doc.md +23 -0
- package/docs/pages/components/ordinal-legend/doc.md +44 -0
- package/docs/pages/components/range-picker/doc.md +86 -0
- package/docs/pages/components/responsive-iframe/doc.md +13 -0
- package/docs/pages/components/scale-legend/doc.md +65 -0
- package/docs/pages/components/secret-input/doc.md +12 -0
- package/docs/pages/components/selectable-dropdown/doc.md +156 -0
- package/docs/pages/components/sharing-options/doc.md +13 -0
- package/docs/pages/components/sharing-options-link/doc.md +36 -0
- package/docs/pages/components/sign-up-form/doc.md +13 -0
- package/docs/pages/components/slide-up-down/doc.md +28 -0
- package/docs/pages/components/textured-deck/doc.md +78 -0
- package/docs/pages/components/tiny-pagination/doc.md +92 -0
- package/docs/pages/datavisualisation/bars/doc.md +110 -0
- package/docs/pages/datavisualisation/columns/doc.md +165 -0
- package/docs/pages/datavisualisation/lines/doc.md +139 -0
- package/docs/pages/datavisualisation/stacked-bar/doc.md +160 -0
- package/docs/pages/datavisualisation/stacked-column/doc.md +191 -0
- package/docs/pages/getting-started/about-icij/doc.md +13 -0
- package/docs/pages/getting-started/custom-bootstrap/doc.md +36 -0
- package/docs/pages/getting-started/installation-guide/doc.md +59 -0
- package/docs/pages/getting-started/internationalization/doc.md +74 -0
- package/docs/pages/maps/choropleth-map/doc.md +420 -0
- package/docs/pages/maps/choropleth-map-annotation/doc.md +373 -0
- package/docs/pages/maps/symbol-map/doc.md +203 -0
- package/docs/pages/structure/breakpoints/doc.md +3 -0
- package/docs/pages/structure/grid/doc.md +3 -0
- package/docs/pages/utilities/assets/doc.md +138 -0
- package/docs/pages/utilities/config/doc.md +52 -0
- package/docs/pages/utilities/iframes/doc.md +3 -0
- package/docs/pages/visual/colors/doc.md +31 -0
- package/docs/pages/visual/iconography/doc.md +56 -0
- package/docs/pages/visual/states/doc.md +77 -0
- package/docs/pages/visual/themes/doc.md +3 -0
- package/docs/pages/visual/typography/doc.md +71 -0
- package/docs/routes.js +25 -0
- package/docs/store/index.js +21 -0
- package/docs/styles/app.scss +36 -0
- package/docs/styles/variables.scss +20 -0
- package/lib/assets/images/icij-full-white.svg +6 -0
- package/lib/assets/images/icij-full.svg +6 -0
- package/lib/assets/images/icij.png +0 -0
- package/lib/assets/images/icij.svg +46 -0
- package/lib/assets/images/icij@2x.png +0 -0
- package/lib/assets/images/murmur-dark.png +0 -0
- package/lib/assets/images/murmur-dark.svg +79 -0
- package/lib/assets/images/murmur-white.png +0 -0
- package/lib/assets/images/murmur-white.svg +68 -0
- package/lib/components/AccordionStep.vue +128 -0
- package/lib/components/AccordionWrapper.vue +138 -0
- package/lib/components/ActiveTextTruncate.vue +258 -0
- package/lib/components/AdvancedLinkForm.vue +273 -0
- package/lib/components/Brand.vue +150 -0
- package/lib/components/BrandExpansion.vue +237 -0
- package/lib/components/ConfirmButton.vue +204 -0
- package/lib/components/ContentPlaceholder.vue +100 -0
- package/lib/components/CustomPagination.vue +225 -0
- package/lib/components/DigitsInput.vue +180 -0
- package/lib/components/DonateForm.vue +367 -0
- package/lib/components/EmbedForm.vue +173 -0
- package/lib/components/EmbeddableFooter.vue +201 -0
- package/lib/components/Fa.js +3 -0
- package/lib/components/FollowUsPopover.vue +117 -0
- package/lib/components/GenericFooter.vue +218 -0
- package/lib/components/GenericHeader.vue +259 -0
- package/lib/components/HapticCopy.vue +256 -0
- package/lib/components/ImddbHeader.vue +336 -0
- package/lib/components/OrdinalLegend.vue +164 -0
- package/lib/components/RangePicker.vue +430 -0
- package/lib/components/ResponsiveIframe.vue +48 -0
- package/lib/components/ScaleLegend.vue +230 -0
- package/lib/components/SecretInput.vue +132 -0
- package/lib/components/SelectableDropdown.vue +368 -0
- package/lib/components/SharingOptions.vue +230 -0
- package/lib/components/SharingOptionsLink.vue +259 -0
- package/lib/components/SignUpForm.vue +181 -0
- package/lib/components/SlideUpDown.vue +131 -0
- package/lib/components/TexturedDeck.vue +101 -0
- package/lib/components/TinyPagination.vue +268 -0
- package/lib/components/index.js +31 -0
- package/lib/composables/chart.ts +182 -0
- package/lib/composables/resizeObserver.ts +37 -0
- package/lib/composables/sendEmail.ts +50 -0
- package/lib/config.default.ts +33 -0
- package/lib/config.ts +70 -0
- package/lib/d3-geo-projection.d.ts +1 -0
- package/lib/datavisualisations/BarChart.vue +275 -0
- package/lib/datavisualisations/ColumnChart.vue +527 -0
- package/lib/datavisualisations/LineChart.vue +274 -0
- package/lib/datavisualisations/StackedBarChart.vue +614 -0
- package/lib/datavisualisations/StackedColumnChart.vue +640 -0
- package/lib/datavisualisations/index.js +5 -0
- package/lib/enums.ts +25 -0
- package/lib/i18n.ts +16 -0
- package/lib/keys.ts +2 -0
- package/lib/locales/en.json +140 -0
- package/lib/locales/fr.json +117 -0
- package/lib/locales/locales/en.json +140 -0
- package/lib/locales/locales/fr.json +117 -0
- package/lib/main.ts +87 -0
- package/lib/maps/ChoroplethMap.vue +825 -0
- package/lib/maps/ChoroplethMapAnnotation.vue +336 -0
- package/lib/maps/SymbolMap.vue +628 -0
- package/lib/maps/index.js +3 -0
- package/lib/querystring-es3.d.ts +1 -0
- package/lib/shims-bootstrap-vue.d.ts +5 -0
- package/lib/shims-tsx.d.ts +11 -0
- package/lib/shims-vue.d.ts +14 -0
- package/lib/styles/functions.scss +20 -0
- package/lib/styles/lib.scss +19 -0
- package/lib/styles/mixins.scss +37 -0
- package/lib/styles/utilities.scss +18 -0
- package/lib/styles/variables.scss +94 -0
- package/lib/styles/variables_dark.scss +1 -0
- package/lib/types.ts +46 -0
- package/lib/utils/animation.ts +24 -0
- package/lib/utils/assets.ts +46 -0
- package/lib/utils/clipboard.ts +41 -0
- package/lib/utils/iframe-resizer.ts +49 -0
- package/lib/utils/placeholder.ts +66 -0
- package/lib/utils/placeholderTypes.ts +21 -0
- package/lib/utils/strings.ts +8 -0
- package/loaders/highlight-loader.js +13 -0
- package/loaders/markdown-loader.js +91 -0
- package/loaders/metadata-loader.js +18 -0
- package/loaders/sass-extract-loader.js +14 -0
- package/loaders/vue-docgen-loader.js +14 -0
- package/package.json +96 -0
- package/plugins/MdPluginTypes.ts +10 -0
- package/plugins/docs.ts +50 -0
- package/plugins/front-matter.ts +36 -0
- package/plugins/highlight.ts +27 -0
- package/plugins/markdown-it/api-table.ts +25 -0
- package/plugins/markdown-it/sample-card.ts +31 -0
- package/plugins/plugin-delete.ts +47 -0
- package/plugins/plugin-docgen.ts +23 -0
- package/plugins/sass-vars.ts +25 -0
- package/plugins/vue-docgen.ts +29 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/assets/img/arrow-bottom.svg +3 -0
- package/public/assets/img/texture-brick-black.jpg +0 -0
- package/public/assets/img/texture-brick.jpg +0 -0
- package/public/assets/img/texture-carbon-black.jpg +0 -0
- package/public/assets/img/texture-carbon.jpg +0 -0
- package/public/assets/img/texture-crack-black.jpg +0 -0
- package/public/assets/img/texture-crack.jpg +0 -0
- package/public/assets/img/texture-rock-black.jpg +0 -0
- package/public/assets/img/texture-rock.jpg +0 -0
- package/public/assets/img/texture-sand-black.jpg +0 -0
- package/public/assets/img/texture-sand.jpg +0 -0
- package/public/assets/img/texture-silk-black.jpg +0 -0
- package/public/assets/img/texture-silk.jpg +0 -0
- package/public/assets/topojson/france-departments.json +1 -0
- package/public/assets/topojson/paris-arrondissements.json +1 -0
- package/public/assets/topojson/world-countries-sans-antarctica.json +1 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/site.webmanifest +1 -0
- package/stories/assets/code-brackets.svg +1 -0
- package/stories/assets/colors.svg +1 -0
- package/stories/assets/comments.svg +1 -0
- package/stories/assets/direction.svg +1 -0
- package/stories/assets/flow.svg +1 -0
- package/stories/assets/plugin.svg +1 -0
- package/stories/assets/repo.svg +1 -0
- package/stories/assets/stackalt.svg +1 -0
- package/stories/getting-started/about-icij.mdx +14 -0
- package/stories/getting-started/custom-bootstrap.mdx +23 -0
- package/stories/getting-started/installation-guide.mdx +62 -0
- package/stories/getting-started/internationalization.mdx +63 -0
- package/stories/murmur/components/AccordionStep.stories.ts +33 -0
- package/stories/murmur/components/AccordionWrapper.stories.ts +69 -0
- package/stories/murmur/components/ActiveTextTruncate.stories.ts +32 -0
- package/stories/murmur/components/AdvancedLinkForm.stories.ts +77 -0
- package/stories/murmur/components/Brand.stories.ts +30 -0
- package/stories/murmur/components/BrandExpansion.stories.ts +41 -0
- package/stories/murmur/components/ConfirmButton.stories.ts +40 -0
- package/stories/murmur/components/ContentPlaceholder.stories.ts +41 -0
- package/stories/murmur/components/CustomPagination.stories.ts +42 -0
- package/stories/murmur/components/DigitsInput.stories.ts +29 -0
- package/stories/murmur/components/DonateForm.stories.ts +29 -0
- package/stories/murmur/components/EmbedForm.stories.ts +35 -0
- package/stories/murmur/components/EmbeddableFooter.stories.ts +59 -0
- package/stories/murmur/components/FollowUsPopover.stories.ts +24 -0
- package/stories/murmur/components/GenericFooter.stories.ts +27 -0
- package/stories/murmur/components/GenericHeader.stories.ts +27 -0
- package/stories/murmur/components/HapticCopy.stories.ts +40 -0
- package/stories/murmur/components/ImddbHeader.stories.ts +27 -0
- package/stories/murmur/components/OrdinalLegend.stories.ts +49 -0
- package/stories/murmur/components/RangePicker.stories.ts +98 -0
- package/stories/murmur/components/ResponsiveIframe.stories.ts +24 -0
- package/stories/murmur/components/ScaleLegend.stories.ts +65 -0
- package/stories/murmur/components/SecretInput.stories.ts +60 -0
- package/stories/murmur/components/SelectableDropdown.stories.ts +143 -0
- package/stories/murmur/components/SharingOptions.stories.ts +32 -0
- package/stories/murmur/components/SharingOptionsLink.stories.ts +53 -0
- package/stories/murmur/components/SignUpForm.stories.ts +51 -0
- package/stories/murmur/components/SlideUpDown.stories.ts +32 -0
- package/stories/murmur/components/TexturedDeck.stories.ts +83 -0
- package/stories/murmur/components/TinyPagination.stories.ts +65 -0
- package/stories/murmur/datavisualisations/BarChart.stories.ts +54 -0
- package/stories/murmur/datavisualisations/ColumnChart.stories.ts +88 -0
- package/stories/murmur/datavisualisations/LineChart.stories.ts +139 -0
- package/stories/murmur/datavisualisations/StackedBarChart.stories.ts +199 -0
- package/stories/murmur/datavisualisations/StackedColumnChart.stories.ts +136 -0
- package/stories/murmur/decorators.ts +108 -0
- package/stories/murmur/maps/ChoroplethMap.stories.ts +440 -0
- package/stories/murmur/maps/ChoroplethMapAnnotation.stories.ts +26 -0
- package/stories/murmur/maps/SymbolMap.stories.ts +24 -0
- package/stories/murmur/utils.ts +7 -0
- package/tests/unit/components/AccordionStep.spec.ts +157 -0
- package/tests/unit/components/AccordionWrapper.spec.ts +57 -0
- package/tests/unit/components/ActiveTextTruncate.spec.js +30 -0
- package/tests/unit/components/AdvancedLinkForm.spec.js +124 -0
- package/tests/unit/components/Brand.spec.js +50 -0
- package/tests/unit/components/ContentPlaceholder.spec.js +29 -0
- package/tests/unit/components/CustomPagination.spec.js +72 -0
- package/tests/unit/components/DigitsInput.spec.ts +157 -0
- package/tests/unit/components/DonateForm.spec.js +149 -0
- package/tests/unit/components/EmbedForm.spec.js +108 -0
- package/tests/unit/components/EmbeddableFooter.spec.js +11 -0
- package/tests/unit/components/Fa.spec.js +18 -0
- package/tests/unit/components/FollowUsPopover.spec.js +29 -0
- package/tests/unit/components/GenericFooter.spec.js +29 -0
- package/tests/unit/components/GenericHeader.spec.js +104 -0
- package/tests/unit/components/HapticCopy.spec.js +123 -0
- package/tests/unit/components/ImddbHeader.spec.js +96 -0
- package/tests/unit/components/OrdinalLegend.spec.js +120 -0
- package/tests/unit/components/RangePicker.spec.ts +87 -0
- package/tests/unit/components/ResponsiveIframe.spec.js +20 -0
- package/tests/unit/components/ScaleLegend.spec.js +139 -0
- package/tests/unit/components/SecretInput.spec.js +81 -0
- package/tests/unit/components/SelectableDropdown.spec.js +160 -0
- package/tests/unit/components/SharingOptions.spec.js +125 -0
- package/tests/unit/components/SharingOptionsLink.spec.js +184 -0
- package/tests/unit/components/SignUpForm.spec.js +145 -0
- package/tests/unit/components/SlideUpDown.spec.js +59 -0
- package/tests/unit/components/TinyPagination.spec.js +46 -0
- package/tests/unit/config.spec.js +136 -0
- package/tests/unit/datavisualisations/BarChart.spec.js +63 -0
- package/tests/unit/datavisualisations/ColumnChart.spec.js +344 -0
- package/tests/unit/datavisualisations/LineChart.spec.js +155 -0
- package/tests/unit/datavisualisations/StackedBarChart.spec.js +294 -0
- package/tests/unit/datavisualisations/StackedColumnChart.spec.js +443 -0
- package/tests/unit/i18n.spec.ts +19 -0
- package/tests/unit/main.spec.js +82 -0
- package/tests/unit/maps/ChoroplethMap.spec.js +214 -0
- package/tests/unit/maps/ChoroplethMapAnnotation.spec.ts +186 -0
- package/tests/unit/maps/SymbolMap.spec.js +92 -0
- package/tests/unit/require.spec.js +22 -0
- package/tests/unit/setup.js +13 -0
- package/tests/unit/utils/assets.spec.js +61 -0
- package/tests/unit/utils/clipboard.spec.js +18 -0
- package/tests/unit/utils/iframe-resizer.spec.js +71 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +79 -0
- package/vitest.config.ts +19 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {defineComponent, VNode, DirectiveBinding, PropType, ref, watch, computed, onBeforeMount, toRef} from 'vue'
|
|
3
|
+
import { faGripLinesVertical } from '@fortawesome/free-solid-svg-icons/faGripLinesVertical'
|
|
4
|
+
import { clamp, get, has, invoke, round } from 'lodash'
|
|
5
|
+
|
|
6
|
+
import Fa, { library } from './Fa'
|
|
7
|
+
|
|
8
|
+
import type { Variant } from '@/types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A component to wrap an HTML element with a range picker overlay.
|
|
12
|
+
*/
|
|
13
|
+
export default defineComponent({
|
|
14
|
+
name: 'RangePicker',
|
|
15
|
+
components: {
|
|
16
|
+
Fa
|
|
17
|
+
},
|
|
18
|
+
directives: {
|
|
19
|
+
draggable: {
|
|
20
|
+
|
|
21
|
+
mounted(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void {
|
|
22
|
+
let startX: number, initialClientX: number
|
|
23
|
+
const relative = binding.modifiers?.relative ?? false
|
|
24
|
+
|
|
25
|
+
// Emit an event to the parent component
|
|
26
|
+
function emitEvent({ name, data = null }: { name: string; data?: any }) {
|
|
27
|
+
vnode.el.dispatchEvent(new CustomEvent(name,{detail: data}))
|
|
28
|
+
//const handlers = get(vnode, 'data.on') ?? get(vnode, 'componentOptions.listeners')
|
|
29
|
+
/*if (has(handlers, name)) {
|
|
30
|
+
invoke(handlers, `${name}.fns`, data)
|
|
31
|
+
}*/
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handle the dragging of the element
|
|
35
|
+
function move(event: MouseEvent | TouchEvent) {
|
|
36
|
+
const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX
|
|
37
|
+
const offset = relative ? el.offsetWidth : 0
|
|
38
|
+
const maxX = binding.instance?.rangeWidth() - offset
|
|
39
|
+
const data = clamp(startX + clientX - initialClientX, 0, maxX)
|
|
40
|
+
emitEvent({ name: 'dragged', data })
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Clean up listeners once the dragging ends
|
|
45
|
+
function end(event: MouseEvent | TouchEvent) {
|
|
46
|
+
emitEvent({ name: 'ended' })
|
|
47
|
+
if (event instanceof MouseEvent) {
|
|
48
|
+
document.removeEventListener('mousemove', move)
|
|
49
|
+
document.removeEventListener('mouseup', end)
|
|
50
|
+
} else {
|
|
51
|
+
document.removeEventListener('touchmove', move)
|
|
52
|
+
document.removeEventListener('touchend', end)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Register listeners when dragging start
|
|
57
|
+
function start(event: MouseEvent | TouchEvent) {
|
|
58
|
+
emitEvent({ name: 'started' })
|
|
59
|
+
startX = el.offsetLeft
|
|
60
|
+
if (event instanceof MouseEvent) {
|
|
61
|
+
initialClientX = event.clientX
|
|
62
|
+
document.addEventListener('mousemove', move)
|
|
63
|
+
document.addEventListener('mouseup', end)
|
|
64
|
+
} else {
|
|
65
|
+
initialClientX = event.touches[0].clientX
|
|
66
|
+
document.addEventListener('touchmove', move)
|
|
67
|
+
document.addEventListener('touchend', end)
|
|
68
|
+
}
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Register the drag and touch event handlers
|
|
73
|
+
el.addEventListener('mousedown', start)
|
|
74
|
+
el.addEventListener('touchstart', start)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
props: {
|
|
79
|
+
/**
|
|
80
|
+
* Initial values of the range bounds. Should contain two numbers.
|
|
81
|
+
* indicating the start and end of the range.
|
|
82
|
+
*/
|
|
83
|
+
range: {
|
|
84
|
+
type: Array as unknown as PropType<[number,number]>,
|
|
85
|
+
required: true
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Enables hover styling on rows.
|
|
89
|
+
*/
|
|
90
|
+
hover: {
|
|
91
|
+
type: Boolean as PropType<boolean>,
|
|
92
|
+
default:false
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* Offset from the left side of the component
|
|
96
|
+
* where the dragging for the start value begins.
|
|
97
|
+
*/
|
|
98
|
+
startOffset: {
|
|
99
|
+
type: [Number,String] as PropType<number|string>,
|
|
100
|
+
default: 0
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Offset from the right side of the component where
|
|
104
|
+
* the dragging for the end value ends.
|
|
105
|
+
*/
|
|
106
|
+
endOffset: {
|
|
107
|
+
type: [Number,String] as PropType<number|string>,
|
|
108
|
+
default: 0
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Number of decimal places to which values should be rounded.
|
|
112
|
+
*/
|
|
113
|
+
precision: {
|
|
114
|
+
type: Number as PropType<number>,
|
|
115
|
+
default: 4
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Snap increment value. For instance,
|
|
119
|
+
* if snap is 0.1, values will snap to 0, 0.1, 0.2, and so on.
|
|
120
|
+
*/
|
|
121
|
+
snap: {
|
|
122
|
+
type: Number as PropType<number>,
|
|
123
|
+
default: 0.0001
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* Minimum distance between the two range bounds to ensure they
|
|
127
|
+
* don't get too close to each other.
|
|
128
|
+
*/
|
|
129
|
+
minDistance: {
|
|
130
|
+
type: Number as PropType<number>,
|
|
131
|
+
default: 0.01
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Variant style of the component. Expected to be one
|
|
135
|
+
* of the predefined Bootstrap theme (e.g., 'primary', 'secondary', etc).
|
|
136
|
+
*/
|
|
137
|
+
variant: {
|
|
138
|
+
type: String as PropType<Variant>,
|
|
139
|
+
default: 'primary'
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* Rounds corner edges of the range boundaries. If
|
|
143
|
+
* true, the component will have rounded corners.
|
|
144
|
+
*/
|
|
145
|
+
rounded: {
|
|
146
|
+
type: Boolean as PropType<boolean>,
|
|
147
|
+
default: false
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
emits:['update:range'],
|
|
151
|
+
setup(props, {emit}){
|
|
152
|
+
onBeforeMount(()=>{
|
|
153
|
+
library.add(faGripLinesVertical)
|
|
154
|
+
})
|
|
155
|
+
const rangePickerBounds = ref<HTMLElement|null>(null)
|
|
156
|
+
const start = toRef(props.range[0] ?? 0)
|
|
157
|
+
const end = toRef(props.range[1] ?? 0)
|
|
158
|
+
const moving = ref( false)
|
|
159
|
+
const resizing = ref( false)
|
|
160
|
+
const disabled = computed(() => {
|
|
161
|
+
return props.range.length < 2
|
|
162
|
+
})
|
|
163
|
+
const overlayStyle = computed((): { left: string; right: string } => {
|
|
164
|
+
return {
|
|
165
|
+
left: `${start.value * 100}%`,
|
|
166
|
+
right: `${(1 - end.value) * 100}%`
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
const boundsStyle = computed((): { left: string; right: string } => {
|
|
170
|
+
return {
|
|
171
|
+
left: startOffsetWithUnit.value,
|
|
172
|
+
right: endOffsetWithUnit.value
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const startOffsetWithUnit = computed((): string => {
|
|
177
|
+
return valueWithUnit(props.startOffset)
|
|
178
|
+
})
|
|
179
|
+
const endOffsetWithUnit = computed((): string => {
|
|
180
|
+
return valueWithUnit(props.endOffset)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const startBoundStyle = computed((): { left: string } => {
|
|
184
|
+
return { left: `${start.value * 100}% ` }
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const endBoundStyle = computed((): { left: string } => {
|
|
188
|
+
return { left: `${end.value * 100}%` }
|
|
189
|
+
})
|
|
190
|
+
const classList = computed((): { [key: string]: boolean } => {
|
|
191
|
+
return {
|
|
192
|
+
[`range-picker--${props.variant}`]: !!props.variant,
|
|
193
|
+
'range-picker--hover': props.hover,
|
|
194
|
+
'range-picker--disabled': disabled.value,
|
|
195
|
+
'range-picker--rounded': props.rounded,
|
|
196
|
+
'range-picker--resizing': resizing.value,
|
|
197
|
+
'range-picker--moving': moving.value
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
function toggleMoving(value){
|
|
203
|
+
moving.value = value ?? !moving.value
|
|
204
|
+
}
|
|
205
|
+
function toggleResizing(value) {
|
|
206
|
+
resizing.value = value ?? !resizing.value
|
|
207
|
+
}
|
|
208
|
+
function snapValue(value): number {
|
|
209
|
+
return round(value / props.snap) * props.snap
|
|
210
|
+
}
|
|
211
|
+
function rangeWidth(): number {
|
|
212
|
+
return rangePickerBounds.value?.getBoundingClientRect().width ?? 0
|
|
213
|
+
}
|
|
214
|
+
function dragStartBound({detail: dx}) {
|
|
215
|
+
|
|
216
|
+
const newValue = snapValue(dx / rangeWidth())
|
|
217
|
+
// Ensure start value doesn't get too close to end value
|
|
218
|
+
if (newValue < end.value - props.minDistance) {
|
|
219
|
+
start.value = round(newValue, props.precision)
|
|
220
|
+
/**
|
|
221
|
+
* Update the values of the range (both start and end)
|
|
222
|
+
* @event update
|
|
223
|
+
* @param Number[] New value of the range
|
|
224
|
+
*/
|
|
225
|
+
emit('update:range', [start.value, end.value])
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function dragEndBound({detail: dx}) {
|
|
229
|
+
const newValue = snapValue(dx / rangeWidth())
|
|
230
|
+
// Ensure end value doesn't get too close to start value
|
|
231
|
+
if (newValue > start.value + props.minDistance) {
|
|
232
|
+
end.value = round(newValue, props.precision)
|
|
233
|
+
/**
|
|
234
|
+
* Update the values of the range (both start and end)
|
|
235
|
+
* @event update
|
|
236
|
+
* @param Number[] New value of the range
|
|
237
|
+
*/
|
|
238
|
+
emit('update:range', [start.value, end.value])
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function dragBounds({detail:dx}) {
|
|
242
|
+
const diff = snapValue(end.value - start.value)
|
|
243
|
+
const newValue = snapValue(dx / rangeWidth())
|
|
244
|
+
start.value = round(newValue, props.precision)
|
|
245
|
+
end.value = round(newValue + diff, props.precision)
|
|
246
|
+
/**
|
|
247
|
+
* Update the values of the range (both start and end)
|
|
248
|
+
* @event update
|
|
249
|
+
* @param Number[] New value of the range
|
|
250
|
+
*/
|
|
251
|
+
emit('update:range', [start.value, end.value])
|
|
252
|
+
}
|
|
253
|
+
function valueWithUnit(value: number | string): string {
|
|
254
|
+
return typeof value === 'number' ? `${value}px` : `${value}`
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
rangePickerBounds,
|
|
258
|
+
start,
|
|
259
|
+
end,
|
|
260
|
+
classList,
|
|
261
|
+
disabled,
|
|
262
|
+
overlayStyle,
|
|
263
|
+
boundsStyle,
|
|
264
|
+
rangeWidth,
|
|
265
|
+
startBoundStyle,
|
|
266
|
+
endBoundStyle,
|
|
267
|
+
dragStartBound,
|
|
268
|
+
dragEndBound,
|
|
269
|
+
dragBounds,
|
|
270
|
+
toggleMoving,
|
|
271
|
+
toggleResizing
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
</script>
|
|
276
|
+
|
|
277
|
+
<template>
|
|
278
|
+
<div class="range-picker" :class="classList">
|
|
279
|
+
<div class="range-picker__wrapper">
|
|
280
|
+
<slot />
|
|
281
|
+
</div>
|
|
282
|
+
<div v-show="!disabled" ref="rangePickerBounds" class="range-picker__bounds" :style="boundsStyle">
|
|
283
|
+
<div
|
|
284
|
+
v-draggable.relative
|
|
285
|
+
class="range-picker__bounds__overlay"
|
|
286
|
+
:style="overlayStyle"
|
|
287
|
+
@dragged="dragBounds"
|
|
288
|
+
@started="toggleMoving(true)"
|
|
289
|
+
@ended="toggleMoving(false)"
|
|
290
|
+
></div>
|
|
291
|
+
<button
|
|
292
|
+
v-draggable
|
|
293
|
+
:style="startBoundStyle"
|
|
294
|
+
class="range-picker__bounds__start btn"
|
|
295
|
+
@dragged="dragStartBound"
|
|
296
|
+
@started="toggleResizing(true)"
|
|
297
|
+
@ended="toggleResizing(false)"
|
|
298
|
+
>
|
|
299
|
+
<fa icon="fa-grip-lines-vertical" fixed-width />
|
|
300
|
+
</button>
|
|
301
|
+
<button
|
|
302
|
+
v-draggable
|
|
303
|
+
class="range-picker__bounds__end btn"
|
|
304
|
+
:style="endBoundStyle"
|
|
305
|
+
@dragged="dragEndBound"
|
|
306
|
+
@started="toggleResizing(true)"
|
|
307
|
+
@ended="toggleResizing(false)"
|
|
308
|
+
>
|
|
309
|
+
<fa icon="fa-grip-lines-vertical" fixed-width />
|
|
310
|
+
</button>
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
</template>
|
|
314
|
+
|
|
315
|
+
<style scoped lang="scss">
|
|
316
|
+
@import '../styles/lib';
|
|
317
|
+
|
|
318
|
+
.range-picker {
|
|
319
|
+
min-height: 1rem;
|
|
320
|
+
position: relative;
|
|
321
|
+
|
|
322
|
+
--bg: #{$component-active-bg};
|
|
323
|
+
--fg: #{$component-active-color};
|
|
324
|
+
|
|
325
|
+
@each $color, $value in $theme-colors {
|
|
326
|
+
&--#{$color} {
|
|
327
|
+
--bg: var(--#{$color}, #{$value});
|
|
328
|
+
--fg: #{color-yiq($value)};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
&--rounded {
|
|
333
|
+
border-radius: $border-radius;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
&--hover:hover &__bounds:after {
|
|
337
|
+
pointer-events: none;
|
|
338
|
+
content: '';
|
|
339
|
+
z-index: -1;
|
|
340
|
+
width: 100%;
|
|
341
|
+
height: 100%;
|
|
342
|
+
display: block;
|
|
343
|
+
background: var(--bg);
|
|
344
|
+
opacity: 0.1;
|
|
345
|
+
border-radius: inherit;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
&--moving &__wrapper,
|
|
349
|
+
&--resizing &__wrapper{
|
|
350
|
+
&,
|
|
351
|
+
* {
|
|
352
|
+
pointer-events: none;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
&--moving,
|
|
357
|
+
&__bounds__overlay,
|
|
358
|
+
&--moving &__bounds__start.btn:not(:disabled):not(.disabled),
|
|
359
|
+
&--moving &__bounds__end.btn:not(:disabled):not(.disabled) {
|
|
360
|
+
cursor: move;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
&--resizing,
|
|
364
|
+
&--resizing &__bounds__overlay,
|
|
365
|
+
&__bounds__start.btn:not(:disabled):not(.disabled),
|
|
366
|
+
&__bounds__end.btn:not(:disabled):not(.disabled) {
|
|
367
|
+
cursor: col-resize;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
&__bounds {
|
|
371
|
+
pointer-events: none;
|
|
372
|
+
position: absolute;
|
|
373
|
+
top: 0;
|
|
374
|
+
height: 100%;
|
|
375
|
+
border-radius: inherit;
|
|
376
|
+
|
|
377
|
+
&__overlay {
|
|
378
|
+
pointer-events: all;
|
|
379
|
+
position: absolute;
|
|
380
|
+
top: 0;
|
|
381
|
+
bottom: 0;
|
|
382
|
+
left: 0;
|
|
383
|
+
right: 0;
|
|
384
|
+
display: flex;
|
|
385
|
+
border-radius: inherit;
|
|
386
|
+
border: 1px solid var(--bg);
|
|
387
|
+
overflow: hidden;
|
|
388
|
+
|
|
389
|
+
&:after {
|
|
390
|
+
content: '';
|
|
391
|
+
width: 100%;
|
|
392
|
+
height: 100%;
|
|
393
|
+
display: block;
|
|
394
|
+
background: var(--bg);
|
|
395
|
+
opacity: 0.3;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
&__start,
|
|
400
|
+
&__end {
|
|
401
|
+
pointer-events: all;
|
|
402
|
+
position: absolute;
|
|
403
|
+
top: 50%;
|
|
404
|
+
transform: translate(-50%, -50%);
|
|
405
|
+
border-radius: 50%;
|
|
406
|
+
font-size: 0.6rem;
|
|
407
|
+
width: 1.2rem;
|
|
408
|
+
height: 1.2rem;
|
|
409
|
+
line-height: 1.2rem;
|
|
410
|
+
padding: 0;
|
|
411
|
+
background: var(--bg);
|
|
412
|
+
color: var(--fg);
|
|
413
|
+
transform: translate(-50%, -50%);
|
|
414
|
+
|
|
415
|
+
&:hover,
|
|
416
|
+
&:active {
|
|
417
|
+
color: var(--fg);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
&__start {
|
|
422
|
+
left: 0;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
&__end {
|
|
426
|
+
left: 100%;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :id="iframeId" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { defineComponent } from 'vue'
|
|
7
|
+
import type { Parent } from 'pym.js'
|
|
8
|
+
|
|
9
|
+
import { injectAssets } from '@/utils/assets'
|
|
10
|
+
|
|
11
|
+
let iframeUniqueIdCounter = 0
|
|
12
|
+
type StartsWithIcijIframe = `icij-iframe-${string}`
|
|
13
|
+
type ResponsiveIframeData = { iframeId: StartsWithIcijIframe; pymParent: null | Parent }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* ResponsiveIframe
|
|
17
|
+
*/
|
|
18
|
+
export default defineComponent({
|
|
19
|
+
name: 'ResponsiveIframe',
|
|
20
|
+
props: {
|
|
21
|
+
/**
|
|
22
|
+
* URL of the generated iframe code.
|
|
23
|
+
*/
|
|
24
|
+
url: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Option to pass to the constructor of the pymParent instance
|
|
30
|
+
*/
|
|
31
|
+
options: {
|
|
32
|
+
type: Object,
|
|
33
|
+
default: () => ({})
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
data(): ResponsiveIframeData {
|
|
37
|
+
return {
|
|
38
|
+
iframeId: `icij-iframe-${++iframeUniqueIdCounter}`,
|
|
39
|
+
pymParent: null
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async mounted(): Promise<void> {
|
|
43
|
+
await injectAssets('https://pym.nprapps.org/pym.v1.min.js')
|
|
44
|
+
//@ts-ignore
|
|
45
|
+
this.pymParent = new window.pym.Parent(this.iframeId, this.url, this.options)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
</script>
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {isFunction, isString} from 'lodash'
|
|
3
|
+
import * as d3 from 'd3'
|
|
4
|
+
import * as scaleFunctions from 'd3-scale'
|
|
5
|
+
import {defineComponent, PropType, ref, computed, onMounted, watch, nextTick, toRef} from 'vue'
|
|
6
|
+
|
|
7
|
+
type ClassListLegend = { 'scale-legend--has-cursor': boolean }
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
type ColorScaleFn = (v?: number) => string
|
|
10
|
+
|
|
11
|
+
type ColorScale = ColorScaleFn | string
|
|
12
|
+
// eslint-disable-next-line no-unused-vars
|
|
13
|
+
type WidthScaleFn = (x: number) => string
|
|
14
|
+
|
|
15
|
+
export default defineComponent({
|
|
16
|
+
name: 'ScaleLegend',
|
|
17
|
+
props: {
|
|
18
|
+
width: {
|
|
19
|
+
type: Number,
|
|
20
|
+
default: 150
|
|
21
|
+
},
|
|
22
|
+
height: {
|
|
23
|
+
type: Number,
|
|
24
|
+
default: 16
|
|
25
|
+
},
|
|
26
|
+
cursorValue: {
|
|
27
|
+
type: Number,
|
|
28
|
+
default: null
|
|
29
|
+
},
|
|
30
|
+
max: {
|
|
31
|
+
type: Number,
|
|
32
|
+
default: 100
|
|
33
|
+
},
|
|
34
|
+
min: {
|
|
35
|
+
type: Number,
|
|
36
|
+
default: 0
|
|
37
|
+
},
|
|
38
|
+
colorScale: {
|
|
39
|
+
type: [Function, String] as PropType<ColorScaleFn | string>,
|
|
40
|
+
default: 'scaleLinear',
|
|
41
|
+
validator(colorScale: ColorScale) {
|
|
42
|
+
return isFunction(colorScale) || (colorScale as string) in scaleFunctions
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
colorScaleEnd: {
|
|
46
|
+
type: String,
|
|
47
|
+
default() {
|
|
48
|
+
const computedStyle = window.getComputedStyle(document.body)
|
|
49
|
+
return computedStyle.getPropertyValue('--primary') || '#000'
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
colorScaleStart: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: '#fff'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
setup(props) {
|
|
58
|
+
const cursorWrapperOffset = ref(0)
|
|
59
|
+
const mounted = ref(false)
|
|
60
|
+
const el = ref<Element | null>(null)
|
|
61
|
+
const classList = computed((): ClassListLegend => {
|
|
62
|
+
return {
|
|
63
|
+
'scale-legend--has-cursor': hasCursor.value
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
const cursorValue = toRef(props.cursorValue)
|
|
67
|
+
onMounted(async () => {
|
|
68
|
+
await nextTick()
|
|
69
|
+
setCursorWrapperOffset()
|
|
70
|
+
setColorScaleCanvas()
|
|
71
|
+
mounted.value = true
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const cursorLeft = computed((): string => {
|
|
75
|
+
const left = cursorLeftScale.value(props.cursorValue)
|
|
76
|
+
return isNaN(left) ? '0%' : `${left}%`
|
|
77
|
+
})
|
|
78
|
+
const colorScaleBaseCanvas = computed((): HTMLCanvasElement | null => {
|
|
79
|
+
return d3.create('canvas').attr('width', props.width).attr('height', props.height).node()
|
|
80
|
+
})
|
|
81
|
+
const colorScaleContext = computed((): CanvasRenderingContext2D | null => {
|
|
82
|
+
return colorScaleBaseCanvas.value?.getContext('2d') ?? null
|
|
83
|
+
})
|
|
84
|
+
const colorScaleBase64 = computed((): string | undefined => {
|
|
85
|
+
if (mounted.value) {
|
|
86
|
+
return colorScaleBaseCanvas.value?.toDataURL() ?? undefined
|
|
87
|
+
}
|
|
88
|
+
return undefined
|
|
89
|
+
})
|
|
90
|
+
const colorScaleWidthRange = computed((): number[] => {
|
|
91
|
+
return d3.range(1, props.width + 1)
|
|
92
|
+
})
|
|
93
|
+
const hasCursor = computed((): boolean => {
|
|
94
|
+
return props.cursorValue != null // double equal also tests undefined
|
|
95
|
+
})
|
|
96
|
+
const colorScaleFunction = computed((): ColorScaleFn => {
|
|
97
|
+
if (isString(props.colorScale)) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
const fn: () => any = scaleFunctions[props.colorScale]
|
|
100
|
+
return fn().domain([props.min, props.max]).range([props.colorScaleStart, props.colorScaleEnd])
|
|
101
|
+
}
|
|
102
|
+
return props.colorScale
|
|
103
|
+
})
|
|
104
|
+
const cursorLeftScale = computed((): d3.ScaleLinear<number, number> => {
|
|
105
|
+
return d3.scaleLinear().domain([props.min, props.max]).range([0, 100]).interpolate(d3.interpolateRound)
|
|
106
|
+
})
|
|
107
|
+
const widthScaleColor = computed((): WidthScaleFn => {
|
|
108
|
+
return (x: number) => {
|
|
109
|
+
const value = widthScale.value(x)
|
|
110
|
+
return colorScaleFunction.value(value)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
const widthScale = computed((): d3.ScaleLinear<number, number> => {
|
|
114
|
+
return d3.scaleLinear().domain([0, props.width]).range([props.min, props.max])
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const formatNumber = d3.format(',')
|
|
118
|
+
|
|
119
|
+
function setCursorWrapperOffset(): void {
|
|
120
|
+
const cursor = el.value?.querySelector('.scale-legend__cursor')
|
|
121
|
+
if (cursor && el.value) {
|
|
122
|
+
const {x: cursorX, width: cursorWidth} = cursor.getBoundingClientRect()
|
|
123
|
+
const {x: legendX, width: legendWidth} = el.value.getBoundingClientRect()
|
|
124
|
+
const left = legendX - cursorX - 6
|
|
125
|
+
const right = legendX + legendWidth - (cursorX + cursorWidth) + 6
|
|
126
|
+
cursorWrapperOffset.value = Math.max(0, left) || Math.min(0, right)
|
|
127
|
+
} else {
|
|
128
|
+
cursorWrapperOffset.value = 0
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function setColorScaleCanvas(): void {
|
|
133
|
+
if (!colorScaleContext.value) {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
for (const x of colorScaleWidthRange.value) {
|
|
137
|
+
colorScaleContext.value.fillStyle = widthScaleColor.value(x)
|
|
138
|
+
colorScaleContext.value.fillRect(x, 0, 1, props.height)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
watch(cursorValue,
|
|
143
|
+
async () => {
|
|
144
|
+
await nextTick()
|
|
145
|
+
setCursorWrapperOffset()
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
classList,
|
|
150
|
+
colorScaleBase64,
|
|
151
|
+
cursorLeft,
|
|
152
|
+
cursorWrapperOffset,
|
|
153
|
+
formatNumber,
|
|
154
|
+
hasCursor,
|
|
155
|
+
//CD: function below are only uses in unit tests. use callable?
|
|
156
|
+
widthScale,
|
|
157
|
+
colorScaleFunction,
|
|
158
|
+
widthScaleColor,
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
</script>
|
|
163
|
+
|
|
164
|
+
<template>
|
|
165
|
+
<div ref="el" :class="classList" class="scale-legend">
|
|
166
|
+
<div class="scale-legend__bound scale-legend__bound--min">
|
|
167
|
+
<slot name="legend-cursor-min" v-bind="{ min }">
|
|
168
|
+
{{ formatNumber(min) }}
|
|
169
|
+
</slot>
|
|
170
|
+
</div>
|
|
171
|
+
<img :height="height" :src="colorScaleBase64" :width="width" class="scale-legend__scale" alt="legend scale"/>
|
|
172
|
+
<div class="scale-legend__bound scale-legend__bound--max">
|
|
173
|
+
<slot name="legend-cursor-max" v-bind="{ max }">
|
|
174
|
+
{{ formatNumber(max) }}
|
|
175
|
+
</slot>
|
|
176
|
+
</div>
|
|
177
|
+
<div v-if="hasCursor" :style="{ left: cursorLeft }" class="scale-legend__cursor">
|
|
178
|
+
<div :style="{ transform: `translateX(${cursorWrapperOffset}px)` }" class="scale-legend__cursor__wrapper">
|
|
179
|
+
<slot name="cursor" v-bind="{ value: cursorValue }">
|
|
180
|
+
{{ formatNumber(cursorValue) }}
|
|
181
|
+
</slot>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</template>
|
|
186
|
+
|
|
187
|
+
<style lang="scss" scoped>
|
|
188
|
+
@import '../styles/lib';
|
|
189
|
+
|
|
190
|
+
.scale-legend {
|
|
191
|
+
position: relative;
|
|
192
|
+
display: inline-block;
|
|
193
|
+
|
|
194
|
+
&__bound,
|
|
195
|
+
&__cursor {
|
|
196
|
+
position: absolute;
|
|
197
|
+
bottom: 100%;
|
|
198
|
+
font-size: 0.8rem;
|
|
199
|
+
|
|
200
|
+
&--min {
|
|
201
|
+
left: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
&--max {
|
|
205
|
+
right: 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.choropleth-map--has-cursor &__bound {
|
|
210
|
+
color: $text-muted;
|
|
211
|
+
opacity: 0.6;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
&__cursor {
|
|
215
|
+
font-weight: bold;
|
|
216
|
+
transform: translateX(-50%);
|
|
217
|
+
left: 50%;
|
|
218
|
+
|
|
219
|
+
&:after {
|
|
220
|
+
content: '';
|
|
221
|
+
border: 5px solid transparent;
|
|
222
|
+
border-top-color: var(--dark, currentColor);
|
|
223
|
+
position: absolute;
|
|
224
|
+
left: 50%;
|
|
225
|
+
top: 100%;
|
|
226
|
+
transform: translateX(-50%);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
</style>
|