logarithmic graph
This commit is contained in:
141
frontend/src/components/SvgGraph.vue
Normal file
141
frontend/src/components/SvgGraph.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, provide } from 'vue'
|
||||
import { useNow } from '@/composables/ticker'
|
||||
import { GRAPH_DATA, type GraphData } from '@/graph/graph'
|
||||
|
||||
const props = defineProps<{
|
||||
width: number
|
||||
height: number
|
||||
border_left_right?: number
|
||||
border_top_bottom?: number
|
||||
// min_x?: number
|
||||
// max_x?: number
|
||||
}>()
|
||||
|
||||
const svg_viewbox = computed(() => {
|
||||
return `0 0 ${props.width} ${props.height}`
|
||||
})
|
||||
const now = useNow(33)
|
||||
const window_duration = 30 * 1000 // 30 seconds
|
||||
|
||||
const time_lines = [
|
||||
1, // 1ms
|
||||
10, // 10ms
|
||||
100, // 100ms
|
||||
1000, // 1s
|
||||
5000, // 5s
|
||||
10000, // 10s
|
||||
30000, // 30s
|
||||
60000, // 1m
|
||||
300000, // 5m
|
||||
6000000, // 10m
|
||||
18000000, // 30m
|
||||
36000000, // 1h
|
||||
144000000, // 4h
|
||||
216000000, // 6h
|
||||
432000000, // 12h
|
||||
864000000, // 1d
|
||||
6048000000, // 1w
|
||||
]
|
||||
time_lines.reverse()
|
||||
const text_offset = computed(() => 5)
|
||||
|
||||
const border_left_right = computed(() => props.border_left_right || 0)
|
||||
const border_top_bottom = computed(() => props.border_top_bottom || 0)
|
||||
|
||||
const max_x = now
|
||||
const min_x = computed(() => max_x.value - window_duration)
|
||||
|
||||
const x_map = (x: number) => {
|
||||
const diff_x = max_x.value - min_x.value
|
||||
return (
|
||||
((props.width - 2 * border_left_right.value) * (x - min_x.value)) / diff_x +
|
||||
border_left_right.value
|
||||
)
|
||||
}
|
||||
|
||||
provide<GraphData>(GRAPH_DATA, {
|
||||
border_top_bottom: border_top_bottom,
|
||||
min_x: min_x,
|
||||
max_x: now,
|
||||
width: () => props.width - 2 * border_left_right.value,
|
||||
height: () => props.height - 2 * border_top_bottom.value,
|
||||
x_map: x_map,
|
||||
})
|
||||
|
||||
const lines = computed(() => {
|
||||
const diff_x = max_x.value - min_x.value
|
||||
const duration = time_lines.find(duration => diff_x / duration >= 3)!
|
||||
const result = []
|
||||
for (
|
||||
let i = Math.ceil(max_x.value / duration);
|
||||
i >= Math.ceil(min_x.value / duration) - 5;
|
||||
i--
|
||||
) {
|
||||
const x = i * duration
|
||||
result.push(x)
|
||||
}
|
||||
return result
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg :viewBox="svg_viewbox" :width="props.width" :height="props.height">
|
||||
<defs>
|
||||
<clipPath id="content">
|
||||
<rect
|
||||
:x="border_left_right"
|
||||
:y="border_top_bottom"
|
||||
:width="width - border_left_right * 2"
|
||||
:height="height - border_top_bottom * 2"
|
||||
></rect>
|
||||
</clipPath>
|
||||
<clipPath id="y_ticker">
|
||||
<rect
|
||||
:x="0"
|
||||
:y="border_top_bottom"
|
||||
:width="width"
|
||||
:height="height - border_top_bottom * 2"
|
||||
></rect>
|
||||
</clipPath>
|
||||
<clipPath id="x_ticker">
|
||||
<rect
|
||||
:x="border_left_right"
|
||||
:y="0"
|
||||
:width="width - border_left_right * 2"
|
||||
:height="height"
|
||||
></rect>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g class="time_tick" clip-path="url(#x_ticker)">
|
||||
<template v-for="tick of lines" :key="tick">
|
||||
<polyline
|
||||
:points="`${x_map(tick)},${border_top_bottom} ${x_map(tick)},${height - border_top_bottom}`"
|
||||
></polyline>
|
||||
<text
|
||||
class="bottom_edge"
|
||||
:transform="`translate(${x_map(tick)},${height - border_top_bottom + text_offset}) rotate(0)`"
|
||||
>
|
||||
{{ new Date(tick).toLocaleString() }}
|
||||
</text>
|
||||
</template>
|
||||
</g>
|
||||
<slot></slot>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bottom_edge {
|
||||
text-anchor: middle;
|
||||
alignment-baseline: text-before-edge;
|
||||
font-family: Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.time_tick {
|
||||
stroke: #ffffff;
|
||||
stroke-width: 1px;
|
||||
fill: #ffffff;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user