UNPKG

vuetify

Version:

Vue Material Component Framework

225 lines (224 loc) 7.71 kB
import { createElementVNode as _createElementVNode, createVNode as _createVNode, normalizeClass as _normalizeClass } from "vue"; // Styles import "./VHeatmap.css"; // Components import { VHeatmapCell } from "./VHeatmapCell.js"; import { VHeatmapLegend } from "./VHeatmapLegend.js"; // Composables import { useHeatmap } from "./heatmap.js"; import { makeThemeProps, provideTheme } from "../../composables/theme.js"; // Utilities import { computed, ref, watch } from 'vue'; import { convertToUnit, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types export const makeVHeatmapProps = propsFactory({ cellSize: { type: [Number, String, Array], default: 26 }, gap: { type: [Number, String], default: 6 }, groupGap: { type: [Number, String], default: 0 }, rounded: [Number, String], hideColumnHeaders: Boolean, hideRowHeaders: Boolean, legend: { type: [Boolean, Object], default: false }, hover: Boolean, hoverScale: { type: [Number, String], default: 0.85 }, items: { type: Array, default: () => [] }, itemValue: { type: [String, Array, Function], default: 'value' }, itemRow: { type: [String, Array, Function], default: 'row' }, itemColumn: { type: [String, Array, Function], default: 'column' }, groupBy: [String, Array, Function], itemProps: [Object, Function], thresholds: { type: [Array, Object], default: () => [] }, emptyColor: String, rows: Array, columns: Array, ...makeThemeProps() }, 'VHeatmap'); export const VHeatmap = genericComponent()({ name: 'VHeatmap', props: makeVHeatmapProps(), setup(props, { slots }) { const { themeClasses } = provideTheme(props); const { rows, rowItems, groups, hasExplicitColumns, cellWidth, cellHeight, gap, cellStep, rowStep, totalWidth, totalHeight, bucketColors, linearColors, colorSpaceClass, bucketBoundaries } = useHeatmap(props); const activeBuckets = ref([]); const colorProperties = computed(() => { const style = {}; const buckets = bucketColors.value; const linear = linearColors.value; for (let i = 0; i < buckets.length; i++) { style[`--v-heatmap-color-bucket-${i}`] = buckets[i]; } if (linear) { style['--v-heatmap-color-start'] = linear.from; style['--v-heatmap-color-end'] = linear.to; } return style; }); watch(bucketBoundaries, val => { activeBuckets.value = val.map((_, i) => i); }, { immediate: true }); function toggle(index) { const position = activeBuckets.value.indexOf(index); if (position >= 0) activeBuckets.value.splice(position, 1);else activeBuckets.value.push(index); } function isDisabled(cell) { if (cell.bucketIndex < 0) return false; return !activeBuckets.value.includes(cell.bucketIndex); } useRender(() => { const radius = convertToUnit(props.rounded); const hasGroupLabels = !props.hideColumnHeaders && (!!slots['group-header'] || groups.value.some(group => group.label)); const hasColumnHeaders = !props.hideColumnHeaders && hasExplicitColumns.value; const itemProps = props.itemProps; const hasCellSlot = !!slots.cell; const space = colorSpaceClass.value; return _createElementVNode("div", { "class": _normalizeClass(['v-heatmap', { 'v-heatmap--hover': props.hover, 'v-heatmap--hide-column-headers': props.hideColumnHeaders, 'v-heatmap--hide-row-headers': props.hideRowHeaders, 'v-heatmap--has-group-labels': hasGroupLabels, 'v-heatmap--has-column-headers': hasColumnHeaders }, space && `v-heatmap--color-space-${space}`, themeClasses.value]), "style": { '--v-heatmap-cell-width': `${cellWidth.value}px`, '--v-heatmap-cell-height': `${cellHeight.value}px`, '--v-heatmap-cell-gap': `${gap.value}px`, '--v-heatmap-cell-radius': radius, '--v-heatmap-hover-scale': props.hover ? Number(props.hoverScale) : undefined, '--v-heatmap-rows-count': rows.value.length, '--v-heatmap-empty-color': props.emptyColor, ...colorProperties.value } }, [_createElementVNode("div", { "class": "v-heatmap__body" }, [hasGroupLabels && _createElementVNode("div", { "class": "v-heatmap__group-labels", "key": "group-labels", "style": { width: `${totalWidth.value}px` } }, [groups.value.map(group => _createElementVNode("div", { "key": group.key, "class": "v-heatmap__group-label", "style": { insetInlineStart: `${group.x}px`, width: `${group.width}px`, paddingInlineStart: group.labelOffset ? `${group.labelOffset}px` : undefined } }, [slots['group-header']?.({ group, items: group.items }) ?? group.label]))]), hasColumnHeaders && _createElementVNode("div", { "class": "v-heatmap__column-headers", "key": "column-headers", "style": { width: `${totalWidth.value}px` } }, [groups.value.flatMap(group => group.columns.map((col, index) => _createElementVNode("div", { "key": `column-header-${group.key}-${col.key}`, "class": "v-heatmap__column-header", "style": { insetInlineStart: `${group.x + index * cellStep.value}px`, width: `${cellWidth.value}px` } }, [slots['column-header']?.({ column: col.key, index, items: col.items }) ?? col.key])))]), !props.hideRowHeaders && _createElementVNode("div", { "class": "v-heatmap__row-headers", "key": "row-headers" }, [rows.value.map((row, index) => _createElementVNode("div", { "key": `row-header-${index}`, "class": "v-heatmap__row-header" }, [slots['row-header']?.({ row, index, items: rowItems.value.get(row) ?? [] }) ?? row]))]), _createElementVNode("svg", { "class": "v-heatmap__grid", "width": totalWidth.value, "height": totalHeight.value, "viewBox": `0 0 ${totalWidth.value} ${totalHeight.value}` }, [groups.value.flatMap(group => group.columns.flatMap((col, columnIndex) => col.cells.map((cell, rowIndex) => { if (!cell) return null; const cellProps = (typeof itemProps === 'function' ? itemProps(cell) : itemProps) ?? {}; return _createVNode(VHeatmapCell, { "key": `${group.key}-${columnIndex}-${rowIndex}`, "item": cell, "x": group.x + columnIndex * cellStep.value, "y": rowIndex * rowStep.value, "width": cellWidth.value, "height": cellHeight.value, "disabled": isDisabled(cell), "cellProps": cellProps }, hasCellSlot ? { default: () => slots.cell({ item: cell }) } : undefined); })))])]), props.legend && (slots.legend?.({ thresholds: props.thresholds, activeBuckets: activeBuckets.value, toggle }) ?? _createVNode(VHeatmapLegend, { "cellSize": (typeof props.legend === 'object' ? props.legend.cellSize : undefined) ?? props.cellSize, "thresholds": props.thresholds, "activeBuckets": activeBuckets.value, "rounded": props.rounded, "labels": typeof props.legend === 'object' ? props.legend.labels : undefined, "onClick:threshold": toggle }, null))]); }); } }); //# sourceMappingURL=VHeatmap.js.map