Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new "Event Marker" path type #668

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4988ad5
initial work to get event markers working
MatthewScott967 Mar 1, 2022
af23913
run rollup
MatthewScott967 Mar 1, 2022
b92d155
get label rendering working
MatthewScott967 Mar 6, 2022
ca4ed60
Merge branch 'master' into event-markers
MatthewScott967 Mar 6, 2022
2df4630
Merge pull request #1 from MatthewScott967/event-markers
MatthewScott967 Mar 6, 2022
dfb74bf
clean up, ready for PR to leeoniya
MatthewScott967 Mar 6, 2022
88ad1d2
Merge pull request #2 from MatthewScott967/event-markers
MatthewScott967 Mar 6, 2022
133d9eb
Revert "clean up, ready for PR to leeoniya"
MatthewScott967 Mar 12, 2022
76cfb39
Merge pull request #3 from MatthewScott967/revert-2-event-markers
MatthewScott967 Mar 12, 2022
02c065c
Revert "Event markers"
MatthewScott967 Mar 12, 2022
109e96c
Merge pull request #4 from MatthewScott967/revert-1-event-markers
MatthewScott967 Mar 12, 2022
4f4d577
redo event-markers as demo / plugin
MatthewScott967 Mar 12, 2022
493c8b0
Merge branch 'master' into event-markers-as-demo
MatthewScott967 Mar 12, 2022
0a3242c
Everything working with only minor core change
MatthewScott967 Mar 13, 2022
359430a
minor formating cleanup before PR
MatthewScott967 Mar 13, 2022
6d71981
run rollup to update dist
MatthewScott967 Mar 13, 2022
603efd9
Merge pull request #5 from MatthewScott967/event-markers-as-demo
MatthewScott967 Mar 13, 2022
5112498
needed to add a s._path null check
MatthewScott967 Mar 13, 2022
976c069
Merge pull request #6 from MatthewScott967/event-markers-as-demo
MatthewScott967 Mar 13, 2022
7f8cf8f
turn label rendering on for both series
MatthewScott967 Mar 13, 2022
124c834
Merge pull request #7 from MatthewScott967/event-markers-as-demo
MatthewScott967 Mar 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions demos/event-markers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Events Markers Series</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="../dist/uPlot.min.css">
</head>
<body>
<script src="../dist/uPlot.iife.js"></script>
<script src="./eventMarkers.js"></script>
<script>
let xs = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30];
let vals = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10];
let events_1 = [null,null,null,null,null,null,"Event_1 0",null,null,null,null,null,null,"Event_1 1",null,null,null,null,"Event_1 2",null,null,null,null,null,null,null,null,null,null,null];
let events_2 = [null,null,null,null,null,null,null,null,null,null,null,"Event_2 0",null,null,null,null,null,null,null,null,"Event_2 1",null,null,null,null,null,null,null,null,null];

let data = [
xs,
xs.map((t, i) => vals[Math.floor(Math.random() * vals.length)]),
xs.map((t, i) => vals[Math.floor(Math.random() * vals.length)]),
events_1,
events_2,
];

function roundIncr(x, incr) {
return Math.round(x/incr)*incr;
}

const moveTuple = [0,0];

function cursorMove(self, left, top) {
moveTuple[0] = roundIncr(left, 10);
moveTuple[1] = roundIncr(top, 10);
return moveTuple;
}

const opts = {
width: 1920,
height: 600,
title: "Event Markers Series Demo",
cursor: {
move: cursorMove
},
scales: {
x: {
time: false,
},
},
series: [
{},
{
stroke: "red",
fill: "rgba(255,0,0,0.1)",
},
{
stroke: "blue",
fill: "rgba(0,0,255,0.1)",
},
{
paths: eventMarkers({showLabels: true, labelsAlign: "top"}),
value: (u, v) => v == null ? "--" : v,
auto: false,
label: "Event_1 Marker",
width: 2,
stroke: "purple",
fill: "rgba(245,235,255)",
},
{
paths: eventMarkers({showLabels: true, labelsAlign: "bottom"}),
value: (u, v) => v == null ? "--" : v,
auto: false,
label: "Event_2 Marker",
width: 2,
stroke: "green",
fill: "rgba(245,255,245)",
},
],
};

