update colors
This commit is contained in:
parent
b92fbadcc3
commit
bdac3ee430
|
@ -11,6 +11,7 @@
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.181",
|
||||||
"@types/sprintf-js": "^1.1.2",
|
"@types/sprintf-js": "^1.1.2",
|
||||||
"bulma": "^0.9.4",
|
"bulma": "^0.9.4",
|
||||||
|
"chroma-js": "^2.4.2",
|
||||||
"clusterize.js": "^0.19.0",
|
"clusterize.js": "^0.19.0",
|
||||||
"d3": "^7.4.0",
|
"d3": "^7.4.0",
|
||||||
"d3-svg-legend": "^2.25.6",
|
"d3-svg-legend": "^2.25.6",
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
"tippy.js": "^6.3.7"
|
"tippy.js": "^6.3.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/chroma-js": "^2.1.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
||||||
"@typescript-eslint/parser": "^5.22.0",
|
"@typescript-eslint/parser": "^5.22.0",
|
||||||
"eslint": "^8.15.0",
|
"eslint": "^8.15.0",
|
||||||
|
@ -173,6 +175,12 @@
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/chroma-js": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-l9hWzP7cp7yleJUI7P2acmpllTJNYf5uU6wh50JzSIZt3fFHe+w2FM6w9oZGBTYzjjm2qHdnQvI+fF/JF/E5jQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/clusterize.js": {
|
"node_modules/@types/clusterize.js": {
|
||||||
"version": "0.18.1",
|
"version": "0.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clusterize.js/-/clusterize.js-0.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clusterize.js/-/clusterize.js-0.18.1.tgz",
|
||||||
|
@ -950,6 +958,11 @@
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chroma-js": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
|
||||||
|
},
|
||||||
"node_modules/clusterize.js": {
|
"node_modules/clusterize.js": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/clusterize.js/-/clusterize.js-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/clusterize.js/-/clusterize.js-0.19.0.tgz",
|
||||||
|
@ -3188,6 +3201,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz",
|
||||||
"integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw=="
|
"integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw=="
|
||||||
},
|
},
|
||||||
|
"@types/chroma-js": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-l9hWzP7cp7yleJUI7P2acmpllTJNYf5uU6wh50JzSIZt3fFHe+w2FM6w9oZGBTYzjjm2qHdnQvI+fF/JF/E5jQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/clusterize.js": {
|
"@types/clusterize.js": {
|
||||||
"version": "0.18.1",
|
"version": "0.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clusterize.js/-/clusterize.js-0.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clusterize.js/-/clusterize.js-0.18.1.tgz",
|
||||||
|
@ -3783,6 +3802,11 @@
|
||||||
"readdirp": "~3.6.0"
|
"readdirp": "~3.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"chroma-js": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
|
||||||
|
},
|
||||||
"clusterize.js": {
|
"clusterize.js": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/clusterize.js/-/clusterize.js-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/clusterize.js/-/clusterize.js-0.19.0.tgz",
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
"@types/jquery": "^3.5.14",
|
"@types/jquery": "^3.5.14",
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.181",
|
||||||
"@types/sprintf-js": "^1.1.2",
|
"@types/sprintf-js": "^1.1.2",
|
||||||
|
"bulma": "^0.9.4",
|
||||||
|
"chroma-js": "^2.4.2",
|
||||||
"clusterize.js": "^0.19.0",
|
"clusterize.js": "^0.19.0",
|
||||||
"d3": "^7.4.0",
|
"d3": "^7.4.0",
|
||||||
"d3-svg-legend": "^2.25.6",
|
"d3-svg-legend": "^2.25.6",
|
||||||
|
@ -13,10 +15,10 @@
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7"
|
||||||
"bulma": "^0.9.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/chroma-js": "^2.1.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
||||||
"@typescript-eslint/parser": "^5.22.0",
|
"@typescript-eslint/parser": "^5.22.0",
|
||||||
"eslint": "^8.15.0",
|
"eslint": "^8.15.0",
|
||||||
|
|
|
@ -15,8 +15,10 @@ import {
|
||||||
secondName,
|
secondName,
|
||||||
textColor,
|
textColor,
|
||||||
tooltip,
|
tooltip,
|
||||||
skipTicks
|
skipTicks,
|
||||||
|
generateColorScheme
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
import COLORS from "./colors";
|
||||||
|
|
||||||
export default async function () {
|
export default async function () {
|
||||||
const {
|
const {
|
||||||
|
@ -55,7 +57,7 @@ function renderAllocationTarget(allocationTargets: AllocationTarget[]) {
|
||||||
|
|
||||||
const keys = ["target", "current"];
|
const keys = ["target", "current"];
|
||||||
const colorKeys = ["target", "current", "diff"];
|
const colorKeys = ["target", "current", "diff"];
|
||||||
const colors = ["#1f77b4", "#17becf", "#4a4a4a"];
|
const colors = [COLORS.primary, COLORS.secondary, COLORS.diff];
|
||||||
|
|
||||||
const y = d3.scaleBand().range([0, height]).paddingInner(0).paddingOuter(0);
|
const y = d3.scaleBand().range([0, height]).paddingInner(0).paddingOuter(0);
|
||||||
y.domain(allocationTargets.map((t) => t.name));
|
y.domain(allocationTargets.map((t) => t.name));
|
||||||
|
@ -244,7 +246,7 @@ function renderPartition(element: HTMLElement, aggregates, hierarchy) {
|
||||||
return formatFloat((d.value / root.value) * 100) + "%";
|
return formatFloat((d.value / root.value) * 100) + "%";
|
||||||
};
|
};
|
||||||
|
|
||||||
const color = rainbowScale(_.keys(aggregates));
|
const color = generateColorScheme(_.keys(aggregates));
|
||||||
|
|
||||||
const stratify = d3
|
const stratify = d3
|
||||||
.stratify<Aggregate>()
|
.stratify<Aggregate>()
|
||||||
|
@ -373,7 +375,7 @@ function renderAllocationTimeline(
|
||||||
0,
|
0,
|
||||||
d3.max(d3.map(points, (p) => d3.max(_.values(_.omit(p, "date")))))
|
d3.max(d3.map(points, (p) => d3.max(_.values(_.omit(p, "date")))))
|
||||||
]),
|
]),
|
||||||
z = d3.scaleOrdinal(d3.schemeCategory10).domain(assets);
|
z = generateColorScheme(assets);
|
||||||
|
|
||||||
const line = (group) =>
|
const line = (group) =>
|
||||||
d3
|
d3
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
const COLORS = {
|
||||||
|
gain: "#b2df8a",
|
||||||
|
gainText: "#48c78e",
|
||||||
|
loss: "#fb9a99",
|
||||||
|
lossText: "#f14668",
|
||||||
|
primary: "#1f77b4",
|
||||||
|
secondary: "#17becf",
|
||||||
|
tertiary: "#ff7f0e",
|
||||||
|
diff: "#4a4a4a"
|
||||||
|
};
|
||||||
|
export default COLORS;
|
|
@ -1,7 +1,7 @@
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import legend from "d3-svg-legend";
|
import legend from "d3-svg-legend";
|
||||||
import { sprintf } from "sprintf-js";
|
|
||||||
import dayjs, { Dayjs } from "dayjs";
|
import dayjs, { Dayjs } from "dayjs";
|
||||||
|
import chroma from "chroma-js";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import {
|
import {
|
||||||
ajax,
|
ajax,
|
||||||
|
@ -14,8 +14,10 @@ import {
|
||||||
secondName,
|
secondName,
|
||||||
setHtml,
|
setHtml,
|
||||||
skipTicks,
|
skipTicks,
|
||||||
tooltip
|
tooltip,
|
||||||
|
generateColorScheme
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
import COLORS from "./colors";
|
||||||
|
|
||||||
export default async function () {
|
export default async function () {
|
||||||
const {
|
const {
|
||||||
|
@ -82,10 +84,10 @@ function renderSelectedMonth(
|
||||||
investments: Posting[]
|
investments: Posting[]
|
||||||
) {
|
) {
|
||||||
renderer(expenses);
|
renderer(expenses);
|
||||||
setHtml("current-month-income", sum(incomes, -1));
|
setHtml("current-month-income", sum(incomes, -1), COLORS.gainText);
|
||||||
setHtml("current-month-tax", sum(taxes));
|
setHtml("current-month-tax", sum(taxes), COLORS.lossText);
|
||||||
setHtml("current-month-expenses", sum(expenses));
|
setHtml("current-month-expenses", sum(expenses), COLORS.lossText);
|
||||||
setHtml("current-month-investment", sum(investments));
|
setHtml("current-month-investment", sum(investments), COLORS.secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sum(postings: Posting[], sign = 1) {
|
function sum(postings: Posting[], sign = 1) {
|
||||||
|
@ -159,7 +161,7 @@ function renderMonthlyExpensesTimeline(
|
||||||
x.domain(points.map((p) => p.month));
|
x.domain(points.map((p) => p.month));
|
||||||
y.domain([0, d3.max(points, sum)]);
|
y.domain([0, d3.max(points, sum)]);
|
||||||
|
|
||||||
const z = d3.scaleOrdinal<string>().range(d3.schemeCategory10);
|
const z = generateColorScheme(groups);
|
||||||
|
|
||||||
g.append("g")
|
g.append("g")
|
||||||
.attr("class", "axis x")
|
.attr("class", "axis x")
|
||||||
|
@ -401,8 +403,8 @@ function renderCurrentExpensesBreakdown(
|
||||||
.style("white-space", "pre")
|
.style("white-space", "pre")
|
||||||
.style("font-size", "13px")
|
.style("font-size", "13px")
|
||||||
.style("font-weight", "bold")
|
.style("font-weight", "bold")
|
||||||
.attr("fill", function (d) {
|
.style("fill", function (d) {
|
||||||
return z(d.category);
|
return chroma(z(d.category)).darken(0.8).hex();
|
||||||
})
|
})
|
||||||
.attr("class", "is-family-monospace")
|
.attr("class", "is-family-monospace")
|
||||||
.text(
|
.text(
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import chroma from "chroma-js";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import legend from "d3-svg-legend";
|
import legend from "d3-svg-legend";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import COLORS from "./colors";
|
||||||
import {
|
import {
|
||||||
ajax,
|
ajax,
|
||||||
formatCurrency,
|
formatCurrency,
|
||||||
|
@ -26,13 +28,13 @@ export default async function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const areaKeys = ["gain", "loss"];
|
const areaKeys = ["gain", "loss"];
|
||||||
const colors = ["#b2df8a", "#fb9a99"];
|
const colors = [COLORS.gain, COLORS.loss];
|
||||||
const areaScale = d3.scaleOrdinal<string>().domain(areaKeys).range(colors);
|
const areaScale = d3.scaleOrdinal<string>().domain(areaKeys).range(colors);
|
||||||
const lineKeys = ["balance", "investment", "withdrawal"];
|
const lineKeys = ["balance", "investment", "withdrawal"];
|
||||||
const lineScale = d3
|
const lineScale = d3
|
||||||
.scaleOrdinal<string>()
|
.scaleOrdinal<string>()
|
||||||
.domain(lineKeys)
|
.domain(lineKeys)
|
||||||
.range(["#1f77b4", "#17becf", "#ff7f0e"]);
|
.range([COLORS.primary, COLORS.secondary, COLORS.tertiary]);
|
||||||
|
|
||||||
function renderTable(gain: Gain) {
|
function renderTable(gain: Gain) {
|
||||||
const tbody = d3.select(this);
|
const tbody = d3.select(this);
|
||||||
|
@ -95,7 +97,13 @@ function renderOverview(gains: Gain[]) {
|
||||||
.paddingOuter(0.1);
|
.paddingOuter(0.1);
|
||||||
|
|
||||||
const keys = ["balance", "investment", "withdrawal", "gain", "loss"];
|
const keys = ["balance", "investment", "withdrawal", "gain", "loss"];
|
||||||
const colors = ["#1f77b4", "#17becf", "#ff7f0e", "#b2df8a", "#fb9a99"];
|
const colors = [
|
||||||
|
COLORS.primary,
|
||||||
|
COLORS.secondary,
|
||||||
|
COLORS.tertiary,
|
||||||
|
COLORS.gain,
|
||||||
|
COLORS.loss
|
||||||
|
];
|
||||||
const z = d3.scaleOrdinal<string>(colors).domain(keys);
|
const z = d3.scaleOrdinal<string>(colors).domain(keys);
|
||||||
|
|
||||||
const getInvestmentAmount = (g: Gain) =>
|
const getInvestmentAmount = (g: Gain) =>
|
||||||
|
@ -203,7 +211,9 @@ function renderOverview(gains: Gain[]) {
|
||||||
.text((g) => formatCurrency(getGainAmount(g)))
|
.text((g) => formatCurrency(getGainAmount(g)))
|
||||||
.attr("alignment-baseline", "hanging")
|
.attr("alignment-baseline", "hanging")
|
||||||
.attr("text-anchor", "end")
|
.attr("text-anchor", "end")
|
||||||
.style("fill", (g) => (getGainAmount(g) > 0 ? z("gain") : "none"))
|
.style("fill", (g) =>
|
||||||
|
getGainAmount(g) > 0 ? chroma(z("gain")).darken().hex() : "none"
|
||||||
|
)
|
||||||
.attr("dx", "-3")
|
.attr("dx", "-3")
|
||||||
.attr("dy", "3")
|
.attr("dy", "3")
|
||||||
.attr("x", textGroupZero + (textGroupWidth * 2) / 3)
|
.attr("x", textGroupZero + (textGroupWidth * 2) / 3)
|
||||||
|
@ -223,7 +233,9 @@ function renderOverview(gains: Gain[]) {
|
||||||
.append("text")
|
.append("text")
|
||||||
.text((g) => formatCurrency(getGainAmount(g)))
|
.text((g) => formatCurrency(getGainAmount(g)))
|
||||||
.attr("text-anchor", "end")
|
.attr("text-anchor", "end")
|
||||||
.style("fill", (g) => (getGainAmount(g) < 0 ? z("loss") : "none"))
|
.style("fill", (g) =>
|
||||||
|
getGainAmount(g) < 0 ? chroma(z("loss")).darken().hex() : "none"
|
||||||
|
)
|
||||||
.attr("dx", "-3")
|
.attr("dx", "-3")
|
||||||
.attr("dy", "-3")
|
.attr("dy", "-3")
|
||||||
.attr("x", textGroupZero + (textGroupWidth * 2) / 3)
|
.attr("x", textGroupZero + (textGroupWidth * 2) / 3)
|
||||||
|
@ -254,7 +266,11 @@ function renderOverview(gains: Gain[]) {
|
||||||
.text((g) => formatFloat(g.xirr))
|
.text((g) => formatFloat(g.xirr))
|
||||||
.attr("text-anchor", "end")
|
.attr("text-anchor", "end")
|
||||||
.attr("alignment-baseline", "middle")
|
.attr("alignment-baseline", "middle")
|
||||||
.style("fill", (g) => (g.xirr < 0 ? z("loss") : z("gain")))
|
.style("fill", (g) =>
|
||||||
|
g.xirr < 0
|
||||||
|
? chroma(z("loss")).darken().hex()
|
||||||
|
: chroma(z("gain")).darken().hex()
|
||||||
|
)
|
||||||
.attr("x", xirrWidth + xirrTextWidth)
|
.attr("x", xirrWidth + xirrTextWidth)
|
||||||
.attr("y", (g) => y(restName(g.account)) + y.bandwidth() / 2);
|
.attr("y", (g) => y(restName(g.account)) + y.bandwidth() / 2);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@ import * as d3 from "d3";
|
||||||
import legend from "d3-svg-legend";
|
import legend from "d3-svg-legend";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import COLORS from "./colors";
|
||||||
import {
|
import {
|
||||||
ajax,
|
ajax,
|
||||||
formatCurrency,
|
formatCurrency,
|
||||||
formatCurrencyCrude,
|
formatCurrencyCrude,
|
||||||
|
generateColorScheme,
|
||||||
Income,
|
Income,
|
||||||
Posting,
|
Posting,
|
||||||
restName,
|
restName,
|
||||||
|
@ -27,8 +29,8 @@ export default async function () {
|
||||||
|
|
||||||
const netTax = _.sumBy(taxes, (t) => _.sumBy(t.postings, (p) => p.amount));
|
const netTax = _.sumBy(taxes, (t) => _.sumBy(t.postings, (p) => p.amount));
|
||||||
|
|
||||||
setHtml("gross-income", formatCurrency(grossIncome));
|
setHtml("gross-income", formatCurrency(grossIncome), COLORS.gainText);
|
||||||
setHtml("net-tax", formatCurrency(netTax));
|
setHtml("net-tax", formatCurrency(netTax), COLORS.lossText);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMonthlyInvestmentTimeline(incomes: Income[]) {
|
function renderMonthlyInvestmentTimeline(incomes: Income[]) {
|
||||||
|
@ -119,7 +121,7 @@ function renderIncomeTimeline(
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const z = d3.scaleOrdinal<string>().range(d3.schemeCategory10);
|
const z = generateColorScheme(groupKeys);
|
||||||
|
|
||||||
g.append("g")
|
g.append("g")
|
||||||
.attr("class", "axis x")
|
.attr("class", "axis x")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
formatCurrency,
|
formatCurrency,
|
||||||
formatCurrencyCrude,
|
formatCurrencyCrude,
|
||||||
formatFloat,
|
formatFloat,
|
||||||
|
generateColorScheme,
|
||||||
Posting,
|
Posting,
|
||||||
secondName,
|
secondName,
|
||||||
skipTicks,
|
skipTicks,
|
||||||
|
@ -132,7 +133,7 @@ function renderMonthlyInvestmentTimeline(postings: Posting[]) {
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const z = d3.scaleOrdinal<string>().range(d3.schemeCategory10);
|
const z = generateColorScheme(groups);
|
||||||
|
|
||||||
g.append("g")
|
g.append("g")
|
||||||
.attr("class", "axis x")
|
.attr("class", "axis x")
|
||||||
|
@ -312,7 +313,7 @@ function renderYearlyInvestmentTimeline(yearlyCards: YearlyCard[]) {
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const z = d3.scaleOrdinal<string>().range(d3.schemeCategory10);
|
const z = generateColorScheme(groups);
|
||||||
|
|
||||||
g.append("g")
|
g.append("g")
|
||||||
.attr("class", "axis y")
|
.attr("class", "axis y")
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as d3 from "d3";
|
||||||
import legend from "d3-svg-legend";
|
import legend from "d3-svg-legend";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import COLORS from "./colors";
|
||||||
import {
|
import {
|
||||||
ajax,
|
ajax,
|
||||||
formatCurrency,
|
formatCurrency,
|
||||||
|
@ -22,13 +23,19 @@ export default async function () {
|
||||||
current.investment_amount +
|
current.investment_amount +
|
||||||
current.gain_amount -
|
current.gain_amount -
|
||||||
current.withdrawal_amount
|
current.withdrawal_amount
|
||||||
)
|
),
|
||||||
|
COLORS.primary
|
||||||
);
|
);
|
||||||
setHtml(
|
setHtml(
|
||||||
"investment",
|
"investment",
|
||||||
formatCurrency(current.investment_amount - current.withdrawal_amount)
|
formatCurrency(current.investment_amount - current.withdrawal_amount),
|
||||||
|
COLORS.secondary
|
||||||
|
);
|
||||||
|
setHtml(
|
||||||
|
"gains",
|
||||||
|
formatCurrency(current.gain_amount),
|
||||||
|
current.gain_amount >= 0 ? COLORS.gainText : COLORS.lossText
|
||||||
);
|
);
|
||||||
setHtml("gains", formatCurrency(current.gain_amount));
|
|
||||||
setHtml("xirr", formatFloat(xirr));
|
setHtml("xirr", formatFloat(xirr));
|
||||||
|
|
||||||
renderOverview(points, document.getElementById("d3-overview-timeline"));
|
renderOverview(points, document.getElementById("d3-overview-timeline"));
|
||||||
|
@ -47,7 +54,7 @@ function renderOverview(points: Overview[], element: Element) {
|
||||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||||
|
|
||||||
const areaKeys = ["gain", "loss"];
|
const areaKeys = ["gain", "loss"];
|
||||||
const colors = ["#b2df8a", "#fb9a99"];
|
const colors = [COLORS.gain, COLORS.loss];
|
||||||
const areaScale = d3.scaleOrdinal().domain(areaKeys).range(colors);
|
const areaScale = d3.scaleOrdinal().domain(areaKeys).range(colors);
|
||||||
|
|
||||||
const lineKeys = ["networth", "investment"];
|
const lineKeys = ["networth", "investment"];
|
||||||
|
@ -55,7 +62,7 @@ function renderOverview(points: Overview[], element: Element) {
|
||||||
const lineScale = d3
|
const lineScale = d3
|
||||||
.scaleOrdinal<string>()
|
.scaleOrdinal<string>()
|
||||||
.domain(lineKeys)
|
.domain(lineKeys)
|
||||||
.range(["#1f77b4", "#17becf", "#ff7f0e"]);
|
.range([COLORS.primary, COLORS.secondary]);
|
||||||
|
|
||||||
const positions = _.flatMap(points, (p) => [
|
const positions = _.flatMap(points, (p) => [
|
||||||
p.gain_amount + p.investment_amount - p.withdrawal_amount,
|
p.gain_amount + p.investment_amount - p.withdrawal_amount,
|
||||||
|
|
103
web/src/utils.ts
103
web/src/utils.ts
|
@ -1,3 +1,4 @@
|
||||||
|
import chroma from "chroma-js";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { sprintf } from "sprintf-js";
|
import { sprintf } from "sprintf-js";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
@ -243,8 +244,106 @@ export function skipTicks<Domain>(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setHtml(selector: string, value: string) {
|
export function generateColorScheme(domain: string[]) {
|
||||||
const node = document.querySelector(".d3-" + selector);
|
let colors: string[];
|
||||||
|
|
||||||
|
const n = domain.length;
|
||||||
|
if (n <= 12) {
|
||||||
|
colors = {
|
||||||
|
1: ["#7570b3"],
|
||||||
|
2: ["#7fc97f", "#fdc086"],
|
||||||
|
3: ["#66c2a5", "#fc8d62", "#8da0cb"],
|
||||||
|
4: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3"],
|
||||||
|
5: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854"],
|
||||||
|
6: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f"],
|
||||||
|
7: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69"
|
||||||
|
],
|
||||||
|
8: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69",
|
||||||
|
"#fccde5"
|
||||||
|
],
|
||||||
|
9: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69",
|
||||||
|
"#fccde5",
|
||||||
|
"#d9d9d9"
|
||||||
|
],
|
||||||
|
10: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69",
|
||||||
|
"#fccde5",
|
||||||
|
"#d9d9d9",
|
||||||
|
"#bc80bd"
|
||||||
|
],
|
||||||
|
11: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69",
|
||||||
|
"#fccde5",
|
||||||
|
"#d9d9d9",
|
||||||
|
"#bc80bd",
|
||||||
|
"#ccebc5"
|
||||||
|
],
|
||||||
|
12: [
|
||||||
|
"#8dd3c7",
|
||||||
|
"#ffed6f",
|
||||||
|
"#bebada",
|
||||||
|
"#fb8072",
|
||||||
|
"#80b1d3",
|
||||||
|
"#fdb462",
|
||||||
|
"#b3de69",
|
||||||
|
"#fccde5",
|
||||||
|
"#d9d9d9",
|
||||||
|
"#bc80bd",
|
||||||
|
"#ccebc5",
|
||||||
|
"#ffed6f"
|
||||||
|
]
|
||||||
|
}[n];
|
||||||
|
} else {
|
||||||
|
const z = d3
|
||||||
|
.scaleSequential()
|
||||||
|
.domain([0, n - 1])
|
||||||
|
.interpolator(d3.interpolateSinebow);
|
||||||
|
colors = _.map(_.range(0, n), (n) => chroma(z(n)).desaturate(1.5).hex());
|
||||||
|
}
|
||||||
|
|
||||||
|
return d3.scaleOrdinal<string>().domain(domain).range(colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setHtml(selector: string, value: string, color?: string) {
|
||||||
|
const node: HTMLElement = document.querySelector(".d3-" + selector);
|
||||||
|
if (color) {
|
||||||
|
node.style.backgroundColor = color;
|
||||||
|
node.style.padding = "5px";
|
||||||
|
node.style.color = "white";
|
||||||
|
}
|
||||||
node.innerHTML = value;
|
node.innerHTML = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered">
|
||||||
<div>
|
<div>
|
||||||
<p class="heading">Gain</p>
|
<p class="heading">Gain / Loss</p>
|
||||||
<p class="d3-gains title"></p>
|
<p class="d3-gains title"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -363,10 +363,9 @@
|
||||||
<section class="section tab-expense">
|
<section class="section tab-expense">
|
||||||
<div class="container is-fluid">
|
<div class="container is-fluid">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column is-full">
|
<div class="column is-full pb-0">
|
||||||
<div class="p-3 has-text-centered">
|
<div class="has-text-right">
|
||||||
<input style="width: 250px" class="input is-medium is-size-4" required type="month" id="d3-current-month">
|
<input style="width: 175px" class="input is-medium is-size-6" required type="month" id="d3-current-month">
|
||||||
<p class="heading d3-current-month is-size-4"></p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -389,13 +388,13 @@
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered">
|
||||||
<div>
|
<div>
|
||||||
<p class="heading">Net Investment</p>
|
<p class="heading">Net Investment</p>
|
||||||
<p class="d3-current-month-investment title has-text-success"></p>
|
<p class="d3-current-month-investment title"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered">
|
||||||
<div>
|
<div>
|
||||||
<p class="heading">Expenses</p>
|
<p class="heading">Expenses</p>
|
||||||
<p class="d3-current-month-expenses title has-text-danger"></p>
|
<p class="d3-current-month-expenses title"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
Loading…
Reference in New Issue