Adjusting text color using D3
When I was working on this calendar visualization, I found a pretty cool method to adjust the text color so that it will appear black on a lighter background and white on a darker background.
<template>
<div style="display: flex;">
<div
v-for="value in items"
:style="{ backgroundColor: `${bgScale(value)}`, width: '30px', height: '30px', display: 'flex', alignItems: 'center', justifyContent: 'center' }"
>
<span :style="{ color: `${colorScale(valueToRatio(value))}` }"
>{{ value }}</span
>
</div>
</div>
</template>
<script>
import * as d3 from "d3";
export default {
props: {
// some random data items
items: {
type: Array,
default: () => [0, 1, 20, 30, 40, 23, 33, 50],
},
},
data() {
return {
// higher value means darker bg color, lower value means lighter bg color
bgScale: d3.scaleQuantize(
[0, d3.max(this.items, (value) => value)],
d3.schemeBlues[9],
),
// higher value will have white color, lower value will have black color
colorScale: d3.scaleQuantize([0, 1], ["black", "white"]),
// function to transform value into a ratio
valueToRatio: d3
.scaleLinear()
.domain([0, d3.max(this.items, (value) => value)])
.range([0, 1]),
};
},
};
</script>
The idea is to transform our data into a ratio with valueToRatio
function, and have two scale functions for background and text color.
With a untransformed value, get the background color from bgScale
which returns a lighter color on the lower range, and a darker color on the lower range. Then with a ratio value, get the text color from colorScale
which returns a darker color on the lower range, and a lighter color on the higher range.