diff --git a/README.md b/README.md
index 6c6b91d..718fab2 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@

-
+
This is an [Obsidian](https://obsidian.md/) plugin that helps you collect data from notes and represent it comprehensively.
@@ -55,7 +55,7 @@ Version 1.10.9
## !!! Breaking Changes !!!
-From version 1.9.0, template variables, e.g. '{{sum}}', are deprecated. Instead, Tracker provide operators (+, -, *, /, %) and functions (dataset(), sum(), maxStreak(), ......etc) to help us do data processing. For users having code blocks from previous version, please replace '{{sum}}' by '{{sum()}}' or '{{sum(1)}}' by '{{sum(dataset(1))}}'. More information about the new expressions could be found [here](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Expressions.md).
+From version 1.9.0, template variables, e.g. '{{sum}}', are deprecated. Instead, Tracker provide operators (+, -, *, /, %) and functions (dataset(), sum(), maxStreak(), ......etc.) to help us do data processing. For users having code blocks from previous version, please replace '{{sum}}' by '{{sum()}}' or '{{sum(1)}}' by '{{sum(dataset(1))}}'. More information about the new expressions could be found [here](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Expressions.md).
## Usage
@@ -68,7 +68,7 @@ For more use cases, please download and open the [examples](https://github.com/p
## More Details You May Want to Know
- [Installation](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Installation.md): Install the plugin from Obsidian or install it manually
-- [Concepts](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Concepts.md): Explain how this plugin works and what to setup
+- [Concepts](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Concepts.md): Explain how this plugin works and what to set up
- [Target Evaluation](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/TargetEvaluation.md)
- [Input Parameters](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/InputParameters.md)
- [Expressions](https://github.com/pyrochlore/obsidian-tracker/blob/master/docs/Expressions.md)
diff --git a/examples/TestMonthlyData.md b/examples/TestMonthlyData.md
new file mode 100644
index 0000000..7a87a22
--- /dev/null
+++ b/examples/TestMonthlyData.md
@@ -0,0 +1,11 @@
+# Test Monthly Data
+
+``` tracker
+searchType: frontmatter
+searchTarget: pushup
+dateFormat: YYYY-MMM
+line:
+ fillGap: true
+ xAxisTickInterval: 1M
+ xAxisTickLabelFormat: YYYY-MMM
+```
\ No newline at end of file
diff --git a/examples/TestMultipleGraphs.md b/examples/TestMultipleGraphs.md
new file mode 100644
index 0000000..5e27eba
--- /dev/null
+++ b/examples/TestMultipleGraphs.md
@@ -0,0 +1,20 @@
+# Test Multiple Graphs
+
+## Line + SVG
+svg from [SVG REPO](https://www.svgrepo.com/svg/124402/weight) with [license](https://www.svgrepo.com/page/licensing)
+``` tracker
+searchType: tag
+searchTarget: weight
+folder: diary
+endDate: 2021-01-31
+line:
+svg:
+ element: ''
+```
+
+## Bar + Summary
+
+
+
+## Pie + Bar
+MTG Deck Statistics
\ No newline at end of file
diff --git a/examples/TestSVG.md b/examples/TestSVG.md
new file mode 100644
index 0000000..97e1c77
--- /dev/null
+++ b/examples/TestSVG.md
@@ -0,0 +1,13 @@
+# Test SVG
+
+svg from [SVG REPO](https://www.svgrepo.com/svg/343407/awkward-emoji-emoticon-happy-simle) with [license](https://www.svgrepo.com/page/licensing)
+
+``` tracker
+searchType: tag
+searchTarget: weight
+folder: diary
+endDate: 2021-01-31
+line:
+svg:
+ element: ''
+```
\ No newline at end of file
diff --git a/examples/TestSummary.md b/examples/TestSummary.md
index fb3d158..cd8ce13 100644
--- a/examples/TestSummary.md
+++ b/examples/TestSummary.md
@@ -1,6 +1,7 @@
# Test Summary
## Multiple Lines
+Accept multitple lines by using a line break '\n' in between
``` tracker
searchType: tag
@@ -17,6 +18,20 @@ searchType: text
searchTarget: ⭐
folder: diary
summary:
+ template: "I have {{sum()}} stars in total."
+ style: "font-size:32px;fill:none;stroke-width:0.5;stroke:yellow"
+```
+
+## Multiple Summaries
+
+``` tracker
+searchType: text
+searchTarget: ⭐
+folder: diary
+summary:
+ template: "I have {{sum()}} stars in total."
+ style: "font-size:20px;color:yellow;margin-left: 50px;margin-top:00px;"
+summary1:
template: "I have {{sum()}} stars in total."
style: "font-size:20px;color:yellow;margin-left: 50px;margin-top:00px;"
```
diff --git a/examples/empty/.keep b/examples/empty/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/examples/monthly/2021-Apr.md b/examples/monthly/2021-Apr.md
new file mode 100644
index 0000000..b211a84
--- /dev/null
+++ b/examples/monthly/2021-Apr.md
@@ -0,0 +1,4 @@
+---
+pushup: 1050
+
+---
\ No newline at end of file
diff --git a/examples/monthly/2021-Feb.md b/examples/monthly/2021-Feb.md
new file mode 100644
index 0000000..dc140d8
--- /dev/null
+++ b/examples/monthly/2021-Feb.md
@@ -0,0 +1,4 @@
+---
+pushup: 900
+
+---
\ No newline at end of file
diff --git a/examples/monthly/2021-Jan.md b/examples/monthly/2021-Jan.md
new file mode 100644
index 0000000..15a45a7
--- /dev/null
+++ b/examples/monthly/2021-Jan.md
@@ -0,0 +1,4 @@
+---
+pushup: 800
+
+---
\ No newline at end of file
diff --git a/examples/monthly/2021-Mar.md b/examples/monthly/2021-Mar.md
new file mode 100644
index 0000000..a3de735
--- /dev/null
+++ b/examples/monthly/2021-Mar.md
@@ -0,0 +1,4 @@
+---
+pushup: 1000
+
+---
\ No newline at end of file
diff --git a/examples/monthly/2021-May.md b/examples/monthly/2021-May.md
new file mode 100644
index 0000000..78d95e7
--- /dev/null
+++ b/examples/monthly/2021-May.md
@@ -0,0 +1,4 @@
+---
+pushup: 1080
+
+---
\ No newline at end of file
diff --git a/src/bullet.ts b/src/bullet.ts
index 0494dcd..cc70845 100644
--- a/src/bullet.ts
+++ b/src/bullet.ts
@@ -15,7 +15,7 @@ import * as d3 from "d3";
import * as expr from "./expr";
function createAreas(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
bulletInfo: BulletInfo
): ChartElements {
@@ -24,8 +24,7 @@ function createAreas(
if (!renderInfo || !bulletInfo) return;
- let svg = d3
- .select(canvas)
+ let svg = svgCanvas
.append("svg")
.attr("id", "svg")
.attr(
@@ -73,11 +72,11 @@ function createAreas(
}
function setChartScale(
- _canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo
) {
- let canvas = d3.select(_canvas);
+ let canvas = svgCanvas;
let svg = chartElements.svg;
let svgWidth = parseFloat(svg.attr("width"));
let svgHeight = parseFloat(svg.attr("height"));
@@ -531,7 +530,7 @@ function renderMark(
// Bullet graph https://en.wikipedia.org/wiki/Bullet_graph
export function renderBullet(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
bulletInfo: BulletInfo
) {
@@ -549,7 +548,7 @@ export function renderBullet(
renderInfo.dataAreaSize = { width: 24, height: 250 };
}
- let chartElements = createAreas(canvas, renderInfo, bulletInfo);
+ let chartElements = createAreas(svgCanvas, renderInfo, bulletInfo);
let retRenderAxis = renderAxis(
chartElements,
@@ -577,5 +576,5 @@ export function renderBullet(
renderMark(chartElements, renderInfo, bulletInfo, dataset);
- setChartScale(canvas, chartElements, renderInfo);
+ setChartScale(svgCanvas, chartElements, renderInfo);
}
diff --git a/src/collecting.ts b/src/collecting.ts
index 1f0325a..309fe91 100644
--- a/src/collecting.ts
+++ b/src/collecting.ts
@@ -333,12 +333,12 @@ function extractDataUsingRegexWithMultipleValues(
): boolean {
// console.log("extractDataUsingRegexWithMultipleValues");
+ let extracted = false;
let regex = new RegExp(strRegex, "gm");
let match;
- let measure = 0.0;
- let extracted = false;
while ((match = regex.exec(text))) {
// console.log(match);
+ let value = null;
if (!renderInfo.ignoreAttachedValue[query.getId()]) {
if (
typeof match.groups !== "undefined" &&
@@ -360,18 +360,14 @@ function extractDataUsingRegexWithMultipleValues(
);
if (retParse.value !== null) {
if (retParse.type === ValueType.Time) {
- measure = retParse.value;
- extracted = true;
+ value = retParse.value;
query.valueType = ValueType.Time;
- query.addNumTargets();
} else {
if (
!renderInfo.ignoreZeroValue[query.getId()] ||
retParse.value !== 0
) {
- measure += retParse.value;
- extracted = true;
- query.addNumTargets();
+ value = retParse.value;
}
}
}
@@ -388,40 +384,37 @@ function extractDataUsingRegexWithMultipleValues(
//console.log(retParse);
if (retParse.value !== null) {
if (retParse.type === ValueType.Time) {
- measure = retParse.value;
- extracted = true;
+ value = retParse.value;
query.valueType = ValueType.Time;
- query.addNumTargets();
} else {
- measure += retParse.value;
- extracted = true;
- query.addNumTargets();
+ value = retParse.value;
}
}
}
} else {
// no named groups, count occurrencies
// console.log("count occurrencies");
- measure += renderInfo.constValue[query.getId()];
- extracted = true;
- query.addNumTargets();
+ value = renderInfo.constValue[query.getId()];
}
} else {
// force to count occurrencies
// console.log("forced count occurrencies");
- measure += renderInfo.constValue[query.getId()];
- extracted = true;
- query.addNumTargets();
+ value = renderInfo.constValue[query.getId()];
}
- }
- if (extracted) {
- let xValue = xValueMap.get(renderInfo.xDataset[query.getId()]);
- addToDataMap(dataMap, xValue, query, measure);
- return true;
+ if (value !== null) {
+ let xValue = xValueMap.get(renderInfo.xDataset[query.getId()]);
+ addToDataMap(dataMap, xValue, query, value);
+ query.addNumTargets();
+ extracted = true;
+
+ if (renderInfo.dataMergeMethod[query.getId()] === "first") {
+ break;
+ }
+ }
}
- return false;
+ return extracted;
}
// No value, count occurrences only
@@ -439,10 +432,10 @@ export function collectDataFromFrontmatterTag(
let frontMatter = fileCache.frontmatter;
let frontMatterTags: string[] = [];
+ let tagExist = false;
if (frontMatter && frontMatter.tags) {
// console.log(frontMatter.tags);
- let tagMeasure = 0.0;
- let tagExist = false;
+
if (Array.isArray(frontMatter.tags)) {
frontMatterTags = frontMatterTags.concat(frontMatter.tags);
} else if (typeof frontMatter.tags === "string") {
@@ -458,34 +451,33 @@ export function collectDataFromFrontmatterTag(
// console.log(query.getTarget());
for (let tag of frontMatterTags) {
+ let value = null;
+
if (tag === query.getTarget()) {
// simple tag
- tagMeasure = tagMeasure + renderInfo.constValue[query.getId()];
- tagExist = true;
- query.addNumTargets();
+ value = renderInfo.constValue[query.getId()];
} else if (tag.startsWith(query.getTarget() + "/")) {
// nested tag
- tagMeasure = tagMeasure + renderInfo.constValue[query.getId()];
- tagExist = true;
- query.addNumTargets();
- } else {
- continue;
+ value = renderInfo.constValue[query.getId()];
}
// valued-tag in frontmatter is not supported
// because the "tag:value" in frontmatter will be consider as a new tag for each existing value
- let value = null;
- if (tagExist) {
- value = tagMeasure;
+ if (value !== null) {
+ let xValue = xValueMap.get(renderInfo.xDataset[query.getId()]);
+ addToDataMap(dataMap, xValue, query, value);
+ query.addNumTargets();
+ tagExist = true;
+
+ if (renderInfo.dataMergeMethod[query.getId()] === "first") {
+ break;
+ }
}
- let xValue = xValueMap.get(renderInfo.xDataset[query.getId()]);
- addToDataMap(dataMap, xValue, query, value);
- return true;
}
}
- return false;
+ return tagExist;
}
// In form 'key: value', target used to identify 'frontmatter key'
diff --git a/src/data.ts b/src/data.ts
index 46fa250..2513e4f 100644
--- a/src/data.ts
+++ b/src/data.ts
@@ -25,6 +25,7 @@ export enum GraphType {
Month,
Heatmap,
Bullet,
+ Svg,
Unknown,
}
@@ -568,6 +569,7 @@ export class RenderInfo {
endDate: Moment | null;
datasetName: string[];
constValue: number[];
+ dataMergeMethod: string[];
ignoreAttachedValue: boolean[];
ignoreZeroValue: boolean[];
accum: boolean[];
@@ -591,6 +593,7 @@ export class RenderInfo {
month: MonthInfo[];
heatmap: HeatmapInfo[];
bullet: BulletInfo[];
+ svg: SvgInfo[];
customDataset: CustomDatasetInfo[];
public datasets: Datasets | null;
@@ -610,6 +613,7 @@ export class RenderInfo {
this.endDate = null;
this.datasetName = []; // untitled
this.constValue = [1.0];
+ this.dataMergeMethod = []; // first, last, sum, product, diff, average
this.ignoreAttachedValue = []; // false
this.ignoreZeroValue = []; // false
this.accum = []; // false, accum values start from zero over days
@@ -633,6 +637,7 @@ export class RenderInfo {
this.month = [];
this.heatmap = [];
this.bullet = [];
+ this.svg = [];
this.customDataset = [];
this.datasets = null;
@@ -964,6 +969,15 @@ export class BulletInfo implements IGraph {
}
}
+export class SvgInfo implements IGraph {
+ element: string;
+ constructor() {
+ this.element = "";
+ }
+ public GetGraphType() {
+ return GraphType.Svg;
+ }
+}
export class Size {
width: number;
height: number;
diff --git a/src/heatmap.ts b/src/heatmap.ts
index 601e618..4e239a3 100644
--- a/src/heatmap.ts
+++ b/src/heatmap.ts
@@ -25,12 +25,12 @@ interface DayInfo {
function createAreas(
chartElements: ChartElements,
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
heatmapInfo: HeatmapInfo
): ChartElements {
// clean areas
- d3.select(canvas).select("#svg").remove();
+ svgCanvas.select("#svg").remove();
var props = Object.getOwnPropertyNames(chartElements);
for (var i = 0; i < props.length; i++) {
// d3.select(chartElements[props[i]]).remove();
@@ -39,8 +39,7 @@ function createAreas(
// console.log(chartElements);
// whole area for plotting, includes margins
- let svg = d3
- .select(canvas)
+ let svg = svgCanvas
.append("svg")
.attr("id", "svg")
.attr(
@@ -88,7 +87,7 @@ function createAreas(
}
function renderHeatmapHeader(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
heatmapInfo: HeatmapInfo,
@@ -97,22 +96,21 @@ function renderHeatmapHeader(
// console.log("renderMonthHeader")
if (!renderInfo || !heatmapInfo) return;
-
}
function renderHeatmapDays(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
heatmapInfo: HeatmapInfo,
- dataset: Dataset,
+ dataset: Dataset
) {
// console.log("renderHeatmapDays");
if (!renderInfo || !heatmapInfo) return;
let cellSize = 20;
- let dotRadius = cellSize / 2.0 * 0.6;
+ let dotRadius = (cellSize / 2.0) * 0.6;
// Get min and max, null values will be treated as zero here
let yMin = d3.min(dataset.getValues());
@@ -128,9 +126,7 @@ function renderHeatmapDays(
// Prepare data for graph
let daysInHeatmapView: Array = [];
const dataStartDate = dataset.getStartDate().clone();
- let startDate = dataStartDate
- .clone()
- .subtract(dataStartDate.day(), "days");
+ let startDate = dataStartDate.clone().subtract(dataStartDate.day(), "days");
if (heatmapInfo.startWeekOn.toLowerCase() === "mon") {
startDate = startDate.add(1, "days");
}
@@ -208,10 +204,7 @@ function renderHeatmapDays(
return scale(d.row);
})
.style("fill", function (d: DayInfo) {
- return d3.interpolateLab(
- "white",
- heatmapColor
- )(d.scaledValue);
+ return d3.interpolateLab("white", heatmapColor)(d.scaledValue);
})
.style("cursor", "default");
@@ -220,8 +213,7 @@ function renderHeatmapDays(
let svgHeight = parseFloat(chartElements.svg.attr("height"));
let graphAreaWidth = parseFloat(chartElements.graphArea.attr("width"));
let graphAreaHeight = parseFloat(chartElements.graphArea.attr("height"));
- let totalHeight =
- (indRow + 2) * cellSize;// + parseFloat(chartElements.header.attr("height"));
+ let totalHeight = (indRow + 2) * cellSize; // + parseFloat(chartElements.header.attr("height"));
let totalWidth = (indCol + 1) * cellSize;
if (totalHeight > svgHeight) {
helper.expandArea(chartElements.svg, 0, totalHeight - svgHeight);
@@ -242,7 +234,7 @@ function renderHeatmapDays(
}
export function renderHeatmap(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
heatmapInfo: HeatmapInfo
) {
@@ -253,7 +245,12 @@ export function renderHeatmap(
return "Under construction";
let chartElements: ChartElements = {};
- chartElements = createAreas(chartElements, canvas, renderInfo, heatmapInfo);
+ chartElements = createAreas(
+ chartElements,
+ svgCanvas,
+ renderInfo,
+ heatmapInfo
+ );
let today = window.moment();
let lastDataMonthDate = renderInfo.datasets.getDates().last();
@@ -262,7 +259,7 @@ export function renderHeatmap(
let dataset = renderInfo.datasets.getDatasetById(datasetId);
renderHeatmapHeader(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
heatmapInfo,
@@ -270,7 +267,7 @@ export function renderHeatmap(
);
renderHeatmapDays(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
heatmapInfo,
diff --git a/src/main.ts b/src/main.ts
index 31d9835..0311bb8 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -25,6 +25,7 @@ import {
} from "./settings";
import * as helper from "./helper";
import { Moment } from "moment";
+import * as d3 from "d3";
// import { getDailyNoteSettings } from "obsidian-daily-notes-interface";
declare global {
@@ -709,27 +710,53 @@ export default class Tracker extends Plugin {
});
if (queryValuePairs.length > 0) {
// Merge values of the same day same query
- let value = null;
+ let collectedValues = [];
for (
let indPair = 0;
indPair < queryValuePairs.length;
indPair++
) {
- let collected = queryValuePairs[indPair].value;
+ let collectedValue = queryValuePairs[indPair].value;
if (
- Number.isNumber(collected) &&
- !Number.isNaN(collected)
+ Number.isNumber(collectedValue) &&
+ !Number.isNaN(collectedValue)
) {
- if (value === null) {
- value = collected;
- } else {
- value += collected;
- }
+ collectedValues.push(collectedValue);
}
}
- // console.log(hasValue);
- // console.log(value);
- if (value !== null) {
+
+ if (collectedValues.length !== 0) {
+ let value = null;
+ let mergeMethod =
+ renderInfo.dataMergeMethod[query.getId()];
+ switch (mergeMethod) {
+ case "sum":
+ value = d3.sum(collectedValues);
+ break;
+ case "first":
+ value = collectedValues[0];
+ break;
+ case "last":
+ value =
+ collectedValues[
+ collectedValues.length - 1
+ ];
+ break;
+ case "average":
+ let sum = d3.sum(collectedValues);
+ value = sum / collectedValues.length;
+ break;
+ case "diff":
+ value =
+ collectedValues[
+ collectedValues.length - 1
+ ] - collectedValues[0];
+ break;
+ default:
+ // sum
+ value = d3.sum(collectedValues);
+ break;
+ }
dataset.setValue(curDate, value);
}
}
diff --git a/src/month.ts b/src/month.ts
index d4eba3f..6fdd748 100644
--- a/src/month.ts
+++ b/src/month.ts
@@ -34,11 +34,11 @@ interface DayInfo {
}
function setChartScale(
- _canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo
) {
- let canvas = d3.select(_canvas);
+ let canvas = svgCanvas;
let svg = chartElements.svg;
let svgWidth = parseFloat(svg.attr("width"));
let svgHeight = parseFloat(svg.attr("height"));
@@ -112,12 +112,12 @@ function toNextDataset(renderInfo: RenderInfo, monthInfo: MonthInfo): boolean {
function createAreas(
chartElements: ChartElements,
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
monthInfo: MonthInfo
): ChartElements {
// clean areas
- d3.select(canvas).select("#svg").remove();
+ svgCanvas.select("#svg").remove();
var props = Object.getOwnPropertyNames(chartElements);
for (var i = 0; i < props.length; i++) {
// d3.select(chartElements[props[i]]).remove();
@@ -126,8 +126,7 @@ function createAreas(
// console.log(chartElements);
// whole area for plotting, includes margins
- let svg = d3
- .select(canvas)
+ let svg = svgCanvas
.append("svg")
.attr("id", "svg")
.attr(
@@ -191,7 +190,7 @@ function clearSelection(chartElements: ChartElements, monthInfo: MonthInfo) {
}
function renderMonthHeader(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
monthInfo: MonthInfo,
@@ -325,7 +324,7 @@ function renderMonthHeader(
clearSelection(chartElements, monthInfo);
refresh(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
monthInfo,
@@ -379,7 +378,7 @@ function renderMonthHeader(
monthInfo.selectedDate = "";
let prevMonthDate = curMonthDate.clone().add(-1, "month");
refresh(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
monthInfo,
@@ -408,7 +407,7 @@ function renderMonthHeader(
let nextMonthDate = curMonthDate.clone().add(1, "month");
refresh(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
monthInfo,
@@ -436,7 +435,7 @@ function renderMonthHeader(
clearSelection(chartElements, monthInfo);
let todayDate = helper.getDateToday(renderInfo.dateFormat);
- refresh(canvas, chartElements, renderInfo, monthInfo, todayDate);
+ refresh(svgCanvas, chartElements, renderInfo, monthInfo, todayDate);
})
.style("cursor", "pointer");
@@ -507,7 +506,7 @@ function renderMonthHeader(
}
function renderMonthDays(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
monthInfo: MonthInfo,
@@ -746,7 +745,7 @@ function renderMonthDays(
logToConsole = false;
}
}
- // console.log(daysInMonthView);
+ console.log(daysInMonthView);
// console.log(daysInMonthView.filter(function (d: DayInfo) {
// return d.streakIn;
// }));
@@ -1085,7 +1084,7 @@ function renderMonthDays(
}
function refresh(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
monthInfo: MonthInfo,
@@ -1095,22 +1094,33 @@ function refresh(
// console.log(renderInfo);
if (!renderInfo || !renderMonth) return;
- chartElements = createAreas(chartElements, canvas, renderInfo, monthInfo);
+ chartElements = createAreas(
+ chartElements,
+ svgCanvas,
+ renderInfo,
+ monthInfo
+ );
// render
renderMonthHeader(
- canvas,
+ svgCanvas,
chartElements,
renderInfo,
monthInfo,
curMonthDate
);
- renderMonthDays(canvas, chartElements, renderInfo, monthInfo, curMonthDate);
+ renderMonthDays(
+ svgCanvas,
+ chartElements,
+ renderInfo,
+ monthInfo,
+ curMonthDate
+ );
}
export function renderMonth(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
monthInfo: MonthInfo
) {
@@ -1136,7 +1146,12 @@ export function renderMonth(
}
let chartElements: ChartElements = {};
- chartElements = createAreas(chartElements, canvas, renderInfo, monthInfo);
+ chartElements = createAreas(
+ chartElements,
+ svgCanvas,
+ renderInfo,
+ monthInfo
+ );
let monthDate: Moment = null;
if (monthInfo.initMonth) {
@@ -1158,9 +1173,15 @@ export function renderMonth(
}
if (!monthDate) return;
- renderMonthHeader(canvas, chartElements, renderInfo, monthInfo, monthDate);
+ renderMonthHeader(
+ svgCanvas,
+ chartElements,
+ renderInfo,
+ monthInfo,
+ monthDate
+ );
- renderMonthDays(canvas, chartElements, renderInfo, monthInfo, monthDate);
+ renderMonthDays(svgCanvas, chartElements, renderInfo, monthInfo, monthDate);
- setChartScale(canvas, chartElements, renderInfo);
+ setChartScale(svgCanvas, chartElements, renderInfo);
}
diff --git a/src/parsing.ts b/src/parsing.ts
index dc4c17a..e53d52c 100644
--- a/src/parsing.ts
+++ b/src/parsing.ts
@@ -13,6 +13,7 @@ import {
MonthInfo,
HeatmapInfo,
BulletInfo,
+ SvgInfo,
Dataset,
CustomDatasetInfo,
} from "./data";
@@ -1112,6 +1113,7 @@ export function getRenderInfoFromYaml(
let yamlMonthKeys = [];
let yamlHeatmapKeys = [];
let yamlBulletKeys = [];
+ let yamlSvgKeys = [];
for (let key of keysFoundInYAML) {
if (/^line[0-9]*$/.test(key)) {
yamlLineKeys.push(key);
@@ -1133,6 +1135,10 @@ export function getRenderInfoFromYaml(
yamlBulletKeys.push(key);
additionalAllowedKeys.push(key);
}
+ if (/^svg[0-9]*$/.test(key)) {
+ yamlSvgKeys.push(key);
+ additionalAllowedKeys.push(key);
+ }
if (/^month[0-9]*$/.test(key)) {
yamlMonthKeys.push(key);
additionalAllowedKeys.push(key);
@@ -1185,10 +1191,11 @@ export function getRenderInfoFromYaml(
yamlPieKeys.length +
yamlSummaryKeys.length +
yamlBulletKeys.length +
+ yamlSvgKeys.length +
yamlMonthKeys.length +
yamlHeatmapKeys.length;
if (totalNumOutputs === 0) {
- return "No output parameter provided, please place line, bar, pie, month, bullet, or summary.";
+ return "No output parameter provided, please place line, bar, pie, month, bullet, svg, or summary.";
}
// Root folder to search
@@ -1416,6 +1423,21 @@ export function getRenderInfoFromYaml(
renderInfo.constValue = retConstValue;
// console.log(renderInfo.constValue);
+ // dataMergeMethod
+ let retDataMergeMethod = getStringArrayFromInput(
+ "dataMergeMethod",
+ yaml.dataMergeMethod,
+ numDatasets,
+ "sum",
+ null,
+ true
+ );
+ if (typeof retDataMergeMethod === "string") {
+ return retDataMergeMethod; // errorMessage
+ }
+ renderInfo.dataMergeMethod = retDataMergeMethod;
+ // console.log(renderInfo.dataMergeMethod);
+
// ignoreAttachedValue
let retIgnoreAttachedValue = getBoolArrayFromInput(
"ignoreAttachedValue",
@@ -2373,5 +2395,30 @@ export function getRenderInfoFromYaml(
} // Bullet related parameters
// console.log(renderInfo.bullet);
+ // svg related parameters
+ for (let svgKey of yamlSvgKeys) {
+ let svg = new SvgInfo();
+ let yamlSvg = yaml[svgKey];
+
+ let keysOfSvgInfo = getAvailableKeysOfClass(svg);
+ let keysFoundInYAML = getAvailableKeysOfClass(yamlSvg);
+ // console.log(keysOfSvgInfo);
+ // console.log(keysFoundInYAML);
+ for (let key of keysFoundInYAML) {
+ if (!keysOfSvgInfo.includes(key)) {
+ errorMessage = "'" + key + "' is not an available key";
+ return errorMessage;
+ }
+ }
+
+ // element
+ if (typeof yamlSvg?.element === "string") {
+ svg.element = yamlSvg.element;
+ }
+ // console.log(bullet.markValue);
+
+ renderInfo.svg.push(svg);
+ }
+ // console.log(renderInfo.svg);
return renderInfo;
}
diff --git a/src/pie.ts b/src/pie.ts
index 992cef6..154428c 100644
--- a/src/pie.ts
+++ b/src/pie.ts
@@ -18,11 +18,11 @@ import * as expr from "./expr";
import { pie } from "d3";
function setChartScale(
- _canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo
) {
- let canvas = d3.select(_canvas);
+ let canvas = svgCanvas;
let svg = chartElements.svg;
let svgWidth = parseFloat(svg.attr("width"));
let svgHeight = parseFloat(svg.attr("height"));
@@ -47,12 +47,12 @@ function setChartScale(
function createAreas(
chartElements: ChartElements,
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
pieInfo: PieInfo
): ChartElements {
// clean areas
- d3.select(canvas).select("#svg").remove();
+ svgCanvas.select("#svg").remove();
var props = Object.getOwnPropertyNames(chartElements);
for (var i = 0; i < props.length; i++) {
// d3.select(chartElements[props[i]]).remove();
@@ -61,8 +61,7 @@ function createAreas(
// console.log(chartElements);
// whole area for plotting, includes margins
- let svg = d3
- .select(canvas)
+ let svg = svgCanvas
.append("svg")
.attr("id", "svg")
.attr(
@@ -110,7 +109,7 @@ function createAreas(
}
function renderTitle(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
pieInfo: PieInfo
@@ -151,7 +150,7 @@ function renderTitle(
}
function renderLegend(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
pieInfo: PieInfo
@@ -374,7 +373,7 @@ function renderLegend(
}
function renderPie(
- canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo,
pieInfo: PieInfo
@@ -632,7 +631,7 @@ function renderPie(
}
export function renderPieChart(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
pieInfo: PieInfo
) {
@@ -643,7 +642,7 @@ export function renderPieChart(
// return "Under construction";
let chartElements: ChartElements = {};
- chartElements = createAreas(chartElements, canvas, renderInfo, pieInfo);
+ chartElements = createAreas(chartElements, svgCanvas, renderInfo, pieInfo);
// Set default dataColor if no dataColor provided
let defaultDataColor = d3.schemeSpectral[pieInfo.dataColor.length];
@@ -653,13 +652,13 @@ export function renderPieChart(
}
}
- renderTitle(canvas, chartElements, renderInfo, pieInfo);
+ renderTitle(svgCanvas, chartElements, renderInfo, pieInfo);
- renderPie(canvas, chartElements, renderInfo, pieInfo);
+ renderPie(svgCanvas, chartElements, renderInfo, pieInfo);
if (pieInfo.showLegend) {
- renderLegend(canvas, chartElements, renderInfo, pieInfo);
+ renderLegend(svgCanvas, chartElements, renderInfo, pieInfo);
}
- setChartScale(canvas, chartElements, renderInfo);
+ setChartScale(svgCanvas, chartElements, renderInfo);
}
diff --git a/src/rendering.ts b/src/rendering.ts
index 2d62188..75ec072 100644
--- a/src/rendering.ts
+++ b/src/rendering.ts
@@ -16,6 +16,7 @@ import {
PieInfo,
SummaryInfo,
BulletInfo,
+ SvgInfo,
MonthInfo,
HeatmapInfo,
} from "./data";
@@ -219,6 +220,8 @@ export function render(canvas: HTMLElement, renderInfo: RenderInfo) {
// console.log("render");
// console.log(renderInfo.datasets);
+ let svgCanvas = d3.select(canvas).append("svg");
+
// Data preprocessing
for (let dataset of renderInfo.datasets) {
if (dataset.getQuery().usedAsXDataset) continue;
@@ -241,43 +244,50 @@ export function render(canvas: HTMLElement, renderInfo: RenderInfo) {
}
for (let lineInfo of renderInfo.line) {
- let ret = renderLineChart(canvas, renderInfo, lineInfo);
+ let ret = renderLineChart(svgCanvas, renderInfo, lineInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let barInfo of renderInfo.bar) {
- let ret = renderBarChart(canvas, renderInfo, barInfo);
+ let ret = renderBarChart(svgCanvas, renderInfo, barInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let pieInfo of renderInfo.pie) {
- let ret = pie.renderPieChart(canvas, renderInfo, pieInfo);
+ let ret = pie.renderPieChart(svgCanvas, renderInfo, pieInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let summaryInfo of renderInfo.summary) {
- let ret = summary.renderSummary(canvas, renderInfo, summaryInfo);
+ let ret = summary.renderSummary(svgCanvas, renderInfo, summaryInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let bulletInfo of renderInfo.bullet) {
- let ret = bullet.renderBullet(canvas, renderInfo, bulletInfo);
+ let ret = bullet.renderBullet(svgCanvas, renderInfo, bulletInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let monthInfo of renderInfo.month) {
- let ret = month.renderMonth(canvas, renderInfo, monthInfo);
+ let ret = month.renderMonth(svgCanvas, renderInfo, monthInfo);
if (typeof ret === "string") {
return ret;
}
}
for (let heatmapInfo of renderInfo.heatmap) {
- let ret = heatmap.renderHeatmap(canvas, renderInfo, heatmapInfo);
+ let ret = heatmap.renderHeatmap(svgCanvas, renderInfo, heatmapInfo);
+ if (typeof ret === "string") {
+ return ret;
+ }
+ }
+
+ for (let svgInfo of renderInfo.svg) {
+ let ret = renderSvg(svgCanvas, renderInfo, svgInfo);
if (typeof ret === "string") {
return ret;
}
@@ -1445,11 +1455,11 @@ function renderTitle(
}
function setChartScale(
- _canvas: HTMLElement,
+ svgCanvas: any,
chartElements: ChartElements,
renderInfo: RenderInfo
) {
- let canvas = d3.select(_canvas);
+ let canvas = svgCanvas;
let svg = chartElements.svg;
let svgWidth = parseFloat(svg.attr("width"));
let svgHeight = parseFloat(svg.attr("height"));
@@ -1472,14 +1482,10 @@ function setChartScale(
}
}
-function createAreas(
- canvas: HTMLElement,
- renderInfo: RenderInfo
-): ChartElements {
+function createAreas(svgCanvas: any, renderInfo: RenderInfo): ChartElements {
let chartElements: ChartElements = {};
// whole area for plotting, includes margins
- let svg = d3
- .select(canvas)
+ let svg = svgCanvas
.append("svg")
.attr("id", "svg")
.attr(
@@ -1527,7 +1533,7 @@ function createAreas(
}
function renderLineChart(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
lineInfo: LineInfo
) {
@@ -1536,7 +1542,7 @@ function renderLineChart(
if (!renderInfo || !lineInfo) return;
- let chartElements = createAreas(canvas, renderInfo);
+ let chartElements = createAreas(svgCanvas, renderInfo);
renderTitle(chartElements, renderInfo, lineInfo);
@@ -1605,11 +1611,11 @@ function renderLineChart(
renderLegend(chartElements, renderInfo, lineInfo);
}
- setChartScale(canvas, chartElements, renderInfo);
+ setChartScale(svgCanvas, chartElements, renderInfo);
}
function renderBarChart(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
barInfo: BarInfo
) {
@@ -1617,7 +1623,7 @@ function renderBarChart(
// console.log(renderInfo);
if (!renderInfo || !barInfo) return;
- let chartElements = createAreas(canvas, renderInfo);
+ let chartElements = createAreas(svgCanvas, renderInfo);
renderTitle(chartElements, renderInfo, barInfo);
@@ -1705,7 +1711,7 @@ function renderBarChart(
renderLegend(chartElements, renderInfo, barInfo);
}
- setChartScale(canvas, chartElements, renderInfo);
+ setChartScale(svgCanvas, chartElements, renderInfo);
}
export function renderErrorMessage(canvas: HTMLElement, errorMessage: string) {
@@ -1721,3 +1727,25 @@ export function renderErrorMessage(canvas: HTMLElement, errorMessage: string) {
.style("padding", "10px")
.style("color", "red");
}
+
+export function renderSvg(
+ svgCanvas: any,
+ renderInfo: RenderInfo,
+ svgInfo: SvgInfo
+) {
+ // Remove graph not completed
+ // let graph = d3.select(canvas).select("#svg").remove();
+
+ if (svgInfo.element) {
+ let svg = svgInfo.element;
+ // unicode space
+ svg = svg.replace(
+ /[\u00A0\u1680\u180e\u2000-\u2009\u200a\u200b\u202f\u205f\u3000]/g,
+ " "
+ );
+ // html space
+ svg = svg.replace(/ /g, " ");
+ // console.log(svg);
+ svgCanvas.append("svg").html(svg);
+ }
+}
diff --git a/src/summary.ts b/src/summary.ts
index 053155c..e84193b 100644
--- a/src/summary.ts
+++ b/src/summary.ts
@@ -7,7 +7,7 @@ function checkSummaryTemplateValid(summaryTemplate: string): boolean {
}
export function renderSummary(
- canvas: HTMLElement,
+ svgCanvas: any,
renderInfo: RenderInfo,
summaryInfo: SummaryInfo
) {
@@ -31,20 +31,41 @@ export function renderSummary(
outputSummary = retResolvedTemplate;
if (outputSummary !== "") {
- let textBlock = d3.select(canvas).append("div");
+ let svg = svgCanvas
+ .append("svg")
+ .attr("id", "svg")
+ .attr("width", 200)
+ .attr("height", 200);
+
+ let textBlock = svg.append("text")
+ .attr("x", 0)
+ .attr("y", 0);
if (outputSummary.includes("\n") || outputSummary.includes("\\n")) {
let outputLines = outputSummary.split(/(\n|\\n)/);
// console.log(outputLines);
for (let outputLine of outputLines) {
- if (outputLine !== "\n" && outputLine !== "\\n")
- textBlock.append("div").text(outputLine);
+ if (outputLine !== "\n" && outputLine !== "\\n") {
+ let line = textBlock.append("tspan").text(outputLine);
+ line.attr("x", 0)
+ .attr("dy", "1.5em")
+ .attr("class", "tracker-summary-text");
+
+ if (summaryInfo.style !== "") {
+ line.attr("style", summaryInfo.style);
+ }
+ }
}
} else {
- textBlock.text(outputSummary);
- }
+ let line = textBlock.text(outputSummary);
+ line.attr("x", 0)
+ .attr("dy", "1.5em")
+ .attr("class", "tracker-summary-text");
- if (summaryInfo.style !== "") {
- textBlock.attr("style", summaryInfo.style);
+ if (summaryInfo.style !== "") {
+ line.attr("style", summaryInfo.style);
+ }
}
+
+
}
}
diff --git a/styles.css b/styles.css
index 9cd8b4c..1196663 100644
--- a/styles.css
+++ b/styles.css
@@ -179,4 +179,10 @@
fill: var(--color-tick-label);
stroke: none;
font-size: 12px;
+}
+
+.tracker-summary-text {
+ fill: var(--color-tick-label);
+ font-size: 18px;
+ stroke: none;
}
\ No newline at end of file