let u = new uPlot(opts, data, document.body);
</script>
</body>
</html>
112 changes: 112 additions & 0 deletions demos/eventMarkers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
function eventMarkers(opts) {
opts = opts || {};

let labels = [];
let textFill = "black";
let rectFill = "white";
let rectStroke = "black";

let showLabels = opts.showLabels == null ? true: opts.showLabels;
let labelsAlign = opts.labelsAlign == null ? "top" : opts.labelsAlign;

function drawPathLabels(u, seriesIdx) {
let rectPadding = 7;

let s = u.series[seriesIdx];

textFill = s._stroke == null ? textFill : s._stroke;
rectFill = s._fill == null ? rectFill : s._fill;
rectStroke = s._stroke == null ? rectStroke : s._stroke;

u.ctx.fillStyle = textFill;
u.ctx.textAlign = "center";
u.ctx.textBaseline = "center";

labels.forEach((label) => {
let text = u.ctx.measureText(label.text);

let textWidth = text.width;
let textHeight = text.actualBoundingBoxDescent + text.actualBoundingBoxAscent;

let rectWidth = textWidth + (rectPadding * 2);
let rectHeight = textHeight + (rectPadding * 2);

let yOffAlign = text.actualBoundingBoxAscent + rectPadding;

if (label.align == "center")
{
yOffAlign = rectHeight;
}
else if (label.align == "bottom")
{
yOffAlign = -(text.actualBoundingBoxDescent + rectPadding);
}

let textCenterX = label.x;
let textCenterY = label.y + yOffAlign;

let rectTop = textCenterX - (rectWidth / 2);
let rectLeft = textCenterY - (rectHeight / 2);

u.ctx.fillStyle = rectFill;
u.ctx.strokeStyle = rectStroke;

u.ctx.fillRect(rectTop, rectLeft, rectWidth, rectHeight);
u.ctx.strokeRect(rectTop, rectLeft, rectWidth, rectHeight);

u.ctx.fillStyle = textFill;
u.ctx.fillText(label.text, textCenterX, textCenterY);
});
}

return (u, seriesIdx, idx0, idx1) => {
return uPlot.orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {

labels = [];

let pxRound = series.pxRound;
const _paths = {stroke: new Path2D(), fill: null, text: drawPathLabels, clip: null, band: null, gaps: null, flags: uPlot.BAND_CLIP_FILL};
const stroke = _paths.stroke;

let yBottom = yOff + yDim;
let yTop = yOff;

let labelPadding = 6;
let yLabel = yTop + labelPadding;

if (labelsAlign == "bottom")
{
yLabel = yBottom - labelPadding;
}
else if (labelsAlign == "center")
{
yLabel = (yBottom - yTop) / 2;
}

for (let i = idx0; i <= idx1; i++) {
let yEventName = dataY[i];

if (yEventName == null) {
continue;
}
let x = pxRound(valToPosX(dataX[i], scaleX, xDim, xOff));

stroke.moveTo(x, yBottom);
stroke.lineTo(x, yTop);

if (showLabels)
{
let labelElement = {text: dataY[i], align: labelsAlign, x: x, y: yLabel};
labels.push(labelElement);
}
}

_paths.gaps = null;
_paths.fill = null;
_paths.clip = null;
_paths.band = null;

return _paths;
});
};
}
5 changes: 5 additions & 0 deletions dist/uPlot.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3643,6 +3643,11 @@ function uPlot(opts, data, then) {
}
}

if (s._paths != null && s._paths.text != null)
{
s._paths.text(self, i);
}

if (ctxAlpha != 1)
ctx.globalAlpha = ctxAlpha = 1;

Expand Down
3 changes: 3 additions & 0 deletions dist/uPlot.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,9 @@ declare namespace uPlot {
/** path to fill */
fill?: Path2D | Map<CanvasRenderingContext2D['fillStyle'], Path2D> | null;

/** fn to draw path labels */
text?: ((self: uPlot, seriesIdx: number) => void) | null;

/** path for clipping fill & stroke (used for gaps) */
clip?: Path2D | null;

Expand Down
5 changes: 5 additions & 0 deletions dist/uPlot.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3641,6 +3641,11 @@ function uPlot(opts, data, then) {
}
}

if (s._paths != null && s._paths.text != null)
{
s._paths.text(self, i);
}

if (ctxAlpha != 1)
ctx.globalAlpha = ctxAlpha = 1;

Expand Down
5 changes: 5 additions & 0 deletions dist/uPlot.iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -3644,6 +3644,11 @@ var uPlot = (function () {
}
}

if (s._paths != null && s._paths.text != null)
{
s._paths.text(self, i);
}

if (ctxAlpha != 1)
ctx.globalAlpha = ctxAlpha = 1;

Expand Down
2 changes: 1 addition & 1 deletion dist/uPlot.iife.min.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/uPlot.js
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,11 @@ export default function uPlot(opts, data, then) {
}
}

if (s._paths != null && s._paths.text != null)
{
s._paths.text(self, i);
}

if (ctxAlpha != 1)
ctx.globalAlpha = ctxAlpha = 1;

Expand Down