vran-dev_obsidian-contribut.../src/render/graphRender.ts

303 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { DEFAULT_RULES } from "src/constants";
import {
ContributionGraphConfig,
ContributionCellData,
CellStyleRule,
ContributionItem,
} from "src/types";
import { parseDate } from "src/util/dateUtils";
import {
generateByLatestDays,
generateByFixedDate,
generateByData,
} from "./matrixDataGenerator";
import { matchCellStyleRule } from "src/util/utils";
import { setTooltip } from "obsidian";
import { Locals } from "src/i18/messages";
export interface GraphRender {
render(container: HTMLElement, graphConfig: ContributionGraphConfig): void;
graphType(): string;
}
export abstract class BaseGraphRender implements GraphRender {
constructor() {}
render(container: HTMLElement, graphConfig: ContributionGraphConfig): void {
throw new Error("Method not implemented.");
}
abstract graphType(): string;
renderTitle(
graphConfig: ContributionGraphConfig,
parent: HTMLElement
): HTMLElement {
const titleEl = document.createElement("div");
titleEl.className = "title";
if (graphConfig.title) {
titleEl.innerText = graphConfig.title;
}
if (graphConfig.titleStyle) {
Object.assign(titleEl.style, graphConfig.titleStyle);
}
parent.appendChild(titleEl);
return titleEl;
}
renderCellRuleIndicator(
graphConfig: ContributionGraphConfig,
parent: HTMLElement
) {
if (graphConfig.showCellRuleIndicators === false) {
return;
}
const cellRuleIndicatorContainer = createDiv({
cls: "cell-rule-indicator-container",
parent: parent,
});
const cellRules = this.getCellRules(graphConfig);
createDiv({
cls: "cell text",
text: "less",
parent: cellRuleIndicatorContainer,
});
cellRules
.sort((a, b) => a.min - b.min)
.forEach((rule) => {
const cellEl = createDiv({
cls: ["cell"],
parent: cellRuleIndicatorContainer,
});
cellEl.className = "cell";
cellEl.style.backgroundColor = rule.color;
cellEl.innerText = rule.text || "";
// bind tips event
const summary = `${rule.min} ≤ contributions ${rule.max}`;
setTooltip(cellEl, summary);
});
createDiv({
cls: "cell text",
text: "more",
parent: cellRuleIndicatorContainer,
});
}
renderActivityContainer(
graphConfig: ContributionGraphConfig,
parent: HTMLElement
): HTMLElement {
const activityContainer = createDiv({
cls: "activity-container",
parent: parent,
});
return activityContainer;
}
renderActivity(
graphConfig: ContributionGraphConfig,
cellData: ContributionCellData,
contaienr: HTMLElement
) {
contaienr.empty();
const closeButton = createEl("button", {
cls: "close-button",
text: 'x',
parent: contaienr,
})
closeButton.onclick = () => {
contaienr.empty();
}
let summary;
if (cellData.value > 0) {
summary = Locals.get().you_have_contributed_to
.replace("{date}", cellData.date)
.replace("{value}", cellData.value.toString());
} else {
summary = Locals.get().you_have_no_contributions_on
.replace("{date}", cellData.date)
.replace("{value}", "0");
}
createDiv({
cls: "activity-summary",
parent: contaienr,
text: summary,
});
const content = createDiv({
cls: "activity-content",
parent: contaienr,
});
// list-main
const list = createDiv({
cls: "activity-list",
parent: content,
});
// show top 10 items
const size = 10;
const items = cellData.items || [];
renderActivityItem(items.slice(0, size), list);
const navigation = createDiv({
cls: "activity-navigation",
parent: content,
});
let page = 1;
if (items.length > size) {
const loadMore = createEl("a", {
text: Locals.get().click_to_load_more,
href: "#",
parent: navigation,
});
loadMore.onclick = (event) => {
event.preventDefault();
page++;
renderActivityItem(
items.slice((page - 1) * size, page * size),
list
);
if (page * size >= items.length) {
loadMore.remove();
}
};
}
}
generateContributionData(graphConfig: ContributionGraphConfig) {
if (graphConfig.days) {
return generateByLatestDays(graphConfig.days, graphConfig.data);
} else if (graphConfig.fromDate && graphConfig.toDate) {
const fromDate = parseDate(graphConfig.fromDate);
const toDate = parseDate(graphConfig.toDate);
return generateByFixedDate(fromDate, toDate, graphConfig.data);
} else {
return generateByData(graphConfig.data);
}
}
getCellRules(graphConfig: ContributionGraphConfig) {
return graphConfig.cellStyleRules &&
graphConfig.cellStyleRules.length > 0
? graphConfig.cellStyleRules
: DEFAULT_RULES;
}
bindMonthTips(
monthCell: HTMLElement,
contributionItem: ContributionCellData,
contributionMapByYearMonth: Map<string, number>
) {
const yearMonth = `${contributionItem.year}-${
contributionItem.month + 1
}`;
const yearMonthValue = contributionMapByYearMonth.get(yearMonth) || 0;
// tips event
setTooltip(
monthCell,
`${yearMonthValue} contributions on ${yearMonth}.`
);
}
applyCellGlobalStyle(
cellEl: HTMLElement,
graphConfig: ContributionGraphConfig
) {
if (graphConfig.cellStyle) {
Object.assign(cellEl.style, graphConfig.cellStyle);
}
}
applyCellStyleRule(
cellEl: HTMLElement,
contributionItem: ContributionCellData,
cellRules: CellStyleRule[],
defaultCellStyleRule?: () => CellStyleRule
) {
const cellStyleRule = matchCellStyleRule(
contributionItem.value,
cellRules
);
if (cellStyleRule != null) {
cellEl.style.backgroundColor = cellStyleRule.color;
cellEl.innerText = cellStyleRule.text || "";
return;
}
if (defaultCellStyleRule) {
const defaultRule = defaultCellStyleRule();
cellEl.style.backgroundColor = defaultRule.color;
cellEl.innerText = defaultRule.text || "";
}
}
bindCellAttribute(
cellEl: HTMLElement,
contributionItem: ContributionCellData
) {
cellEl.setAttribute("data-year", contributionItem.year.toString());
cellEl.setAttribute("data-month", contributionItem.month.toString());
cellEl.setAttribute("data-date", contributionItem.date.toString());
}
bindCellClickEvent(
cellEl: HTMLElement,
contributionItem: ContributionCellData,
graphConfig: ContributionGraphConfig,
activityContainer?: HTMLElement
) {
cellEl.onclick = (event: MouseEvent) => {
if (graphConfig.onCellClick) {
graphConfig.onCellClick(contributionItem, event);
}
if (activityContainer) {
this.renderActivity(
graphConfig,
contributionItem,
activityContainer
);
}
};
}
bindCellTips(cellEl: HTMLElement, contributionItem: ContributionCellData) {
cellEl.addEventListener("mouseenter", (event) => {
const summary = contributionItem.summary
? contributionItem.summary
: `${contributionItem.value} contributions on ${contributionItem.date}.`;
setTooltip(cellEl, summary);
});
}
}
function renderActivityItem(items: ContributionItem[], listMain: HTMLElement) {
(items || []).slice(0, 10).forEach((item) => {
const listItem = createDiv({
cls: "activity-item",
parent: listMain,
});
const linkEl = createEl("a", {
text: item.label,
href: "#",
parent: listItem,
cls: "label",
});
linkEl.onclick = (event) => {
event.preventDefault();
if (item.open) {
item.open(event);
}
};
});
}