diff --git a/package.json b/package.json
index 0192588..cfadbc2 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"@typescript-eslint/parser": "^6.19.0",
"autoprefixer": "^10.4.16",
"conventional-changelog-eslint": "^5.0.0",
+ "dayjs": "^1.11.10",
"dequal": "^2.0.3",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 95c7ff3..92bbe35 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,6 +41,9 @@ devDependencies:
conventional-changelog-eslint:
specifier: ^5.0.0
version: 5.0.0
+ dayjs:
+ specifier: ^1.11.10
+ version: 1.11.10
dequal:
specifier: ^2.0.3
version: 2.0.3
@@ -1598,6 +1601,10 @@ packages:
hasBin: true
dev: true
+ /dayjs@1.11.10:
+ resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
+ dev: true
+
/debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
diff --git a/src/lib/Block.ts b/src/lib/Block.ts
index 4da1eb9..ce80d87 100644
--- a/src/lib/Block.ts
+++ b/src/lib/Block.ts
@@ -26,7 +26,7 @@ export class Block implements ISequenceChild {
data?: {
[key: string]: unknown;
};
- markers: { time: number; label: string }[] = [];
+ markers: { time: number; title?: string }[] = [];
errors: { type: string; message: string }[] = [];
private _inTime?: number;
diff --git a/src/lib/components/Block.svelte b/src/lib/components/Block.svelte
index 4d17639..5d648ee 100644
--- a/src/lib/components/Block.svelte
+++ b/src/lib/components/Block.svelte
@@ -250,7 +250,7 @@
{#if markers.length > 0}
{#each markers as marker, index}
-
{/each}
diff --git a/src/lib/components/BlockMarker.svelte b/src/lib/components/BlockMarker.svelte
index f96ec8b..508c73a 100644
--- a/src/lib/components/BlockMarker.svelte
+++ b/src/lib/components/BlockMarker.svelte
@@ -4,13 +4,21 @@
export let time: number;
export let index: number;
+ export let title = `Marker #${index + 1}`;
export let disableSnapping = false;
export let block: Block;
export let tag = 'div';
- const { duration, width, scrubOverride, time: playheadTime } = getSequenceContext();
+ const { duration, width, scrubOverride, time: playheadTime, formatTimeFn } = getSequenceContext();
+
+ //export let format = (value: number) => `${Math.round(value)}`;
+
+ export let formatTitle = () => {
+ return `${title} (+${formatTimeFn(time)})`;
+ };
+
$: timeToPixel = (1 / $duration) * $width;
$: absoluteTime = time + block.absoluteInTime;
@@ -25,7 +33,7 @@
>
`${Math.round(value)}`;
+
setSequenceContext({
time,
duration,
@@ -29,7 +31,8 @@
width,
snapTimes,
selectedHandle,
- scrubOverride
+ scrubOverride,
+ formatTimeFn
});
$: currentTime = $time;
@@ -84,7 +87,7 @@
>
-
+
diff --git a/src/lib/components/SequenceContext.ts b/src/lib/components/SequenceContext.ts
index 9740562..034e22d 100644
--- a/src/lib/components/SequenceContext.ts
+++ b/src/lib/components/SequenceContext.ts
@@ -12,6 +12,7 @@ export type SequenceContext = {
snapTimes: Writable;
scrubOverride: Writable;
sequence: Writable;
+ formatTimeFn: (time: number) => string;
};
export const key = Symbol();
diff --git a/src/lib/components/Timebar.svelte b/src/lib/components/Timebar.svelte
index 5b2511d..3145c81 100644
--- a/src/lib/components/Timebar.svelte
+++ b/src/lib/components/Timebar.svelte
@@ -4,9 +4,9 @@
import TimebarLabel from './TimebarLabel.svelte';
- const { time, duration, scrubOverride, selectedHandle } = getSequenceContext();
+ const { time, duration, scrubOverride, selectedHandle, formatTimeFn: sequenceFormatTimeFn } = getSequenceContext();
- export let formatTimeFn = (value: number) => `${Math.round(value)}`;
+ export let formatTimeFn = sequenceFormatTimeFn;
// We could instead have a store for timebarLabels that we loop over to allow showing n number of relevant times and control through context
let extraTime: number | null = null;
diff --git a/src/lib/components/TimebarLabel.svelte b/src/lib/components/TimebarLabel.svelte
index 0b46b31..958a448 100644
--- a/src/lib/components/TimebarLabel.svelte
+++ b/src/lib/components/TimebarLabel.svelte
@@ -2,9 +2,9 @@
import { uniqueClasses } from '../utils';
import { getSequenceContext } from './SequenceContext';
- const { duration, width } = getSequenceContext();
+ const { duration, width, formatTimeFn } = getSequenceContext();
- export let formatFn = (value: number) => `${Math.round(value)}`;
+ export let formatFn = formatTimeFn;
export let time: number;
let pos: number;
diff --git a/src/routes/examples/markers/+page.svelte b/src/routes/examples/markers/+page.svelte
index e1176e2..ee6ae27 100644
--- a/src/routes/examples/markers/+page.svelte
+++ b/src/routes/examples/markers/+page.svelte
@@ -5,6 +5,10 @@
import CustomLayer from './CustomLayer.svelte';
import { Label, Input } from 'flowbite-svelte';
+ import dayjs from 'dayjs';
+ import dayjsDuration from 'dayjs/plugin/duration';
+ dayjs.extend(dayjsDuration);
+
const PromoterBlockTemplate = {
key: 'promoter',
type: 'promoter',
@@ -32,43 +36,40 @@
markers: [
{
time: 1000,
- label: 'scene 1'
+ title: 'scene 1'
},
{
time: 1050,
- label: 'scene 2'
+ title: 'scene 2'
},
{
time: 300,
- label: 'scene 3'
},
{
time: 4000,
- label: 'scene 4'
},
{
time: 5000,
- label: 'scene 5'
},
{
time: 6000,
- label: 'scene 6'
+ title: 'scene 6'
},
{
time: 7000,
- label: 'scene 7'
+ title: 'scene 7'
},
{
time: 8000,
- label: 'scene 8'
+ title: 'scene 8'
},
{
time: 9000,
- label: 'scene 9'
+ title: 'scene 9'
},
{
time: 10000,
- label: 'scene 10'
+ title: 'scene 10'
}
]
}
@@ -181,6 +182,44 @@
/*
TODO: toggle snapping
*/
+
+ const millisInSecond = 1000;
+ const millisInFrame = (framerate: number) => {
+ return (1 / framerate) * millisInSecond;
+ };
+
+ type formatTimeOptions = {
+ framerate?: number;
+ format?: string;
+ };
+ const formatTimeFn = (time: number, options?: formatTimeOptions) => {
+ if (time === undefined || time === null) {
+ return '';
+ }
+
+ time = Math.floor(time);
+
+ let format = options?.format ?? 'HH:mm:ss.SSS';
+ const framerate = options?.framerate ?? 25;
+
+ const duration = dayjs.duration(time, 'milliseconds');
+
+ if (format.includes('FF')) {
+ // calculate remaining frames after smallest unit in format string
+
+ const millis = duration.milliseconds();
+ const frames = Math.floor(millis / millisInFrame(framerate));
+
+ format = format.replace('FF', `${frames}`.padStart(2, '0'));
+ }
+
+ if (format.includes('R')) {
+ format = format.replace('R', `${framerate}`);
+ }
+
+ return `${duration.format(format)}`;
+};
+
@@ -219,11 +258,11 @@
`${value}`}
class="dark:bg-gray-900"
/>