Skip to content
Snippets Groups Projects
Commit 5358ed25 authored by Paul Pestov's avatar Paul Pestov
Browse files

feat: add axis info to detailed metric charts

parent d09b6dd3
No related branches found
No related tags found
No related merge requests found
......@@ -47,9 +47,6 @@ function render([data, startDate, endDate]) {
if (data.length === 0) return
console.log(container.value)
// Declare the x (horizontal position) scale.
const x = d3.scaleTime()
.domain([startDate, endDate])
......@@ -84,7 +81,6 @@ function render([data, startDate, endDate]) {
svg.selectAll('.y-axis-group .tick text').attr('fill', colors.gray['400'])
const trend = isUp(data, false)
const pathGroup = svg
......
<script setup lang="ts">
import * as d3 from "d3"
import { ref, watch, computed, onMounted } from "vue"
import type { TimelineChartDataPoint } from "@/types"
import { createTooltip, setEventListeners } from "@/helpers/d3/d3-tooltip"
import colors from 'tailwindcss/colors'
interface Props {
data: TimelineChartDataPoint[],
maxY?: number,
width?: number,
startDate: Date,
endDate: Date,
height?: number,
tooltipContent: (d: TimelineChartDataPoint) => string,
yAxisTitle?: string
}
const props = defineProps<Props>()
const height = props.height || 60
const marginTop = 10
const marginRight = 10
const marginBottom = 30
const marginLeft = 40
const _width = computed(() => props.width ?? 300)
const _maxY = computed(() => props.maxY ?? 2)
const container = ref<HTMLDivElement>()
function isUp(data: TimelineChartDataPoint[], higherIsUp = true) {
if (data.length === 0) return 0
const last = data[data.length - 1].value
const secondLast = data.length > 1 ? data[data.length - 2].value : last
const diff = higherIsUp ? last - secondLast : secondLast - last
if (diff === 0) return 0
else if (diff > 0) return 1
else return -1
}
function render([data, startDate, endDate]) {
if (!data || !startDate || !endDate) return
if (data.length === 0) return
// Declare the x (horizontal position) scale.
const x = d3.scaleTime()
.domain([startDate, endDate])
.range([marginLeft, _width.value - marginRight])
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, _maxY.value])
.range([height - marginBottom, marginTop])
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", _width.value - marginRight)
.attr("height", height)
.classed('!overflow-visible', true)
// Add the x-axis.
svg.append("g")
.classed('x-axis-group', true)
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x).ticks(6).tickSize(4).tickFormat(d3.utcFormat("%d.%m.%Y")))
svg.select('.x-axis-group .domain').attr('stroke', colors.gray['400'])
svg.selectAll('.x-axis-group .tick text').attr('fill', colors.gray['400'])
// Add the y-axis.
svg.append("g")
.classed('y-axis-group', true)
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y).ticks(6).tickSize(0).tickPadding(5))
svg.append("text")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.attr("y", marginLeft - 30)
.attr("x", marginTop - 50)
.text(props.yAxisTitle ?? '')
.attr('fill', colors.gray['400'])
svg.select('.y-axis-group .domain').attr('stroke', colors.gray['400'])
svg.selectAll('.y-axis-group .tick text').attr('fill', colors.gray['400'])
const trend = isUp(data, false)
const pathGroup = svg
.append('g')
.classed('path-group', true)
.classed('up', trend === 1)
.classed('down', trend === -1)
pathGroup.append("path")
.datum(data)
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
const pointGroups = pathGroup.selectAll("myCircles")
.data(data)
.enter()
.append("g")
pointGroups
.append('circle')
.attr("r", 10)
.style('fill', 'transparent')
.style('cursor', 'pointer')
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.classed('chart-point', true)
pointGroups
.append("circle")
.attr("r", 2)
.classed('pointer-events-none', true)
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
const oldTooltip = document.querySelector('.d3-tooltip')
const tooltip = oldTooltip ? d3.select(oldTooltip) : createTooltip(d3.select('body'), {
classes: 'border border-gray-300 bg-white p-2 rounded-md'
})
setEventListeners(svg.selectAll('.chart-point'), tooltip, { useData: props.tooltipContent })
// Append the SVG element.
if (!container.value) return
container.value.replaceChildren()
container.value.append(svg.node())
}
onMounted(() => {
render([props.data, props.startDate, props.endDate])
})
watch([() => props.data, () => props.startDate, () => props.endDate], render)
</script>
<template>
<div ref="container"></div>
</template>
<style lang="scss">
.path-group {
path {
fill: none;
stroke: var(--color--medium-text);
}
circle {
fill: var(--color--medium-text);
}
&.up {
path {
stroke: var(--color--positive-text);
}
circle {
fill: var(--color--positive-text);
}
}
&.down {
path {
stroke: var(--color--negative-text);
}
circle {
fill: var(--color--negative-text);
}
}
}
.y-axis-group {
.tick {
&:first-of-type {
text {
transform: translateY(-3px);
}
}
text {
@apply text-[9px];
}
}
}
</style>
......@@ -7,6 +7,7 @@ import { getMaxValueOfMetric } from '@/helpers/metrics'
import {useI18n} from "vue-i18n";
import { metricChartTooltipContent } from "@/helpers/metric-chart-tooltip-content";
import OverlayPanel from "primevue/overlaypanel";
import BaseTimelineDetailedChart from "@/components/timeline/BaseTimelineDetailedChart.vue";
const { t } = useI18n()
......@@ -81,13 +82,14 @@ function tooltipContent(d: TimelineChartDataPoint) {
ref="op"
:pt="{
root: {
class: 'z-[9999] bg-white border rounded-md shadow-md'
class: 'z-[9999] bg-white border rounded-md shadow-md p-6'
}
}"
>
<BaseTimelineChart
<BaseTimelineDetailedChart
:data="data"
:max-y="maxY"
:y-axis-title="$t(metric)"
:start-date="startDate"
:end-date="endDate"
:tooltip-content="tooltipContent"
......
......@@ -6,6 +6,7 @@ import { getMaxValueOfMetric } from '@/helpers/metrics'
import type { EvaluationResultsDocumentWide, EvaluationRun, TimelineChartDataPoint } from "@/types"
import { metricChartTooltipContent } from "@/helpers/metric-chart-tooltip-content"
import OverlayPanel from 'primevue/overlaypanel'
import BaseTimelineDetailedChart from "@/components/timeline/BaseTimelineDetailedChart.vue"
const props = defineProps(['gtId', 'workflowId', 'metric', 'startDate', 'endDate'])
const runs = ref<EvaluationRun[]>([])
......@@ -64,7 +65,7 @@ function tooltipContent(d: TimelineChartDataPoint) {
}
}"
>
<BaseTimelineChart
<BaseTimelineDetailedChart
:data="data"
:max-y="maxY"
:start-date="startDate"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment