diff --git a/demo/src/App.tsx b/demo/src/App.tsx
index 469555d4..32d0c86a 100644
--- a/demo/src/App.tsx
+++ b/demo/src/App.tsx
@@ -1,12 +1,8 @@
import { ComponentType } from 'react'
-import {
- createBrowserRouter,
- Link,
- RouteObject,
- RouterProvider,
-} from 'react-router-dom'
+import { createBrowserRouter, Link, RouteObject, RouterProvider } from 'react-router-dom'
import DemoMain from './demo-main'
+import DemoCustom from './demo-custom'
import DemoPerformance from './demo-performance'
import DemoTreePGroups from './demo-tree-groups'
import LinkedTimelines from './demo-linked-timelines'
@@ -18,7 +14,7 @@ import CustomHeaders from './demo-headers'
import CustomInfoLabel from './demo-custom-info-label'
import ControledSelect from './demo-controlled-select'
import ControlledScrolling from './demo-controlled-scrolling'
-import ExternalDrop from "./demo-external"
+import ExternalDrop from './demo-external'
const loader = () => 'loading'
const routes: RouteObject[] = [
{
@@ -26,6 +22,11 @@ const routes: RouteObject[] = [
Component: withLayout(DemoMain),
loader,
},
+ {
+ path: '/CustomTimescale',
+ Component: withLayout(DemoCustom),
+ loader,
+ },
{
path: '/DemoPerformance',
Component: withLayout(DemoPerformance),
@@ -72,9 +73,9 @@ const routes: RouteObject[] = [
Component: withLayout(ControlledScrolling),
},
{
- path: "/ExternalDrop",
+ path: '/ExternalDrop',
Component: withLayout(ExternalDrop),
- }
+ },
]
function Menu() {
diff --git a/demo/src/demo-custom/generate-fake-data.js b/demo/src/demo-custom/generate-fake-data.js
new file mode 100644
index 00000000..105472a5
--- /dev/null
+++ b/demo/src/demo-custom/generate-fake-data.js
@@ -0,0 +1,41 @@
+import { faker } from '@faker-js/faker'
+import randomColor from "randomcolor";
+import dayjs from 'dayjs';
+
+export default function (groupCount = 30, itemCount = 1000, daysInPast = 30) {
+ let randomSeed = Math.floor(Math.random() * 1000);
+ let groups = [];
+ for (let i = 0; i < groupCount; i++) {
+ groups.push({
+ id: `${i + 1}`,
+ title: faker.name.firstName(),
+ rightTitle: faker.name.lastName(),
+ bgColor: randomColor({ luminosity: "light", seed: randomSeed + i })
+ });
+ }
+
+ let items = [];
+ for (let i = 0; i < itemCount; i++) {
+ const startDate = faker.date.recent({ days: daysInPast }).valueOf() + daysInPast * 0.3 * 86400 * 1000
+ const startValue = Math.floor(dayjs(startDate).valueOf() / 10000000) * 10000000
+ const endValue = dayjs(startDate + faker.number.int({ min: 2, max: 20 }) * 15 * 60 * 1000).valueOf()
+
+ items.push({
+ id: i + "",
+ group: faker.number.int({ min: 1, max: groups.length }) + '',
+ title: faker.hacker.phrase(),
+ start: startValue,
+ end: endValue,
+ // canMove: startValue > new Date().getTime(),
+ // canResize: 'both',
+ className: dayjs(startDate).day() === 6 || dayjs(startDate).day() === 0 ? "item-weekend" : "",
+ itemProps: {
+ "data-tip": faker.hacker.phrase()
+ }
+ });
+ }
+
+ items = items.sort((a, b) => b - a);
+
+ return { groups, items };
+}
diff --git a/demo/src/demo-custom/groups.json b/demo/src/demo-custom/groups.json
new file mode 100644
index 00000000..3a18a49d
--- /dev/null
+++ b/demo/src/demo-custom/groups.json
@@ -0,0 +1,70 @@
+[
+ {
+ "id": 10,
+ "title": "U.S. President"
+ },
+ {
+ "id": 20,
+ "title": "Windows"
+ },
+ {
+ "id": 21,
+ "title": "Android"
+ },
+ {
+ "id": 22,
+ "title": "RPG Maker"
+ },
+ {
+ "id": 40,
+ "title": "Pokemon game"
+ },
+ {
+ "id": 30,
+ "title": "Nintendo console"
+ },
+ {
+ "id": 31,
+ "title": "Nintendo handheld"
+ },
+ {
+ "id": 32,
+ "title": "Sony console"
+ },
+ {
+ "id": 33,
+ "title": "Sony handheld"
+ },
+ {
+ "id": 34,
+ "title": "Microsoft console"
+ },
+ {
+ "id": 35,
+ "title": "Sega console"
+ },
+ {
+ "id": 41,
+ "title": "Mario game"
+ },
+ {
+ "id": 42,
+ "title": "Zelda game"
+ },
+ {
+ "id": 49,
+ "title": "GTA game"
+ },
+ {
+ "id": 50,
+ "title": "Best Picture"
+ },
+ {
+ "id": 51,
+ "title": "Star Wars movies"
+ },
+ {
+ "id": 52,
+ "title": "Marvel movies (MCU)"
+ }
+]
diff --git a/demo/src/demo-custom/index.jsx b/demo/src/demo-custom/index.jsx
new file mode 100644
index 00000000..ee854ea6
--- /dev/null
+++ b/demo/src/demo-custom/index.jsx
@@ -0,0 +1,184 @@
+import React from 'react'
+import { Component } from 'react'
+import dayjs from 'dayjs'
+import randomColor from "randomcolor";
+
+import Timeline, { TimelineMarkers, TodayMarker, CustomMarker, CursorMarker } from '../../../src/index'
+
+import generateFakeData from './generate-fake-data'
+
+var keys = {
+ groupIdKey: "id",
+ groupTitleKey: "title",
+ groupRightTitleKey: "rightTitle",
+ itemIdKey: "id",
+ itemTitleKey: "title",
+ itemDivTitleKey: "title",
+ itemGroupKey: "group",
+ itemTimeStartKey: "start",
+ itemTimeEndKey: "end",
+ groupLabelKey: "title"
+};
+
+function customData() {
+ let randomSeed = Math.floor(Math.random() * 1000);
+ let groups = [
+ { id: 1, title: "G1", rightTitle: "Right Title 1", bgColor: randomColor({ luminosity: "light", seed: randomSeed + 0 }) },
+ { id: 2, title: "G2", rightTitle: "Right Title 2", bgColor: randomColor({ luminosity: "light", seed: randomSeed + 1 }) },
+ { id: 3, title: "G3", rightTitle: "Right Title 3", bgColor: randomColor({ luminosity: "light", seed: randomSeed + 2 }) },
+ ]
+
+ let items = [];
+ items.push({
+ id: "0",
+ group: "1",
+ title: "Hercules",
+ start: 0,
+ end: 16 * 10,
+ canChangeGroup: false,
+ className: "",
+ itemProps: { "data-tip": "GO" }
+ });
+ items.push({
+ id: "1",
+ group: "1",
+ title: "Ares",
+ start: 16 * 12,
+ end: 16 * 30,
+ canChangeGroup: false,
+ className: "",
+ itemProps: { "data-tip": "GO" }
+ });
+ items.push({
+ id: "2",
+ group: "2",
+ title: "Artemis",
+ start: 16 * 4,
+ end: 16 * 124,
+ canMove: true,
+ canChangeGroup: false,
+ className: "",
+ itemProps: { "data-tip": "GO" }
+ });
+ items.push({
+ id: "3",
+ group: "3",
+ title: "Athena",
+ start: 16 * 1,
+ end: 16 * 60,
+ canChangeGroup: false,
+ canResize: "both",
+ className: "",
+ itemProps: { "data-tip": "GO" }
+ });
+
+ return { groups, items };
+}
+
+export default class App extends Component {
+ constructor(props) {
+ super(props);
+
+ // const { groups, items } = generateFakeData(3, 6, 1);
+ const { groups, items } = customData();
+ // const defaultTimeStart = dayjs(items[0].start_time).startOf('day').toDate().valueOf()
+ const defaultTimeStart = 1
+ // const defaultTimeEnd = dayjs(items[0].end_time).startOf('day').add(1, 'day').toDate().valueOf()
+ const defaultTimeEnd = 10000
+
+ this.state = {
+ groups,
+ items,
+ defaultTimeStart,
+ defaultTimeEnd
+ };
+ }
+
+ handleItemClick = (itemId, _, time) => {
+ console.log('Clicked: ' + itemId, dayjs(time).format())
+ }
+
+ handleItemSelect = (itemId, _, time) => {
+ console.log('Selected: ' + itemId, dayjs(time).format())
+ }
+
+ handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ const { items, groups } = this.state;
+
+ const group = groups[newGroupOrder];
+
+ this.setState({
+ items: items.map(item =>
+ item.id === itemId
+ ? Object.assign({}, item, {
+ start: dragTime,
+ end: dragTime + (item.end - item.start),
+ group: group.id
+ })
+ : item
+ )
+ });
+
+ console.log("Moved", itemId, dragTime, newGroupOrder);
+ };
+
+ handleItemResize = (itemId, time, edge) => {
+ const { items } = this.state;
+
+ this.setState({
+ items: items.map(item =>
+ item.id === itemId
+ ? Object.assign({}, item, {
+ start: edge === "left" ? time : item.start,
+ end: edge === "left" ? item.end : time
+ })
+ : item
+ )
+ });
+
+ console.log("Resized", itemId, time, edge);
+ };
+
+ handleZoom = (timelineContext, unit, dividers) => {
+ console.log("Unit: ", unit, dividers[unit]);
+ }
+
+ render() {
+ const { groups, items, defaultTimeStart, defaultTimeEnd } = this.state;
+
+ return (
+