vue-bar-graph
Version:
Simple and lightweight Vue chart svg component without chart library dependencies
313 lines (312 loc) • 10.8 kB
JavaScript
import { openBlock as o, createElementBlock as a, toDisplayString as y, createCommentVNode as u, createElementVNode as d, Fragment as m, renderList as C, renderSlot as A, normalizeStyle as g } from "vue";
const w = (t, s) => {
const i = t.__vccOpts || t;
for (const [r, h] of s)
i[r] = h;
return i;
}, _ = {
props: {
title: { type: String, default: "" },
points: { type: Array, default: () => [] },
height: { type: Number, default: 100 },
width: { type: Number, default: 300 },
showYAxis: { type: Boolean, default: !1 },
showXAxis: { type: Boolean, default: !1 },
labelHeight: { type: Number, default: 12 },
showTrendLine: { type: Boolean, default: !1 },
trendLineColor: { type: String, default: "green" },
trendLineWidth: { type: Number, default: 2 },
easeIn: { type: Boolean, default: !0 },
showValues: { type: Boolean, default: !1 },
maxYAxis: { type: Number, default: 0 },
animationDuration: { type: Number, default: 0.5 },
barColor: { type: String, default: "deepskyblue" },
textColor: { type: String, default: "black" },
textAltColor: { type: String, default: "black" },
textFont: { type: String, default: "10px sans-serif" },
useCustomLabels: { type: Boolean, default: !1 },
customLabels: { type: Array, default: () => [] }
},
data() {
return {
dynamicPoints: [],
staticPoints: [],
extraTopHeightForYAxisLabel: 4,
extraBottomHeightForYAxisLabel: 4,
digitsUsedInYAxis: 0
};
},
computed: {
usingObjectsForDataPoints() {
return this.points.every((t) => typeof t == "object");
},
dataPoints() {
return this.usingObjectsForDataPoints ? this.points.map((t) => t.value) : this.points;
},
dataLabels() {
return this.points.map((t, s) => this.useCustomLabels ? this.customLabels[s] : this.usingObjectsForDataPoints ? t.label : s + 1);
},
dataColors() {
return this.points.map((t) => ({
barColor: t && t.barColor ? t.barColor : this.barColor,
textColor: t && t.textColor ? t.textColor : this.textColor,
textAltColor: t && t.textAltColor ? t.textAltColor : this.textAltColor
}));
},
yAxisWidth() {
return this.digitsUsedInYAxis * 5.8 + 5;
},
xAxisHeight() {
return this.showYAxis ? this.labelHeight : this.labelHeight + this.extraBottomHeightForYAxisLabel + this.extraTopHeightForYAxisLabel;
},
fullSvgWidth() {
return this.width;
},
fullSvgHeight() {
return this.height;
},
innerChartWidth() {
return this.showYAxis ? this.width - this.yAxisWidth : this.width;
},
innerChartHeight() {
let t = this.height;
return this.showYAxis && (t -= this.extraTopHeightForYAxisLabel + this.extraBottomHeightForYAxisLabel), this.showXAxis && (t -= this.xAxisHeight), t;
},
partitionWidth() {
return this.innerChartWidth / this.dataPoints.length;
},
maxDomain() {
return this.maxYAxis ? this.maxYAxis : Math.ceil(Math.max(...this.dataPoints));
},
chartData() {
return this.dynamicPoints.map((t, s) => ({
staticValue: this.staticPoints[s],
index: s,
label: this.dataLabels[s],
width: this.partitionWidth - 2,
midPoint: this.partitionWidth / 2,
yLabel: this.innerChartHeight + 4,
x: s * this.partitionWidth,
xMidpoint: s * this.partitionWidth + this.partitionWidth / 2,
yOffset: this.innerChartHeight - this.y(t),
height: this.y(t),
barColor: this.dataColors[s].barColor,
textColor: this.dataColors[s].textColor,
textAltColor: this.dataColors[s].textAltColor
}));
},
trendLine() {
const t = this.applySlope(this.dynamicPoints);
return {
x1: this.partitionWidth / 2,
y1: this.roundTo(this.innerChartHeight - this.y(t[0]), 2),
x2: this.innerChartWidth - this.partitionWidth / 2,
y2: this.roundTo(this.innerChartHeight - this.y(t[t.length - 1]), 2)
};
}
},
watch: {
dataPoints: {
handler(t) {
this.tween(t);
},
deep: !0
}
},
created() {
this.easeIn ? this.tween(this.dataPoints) : (this.dynamicPoints = this.dataPoints, this.staticPoints = this.dataPoints);
},
methods: {
y(t) {
return t / this.maxDomain * this.innerChartHeight;
},
roundTo(t, s = 0) {
let i = !1, r = t;
r < 0 && (i = !0, r *= -1);
const h = 10 ** s;
return r = parseFloat((r * h).toFixed(11)), r = (Math.round(r) / h).toFixed(2), i && (r = (r * -1).toFixed(2)), r;
},
easeInFunc(t) {
return 1 - Math.cos(t * (Math.PI / 2));
},
tween(t) {
this.staticPoints = t, this.dynamicPoints = Array(t.length).fill(0);
const s = this.dynamicPoints, i = 200, r = 10;
let h = (/* @__PURE__ */ new Date()).getTime(), n = setInterval(() => {
if (this.dynamicPoints !== s) {
clearInterval(n);
return;
}
let e = ((/* @__PURE__ */ new Date()).getTime() - h) / i;
if (e = e < 0 ? 1 : Math.min(e, 1), e >= 1) {
clearInterval(n), this.dynamicPoints = t;
return;
}
for (let x = 0; x < s.length; x += 1)
this.dynamicPoints[x] = this.easeInFunc(e) * t[x];
}, r);
},
getTicks() {
for (let t = 6; t > 0; t -= 1)
if (this.maxDomain % t === 0) {
const s = t < 3, i = s ? 3 : t;
return this.digitsUsedInYAxis = this.maxDomain.toFixed(s ? 1 : 0).replace(".", "").length, [...new Array(i + 1)].map((r, h) => {
const n = this.maxDomain / i * (i - h), e = this.innerChartHeight / i * h;
return {
key: h,
text: s ? n.toFixed(1) : n,
yText: e < 10 ? 10 : e + 4,
x1: this.yAxisWidth - 4,
y1: e,
x2: this.yAxisWidth - 1,
y2: e
};
});
}
return [];
},
applySlope(t) {
let s = 0, i = 0;
for (let l = 0; l < t.length; l += 1)
s += l, i += t[l];
s /= t.length, i /= t.length;
let r = 0, h = 0;
for (let l = 0; l < t.length; l += 1)
r += (l - s) * (t[l] - i), h += (l - s) ** 2;
const n = r / h, e = i - n * s, x = [];
for (let l = 0; l < t.length; l += 1)
x.push(n * l + e);
return x;
}
}
}, b = ["width", "height"], H = {
key: 0,
id: "title"
}, L = ["transform"], P = ["transform", "width", "height"], W = ["transform"], F = ["width", "height", "y"], k = ["x", "y", "dy"], p = { key: 1 }, Y = ["x", "y"], S = ["x1", "x2", "y1", "y2"], T = ["x1", "y1", "x2", "y2", "stroke-width", "stroke"], D = { key: 0 }, B = ["x1", "x2", "y1", "y2"], I = { key: 1 }, V = ["x1", "x2", "y1"], v = ["x1", "y1", "x2", "y2"], N = ["y"];
function O(t, s, i, r, h, n) {
return o(), a("svg", {
width: n.fullSvgWidth,
height: n.fullSvgHeight,
"aria-labelledby": "title",
role: "img"
}, [
i.title ? (o(), a("title", H, y(i.title), 1)) : u("", !0),
d("g", {
transform: `translate(0,${i.showYAxis ? h.extraTopHeightForYAxisLabel : 0})`
}, [
d("g", {
transform: `translate(${i.showYAxis ? n.yAxisWidth : 0},0)`,
width: n.innerChartWidth,
height: n.innerChartHeight
}, [
(o(!0), a(m, null, C(n.chartData, (e) => (o(), a("g", {
key: e.index,
transform: `translate(${e.x},0)`
}, [
d("title", null, [
A(t.$slots, "title", { bar: e }, () => [
d("tspan", null, y(e.staticValue), 1)
])
]),
d("rect", {
width: e.width,
height: e.height,
x: 2,
y: e.yOffset,
style: g({ fill: e.barColor })
}, null, 12, F),
i.showValues ? (o(), a("text", {
key: 0,
x: e.midPoint,
y: e.yOffset,
dy: `${e.height < 22 ? "-5px" : "15px"}`,
"text-anchor": "middle",
style: g({ fill: e.height < 22 ? e.textColor : e.textAltColor, font: i.textFont })
}, y(e.staticValue), 13, k)) : u("", !0),
i.showXAxis ? (o(), a("g", p, [
A(t.$slots, "label", {
bar: e,
textStyle: { fill: i.textColor, font: i.textFont }
}, () => [
d("text", {
x: e.midPoint,
y: `${e.yLabel + 10}px`,
"text-anchor": "middle",
style: g({ fill: i.textColor, font: i.textFont })
}, y(e.label), 13, Y)
]),
d("line", {
x1: e.midPoint,
x2: e.midPoint,
y1: n.innerChartHeight + 3,
y2: n.innerChartHeight,
stroke: "#555555",
"stroke-width": "1"
}, null, 8, S)
])) : u("", !0)
], 8, W))), 128)),
i.showTrendLine ? (o(), a("line", {
key: 0,
x1: n.trendLine.x1,
y1: n.trendLine.y1,
x2: n.trendLine.x2,
y2: n.trendLine.y2,
"stroke-width": i.trendLineWidth,
stroke: i.trendLineColor
}, null, 8, T)) : u("", !0)
], 8, P),
i.showXAxis ? (o(), a("g", D, [
d("line", {
x1: i.showYAxis ? n.yAxisWidth - 1 : 2,
x2: n.innerChartWidth + n.yAxisWidth,
y1: n.innerChartHeight,
y2: n.innerChartHeight,
stroke: "#555555",
"stroke-width": "1"
}, null, 8, B)
])) : u("", !0),
i.showYAxis ? (o(), a("g", I, [
d("line", {
x1: n.yAxisWidth - 1,
x2: n.yAxisWidth - 1,
y1: n.innerChartHeight,
y2: "0",
stroke: "#555555",
"stroke-width": "1"
}, null, 8, V),
(o(!0), a(m, null, C(n.getTicks(), (e) => (o(), a("g", {
key: e.key
}, [
d("line", {
x1: e.x1,
y1: e.y1,
x2: e.x2,
y2: e.y2,
stroke: "#555555",
"stroke-width": "1"
}, null, 8, v),
d("text", {
x: "0",
y: e.yText,
"alignment-baseline": "central",
style: g({ fill: i.textColor, font: i.textFont })
}, y(e.text), 13, N)
]))), 128))
])) : u("", !0)
], 8, L)
], 8, b);
}
const M = /* @__PURE__ */ w(_, [["render", O]]);
function f(t) {
f.installed || (f.installed = !0, t.component("VueBarGraph", M));
}
const j = {
install: f
};
let c = null;
typeof window < "u" ? c = window.Vue : typeof global < "u" && (c = global.Vue);
c && c.use(j);
export {
M as VueBarGraph,
f as install
};