Arc Rider Docs · Markdown

Premium Widgets

Custom Calendar Timeline

Custom Calendar Timeline

AI Defaults
uniqueId
Required, `"timeline-" + Nr`.
height
Use `"700px"` or `"100%"` when embedded; `"auto"` lets the widget grow with content (Ninox form scrolls).
timeZoneBalance
Set `-1` for German timezone.
header
`dateSettings.header.days` (Tages-Labels). Optional `header.months` / `header.weeks`.** `header.title`**: Titel/Layout oben links über den Spaltennamen (Text, HTML oder Widget) — nicht mehr die Tageszeile. Reiner Text ohne Extra-Typo: **16px / Schriftstärke 400**. Alte Configs mit `header.title.label` (`##day##` …) ohne `value`/`customLayout` gelten weiter als Tageszeile.
columns
Label-Spalten links (Titel im Header, optional `width`); mindestens eine Spalte. Header-Farbe default = `dateSettings.header.days` (`backgroundColor` / `fontColor`); pro Spalte überschreibbar.
items
Ressourcen-Zeilen; jedes Item braucht `id` (eindeutig pro Zeile) und `timeEntries`. Verschachtelung über `items` (max. eine Ebene unterhalb des Parents).
dateFrom/dateTo
Actual date values in timeEntries, not strings.
dayWidth
Default `"120px"`, increase for detailed timelines. Startbreite, wenn kein gespeicherter Zoom existiert; überschreibbar via `zoomSettings.defaultDayWidth`.
zoomSettings
Optional. Zoom ist standardmäßig aktiv (`enabled: false` zum Abschalten). `defaultDayWidth`, `minDayWidth`, `maxDayWidth`, `step`, `persist` (LocalStorage pro `uniqueId`), `controls.enabled` für +/- unten rechts.
dragAction
`recordId` + optional `resourceField` für vertikal; nur **gleiche Verschachtelungstiefe** (`_depth`, z. B. Mitarbeiter ↔ Mitarbeiter auch **über Teams hinweg**). Optional `enabled: false` schaltet Drag für diesen Balken aus. Optional `changeFieldValues` für Zusatzfelder nach erfolgreichem Drag (z. B. Cache-/Trigger-Felder).
Uhrzeit mode
Activated by `timeSettings`, uses `columnWidth` instead of `dayWidth`. `timeFrom`/`timeTo` in milliseconds.
styles.borders
Gleicher Vertrag wie Table (`outer` / `columns` / `rows`). Default: Rahmen an, Zeilenlinien an, **Spaltenlinien aus**. `outer: false` für bündig im Layout. Dark Mode über `backgroundColor`, `headerBackgroundColor`, `fontColor`, `borderColor`.
styles.dayStripes
Default **an** — Tagesspalten abwechselnd Weiß / sehr helles Grau. `false` schaltet aus; `{ odd, even }` setzt eigene Farben. Wochenend-Highlights liegen darüber.
Zellen-Hintergrund
`dateSettings.highlights[]` mit optional `applyToRows: true`; optional `items[].highlights` pro Zeile (`date`, `dateFrom`/`dateTo` bzw. `timeFrom`/`timeTo`).
Ghost (Neueinträge)
Optional **pro Zeile** `items[].ghost` mit** `title`, `actions`, optional `position` (Default `bottomRight`: kleiner Plus-Button unten rechts in der Spalte), optional `styles`**. Klick führt `ghost.actions` aus. **Positionen außer `timeEntry`**: Plus erscheint erst bei **Maus über der Spalte** (Spalte wird per Zeilen-`mousemove` erkannt); **Touch**: Ghost bleibt sichtbar.** `timeEntry`**: siehe Abschnitt ghost (Idle nur in leeren Spalten). Details im Abschnitt **ghost**.
tooltip pro Balken
Optional. Hover-Tooltip mit `value` (Text **oder** Widget-Deskriptor `{ widget, uid, data }`), optional `width` / `maxWidth` / `maxHeight` / `position` / `styles`. Portaliert an `document.body` (kein Clipping). Details im Abschnitt **tooltip**. Con el widget **Custom Calendar Timeline** llevas una vista de calendario basada en recursos a tu base de datos Ninox. Los recursos (p. ej. empleados, salas, vehículos) se representan como filas, y los días u horas como columnas. Las citas aparecen como barras horizontales — ideal para planificación de intervenciones, vista de capacidades o gestión de recursos. 💡 **Lo que puedes hacer con Custom Calendar Timeline:**
Recursos como filas:
Cada fila representa un recurso (persona, sala, equipo, vehículo).
Citas como barras:
Las entradas se extienden horizontalmente sobre los días — con o sin hora.
Modo horario:
Muestra columnas de hora en lugar de días — ideal para diagramas de flota y planificación diaria de intervenciones.
Entradas jerárquicas:
`items` con sub-`items` (un nivel), filas planas con sangría — modelo de datos como Gantt.
Arrastrar y soltar:
Mueve citas horizontalmente (cambiar fecha/hora) o verticalmente (cambiar recurso/fila).
Entradas de varios días:
Muestra proyectos, vacaciones o bloques más largos a lo largo de varios días.
Resaltado:
Marca fines de semana, ciertas horas o días especiales con color.
Estilo individual:
Adapta colores, anchos y alturas a tu diseño. 📅 **Custom Calendar Timeline** es especialmente adecuado para planificación de intervenciones, planes de turnos, vistas de capacidad y **diagramas de flota** — en todos los casos donde quieras controlar recursos y citas en el tiempo.

Código de aplicación

let current := this;
arcCustomCalendarTimeline({
    uniqueId: "timeline-1",
    timeZoneBalance: 0,
    lang: "de",
    dateSettings: {
        startDate: today(),
        duration: 30,
        highlights: [
            { weekday: 6, color: "rgba(59,130,246,0.06)" },
            { weekday: 0, color: "rgba(59,130,246,0.06)" }
        ],
        header: {
            days: {
                label: "##weekDayShort## ##day##.",
                fontSize: "12px",
                fontColor: "#52525b",
                fontWeight: "600",
                backgroundColor: "#fafafa"
            }
        }
    },
    dayWidth: "120px",
    rowHeight: "auto",
    currentTime: "rgba(59,130,246,0.5)",
    height: "700px",
    styles: {
        backgroundColor: "#ffffff"
    },
    columns: [
        { title: "Name", width: "200px" },
        { title: "Abteilung", width: "130px" }
    ],
    items: (select Mitarbeiter).[{
        id: Nr,
        title: Name,
        subtitle: Abteilung,
        columns: [
            { title: text(Name) },
            { title: text(Abteilung) }
        ],
        timeEntries: (select Termine where Bearbeiter = Nr).[{
            title: Bezeichnung,
            subtitle: Kunde,
            dateFrom: Datum_von,
            dateTo: Datum_bis,
            timeFrom: Zeit_von,
            timeTo: Zeit_bis,
            styles: {
                backgroundColor: text(Farbe),
                color: "#fff",
                borderRadius: "6px",
                padding: "4px 8px"
            },
            dragAction: {
                recordId: Nr,
                dateFrom: fieldId(Nr, "Datum_von"),
                dateTo: fieldId(Nr, "Datum_bis"),
                resourceField: fieldId(Nr, "Bearbeiter"),
                changeFieldValues: [{
                    fieldId: fieldId(Nr, "CacheTrigger"),
                    value: now()
                }]
            },
            actions: [{
                type: "popup",
                recordId: Nr
            }]
        }]
    }]
})

Ajustes generales

uniqueId

Identificador único del widget. Importante si se usan varios widgets Timeline en una página.

uniqueId: "timeline-1",

timeZoneBalance

Corrección de zona horaria en horas. Para Alemania a menudo -1, para adaptar la visualización a CET/CEST.

timeZoneBalance: 0,
timeZoneBalance: -1,

lang

Idioma para el formato de fecha (p. ej. nombres de días de la semana).

lang: "de",
lang: clientLang(),

height

Altura del contenedor del widget.

  • "700px" o "100%" — altura fija con scroll interno (por defecto en Ninox-Embeds).
  • "auto" — la Timeline crece con el contenido; el formulario de Ninox hace scroll vertical (sin scroll vertical interno). Horizontalmente la Timeline sigue haciendo scroll dentro del widget.
  • Con maxHeight se puede limitar la altura automática; entonces la Timeline hace scroll vertical internamente.
height: "700px",
height: "100%",
height: "auto",
maxHeight: "600px",
minHeight: "200px",

styles

Los bordes y las líneas de cuadrícula viven en styles — junto con fondo, radio y color de línea. Mismo contrato que Custom Table.

Por defecto: borde exterior redondeado, líneas de fila, sin líneas de columna verticales — como Table.

Cada campo de línea es true / false o { color, width }.

PropDefaultBedeutung
styles.backgroundColor—Fläche inkl. Label-Spalten links
styles.headerBackgroundColor= backgroundColorName/Abteilung + Ecken
styles.groupBackgroundColor= HeaderMonats-/KW-Zeile
styles.rowBackgroundColor= backgroundColorTagesraster-Zeilen
styles.fontColor—Text links und Fallback für Header
styles.mutedColor / subtleColor= fontColorSekundärtext / Untertitel
styles.borderColor#e4e4e7Farbe für alle angeschalteten Linien
styles.borderRadius12pxEckenradius (nur wenn outer an)
styles.borders.outertrueAußenrahmen. false = bündig im Layout
styles.borders.columnsfalseVertikale Linien im Tagesgitter und zwischen Label-Spalten. Die Kante Labels → Raster bleibt an.
styles.borders.rowstrueHorizontale Ressourcenlinien
styles.dayStripestrueTagesspalten abwechselnd Weiß / sehr helles Grau. false = aus. { odd, even } = eigene Farben.
styles: {
  backgroundColor: "#ffffff",
  borderRadius: "12px",
  borderColor: "#e4e4e7",
  borders: {
    outer: true,
    columns: false,
    rows: true
  }
}

// In einem Layout / Card: styles: { borders: { outer: false } }

// Tagesgitter wieder an: styles: { borders: { columns: true } }

// Tagesspalten-Zebra aus: styles: { dayStripes: false }

// Dunkler Hintergrund: styles: { backgroundColor: &quot;#18181b&quot;, borderColor: &quot;#3f3f46&quot;, borders: { outer: true, rows: { color: &quot;#27272a&quot; } } }</code></pre>

dateSettings – periodo y representación

startDate

Fecha de inicio de la Timeline. A partir de este día se muestran las columnas.

startDate: today(),
startDate: date(2025, 2, 1),

duration

Número de días mostrados. Se ignora si se define endDate.

duration: 30,
duration: 14,

endDate

*(Opcional)* Fecha de fin de la Timeline. Tiene prioridad sobre duration.

dateSettings: {
    startDate: date(2025, 2, 1),
    endDate: date(2025, 2, 28)
}

highlights

Resaltado de color de determinados días — p. ej. fines de semana o festivos.

highlights: [
    { weekday: 6, color: "rgba(59,130,246,0.06)" },
    { weekday: 0, color: "rgba(59,130,246,0.06)" },
    { date: date(2025, 12, 24), color: "rgba(239,68,68,0.1)" }
],
  • weekday: 0 = domingo, 6 = sábado
  • date: Fecha concreta
  • dateFrom / dateTo: Rango de fechas (opcional en lugar de date único)
  • color: Color CSS (HEX o rgba)

En modo horario además: - hour: Hora (0–23) para resaltar determinadas columnas de hora - timeFrom / timeTo: Rango de tiempo en milisegundos (como en timeEntries), p. ej. pausa de mediodía

highlights: [
    { hour: 12, color: "rgba(239,68,68,0.1)" }
]
highlights: [
    { weekday: 6, color: "rgba(59,130,246,0.06)", applyToRows: true },
    { date: date(2025, 12, 24), color: "rgba(239,68,68,0.1)", applyToRows: true },
    { timeFrom: time(12, 0), timeTo: time(13, 0), color: "rgba(156,163,175,0.15)", applyToRows: true }
],

highlights por fila (items[].highlights)

Además de los dateSettings.highlights globales, cada fila de recurso puede tener su propio array highlights — p. ej. vacaciones o baja por enfermedad solo para un empleado. Se aplican los mismos campos que arriba; applyToRows no es necesario aquí (siempre se aplica solo a esta fila).

items: (select Mitarbeiter).[{
    id: Nr,
    title: Name,
    highlights: [
        { dateFrom: Urlaub_von, dateTo: Urlaub_bis, color: "rgba(34,197,94,0.15)" },
        { date: Krank_Tag, color: "rgba(239,68,68,0.12)" }
    ],
    timeEntries: [...]
}]

Modo horario: p. ej. ventanas de bloqueo o mantenimiento con timeFrom / timeTo.

header

El bloque header controla todas las cabeceras de la Timeline. Consta de tres subbloques opcionales: months, weeks y days. Los tres tienen la misma estructura y se pueden activar de forma independiente. El orden en el widget es siempre: meses → semanas calendario → días (de arriba a abajo).

header: {
    months: {
        visible: true,
        label: "##monthLong## ##year##",
        fontSize: "11px",
        fontColor: "#555",
        fontWeight: "600",
        backgroundColor: "#ececec",
        highlights: [
            { month: 5, color: "rgba(59,130,246,0.12)" }
        ]
    },
    weeks: {
        visible: true,
        label: "KW ##week##",
        fontSize: "11px",
        fontColor: "#555",
        backgroundColor: "#f2f2f2",
        highlights: [
            { week: 18, color: "rgba(239,68,68,0.1)" }
        ]
    },
    days: {
        visible: true,
        label: "##weekDayShort## ##day##.",
        fontSize: "12px",
        fontColor: "#333",
        fontWeight: "600",
        backgroundColor: "#f9f9f9"
    }
}

header.title se sitúa arriba a la izquierda sobre los nombres de columna (Name, Abteilung), en una superficie tan alta como la fila de mes + KW. Los nombres de columna están en la misma fila que los días, con línea hacia arriba. Texto simple sin fontSize / fontWeight / layout personalizado: 16px, grosor de fuente 400.

header: {
    title: {
        value: "Teamplanung",
        alignX: "left"
    }
}
PropertyBeschreibung
valueText oder HTML. Alternativ ein Widget-Deskriptor { widget, uid, data }.
customLayoutHTML oder Widget-Deskriptor (wie in Label-Zellen). Hat Vorrang vor value.
alignX"left" \"center" \"right"
fontSize / fontColor / fontWeight / backgroundColorTypo und Fläche des Slots

Sin mes/KW no existe el slot (sin fila extra). Legacy: Solo header.title con label (##day## …) y sin value/customLayout sigue controlando la fila de días, cuando falta header.days.

Los tres bloques de fila (months / weeks / days) son opcionales. Si se omite un bloque, no está activo.

Propiedades comunes (por subbloque):

PropertyBeschreibung
visiblefalse blendet die Zeile aus (Standard: true)
labelAnzeigetext mit Platzhaltern (s. u.)
alignX"left" \"center" \"right" – horizontale Ausrichtung in der Zelle bzw. Gruppe. Standard: "left" (Monat/KW-Gruppen und Tage).
fontSizeSchriftgröße, z. B. "12px"
fontColorSchriftfarbe
fontWeightSchriftstärke, z. B. "600"
backgroundColorHintergrund der gesamten Zeile bzw. Monats-/KW-Gruppe. days: färbt u. a. die Tages-Headerzeile; bei days.sticky: "left" hat der Beschriftungs-span kein eigenes undurchsichtiges backgroundColor, damit dateSettings.highlights (Farb-Overlay pro Tages-div) hinter dem Text sichtbar bleibt.
highlightsHervorhebungen pro Monats- bzw. KW-Gruppe (s. u.) – nur für months / weeks
stickyOptional für months, weeks und days: sticky: "left" hält die Bezeichnung bei horizontalem Scrollen sichtbar (CSS position: sticky); der horizontale Abstand setzt an den linken sichtbaren Rand des Zeitbereichs, berechnet als Summe aller linken columns-Breiten + stickyPadding. Ohne sticky steuert nur alignX die Ausrichtung.
stickyPaddingZusätzlicher Abstand in px (Zahl) oder z. B. "12px", addiert auf die Labelspalten-Breite für sticky: "left". Wenn weggelassen, wird +8 px addiert.
hideBelowOptional. days: Spaltenbreite in px — darunter verschwindet der Tages-Text; die Zeile bleibt als Trenner. Default: pro Tag eine vertikale Linie (data-arc-day-ticks). Mit compactRanges: true stattdessen KW- bzw. Monats-Ranges (01.09. - 07.09.). Default-Schwelle: 36. weeks/months: minimale Gruppenbreite in px, unter der der Label-Text ausgeblendet wird — die Zeile bleibt. Defaults: weeks 44, months 72.
compactRangesOptional, nur days. true = beim Rauszoomen Tage zu KW-/Monats-Ranges zusammenfassen. Default: aus (Tick-Linien).
monthCompactBelowOptional, nur days, nur mit compactRanges. Spaltenbreite in px — darunter wechselt die Range von KW auf Monat. Default: 14.
labelBreakpointsOptional, nur days: Array { below, label } — bei mittlerer Spaltenbreite kürzeres Tages-Label (bevor der Text ganz verschwindet).

Nota: dateSettings.highlights colorean por día la celda de cabecera del día (div, opcionalmente con applyToRows también el área de fila). En combinación con header.days.sticky: "left", ten en cuenta la nota de backgroundColor en la tabla.

Marcadores para days.label: - ##weekDayShort## – Día de la semana corto (Lu, Ma, …) - ##weekDayLong## – Día de la semana largo (Lunes, Martes, …) - ##day## – Día (1–31) - ##monthShort## – Mes corto (Ene, Feb, …) - ##monthLong## – Mes largo (Enero, Febrero, …) - ##year## – Año

Marcadores para weeks.label: - ##week## – Número de semana calendario (01–53, dos cifras con cero inicial) - ##year## – Año

Marcadores para months.label: - ##monthLong## – Nombre de mes largo (Enero, Febrero, …) - ##monthShort## – Nombre de mes corto (Ene, Feb, …) - ##year## – Año highlights por subbloque:

months: {
    highlights: [
        { month: 5, color: "rgba(59,130,246,0.12)" }   // Mai hervorheben (1 = Januar)
    ]
},
weeks: {
    highlights: [
        { week: 18, color: "rgba(239,68,68,0.1)" }     // KW 18 hervorheben
    ]
}
  • months.highlights: { month: N } – N = 1 (enero) a 12 (diciembre)
  • weeks.highlights: { week: N } – N = número de semana calendario ISO

Parámetros de layout

dayWidth

Ancho de una columna de día (valor inicial). Si el zoom está activo y el usuario aún no tiene un nivel de zoom guardado, se aplica zoomSettings.defaultDayWidth — si no, este valor.

dayWidth: "120px",
dayWidth: "90px",

zoomSettings

Controla el zoom interactivo y el ancho de columna inicial. El nivel de zoom elegido se guarda por uniqueId en el LocalStorage (junto con la posición de scroll), salvo que persist sea false.

zoomSettings: {
    enabled: true,
    defaultDayWidth: 48,
    minDayWidth: 16,
    maxDayWidth: 200,
    step: 8,
    persist: true,
    controls: {
        enabled: true,
        position: "bottomRight"
    }
}
  • enabled: false desactiva el zoom por completo — solo dayWidth estático, sin controles.
  • defaultDayWidth: Ancho inicial en px, si no existe un valor guardado.
  • minDayWidth / maxDayWidth: Límite inferior y superior del ancho de columna.
  • step: Paso en px por clic en +/−.
  • persist: Guardar el nivel de zoom en LocalStorage (por defecto: true).
  • controls: Botones flotantes abajo a la derecha en el widget.

El zoom con rueda de ratón/pinch no está incluido en v1 (previsto).

rowHeight

Altura de una fila de recurso. "auto" se adapta al contenido.

rowHeight: "auto",
rowHeight: "36px",

labelWidth

Ancho estándar para una columna de etiqueta, si falta columns o si en columns[i] no se ha definido width. Por defecto: "120px".

labelWidth: "150px",

currentTime

Color de la barra que marca la hora actual. Vacío o false la oculta.

currentTime: "rgba(59,130,246,0.5)",
currentTime: "",

items – recursos y citas

items es un array de filas de recurso. Cada fila tiene timeEntries (barras). Opcional: items (hijos, un nivel) y columns (textos de celda por columna de etiqueta).

Estructura de una fila

{
    id: Nr,
    title: Name,
    subtitle: Abteilung,
    fontSize: "13px",
    fontWeight: "normal",
    columns: [
        { title: text(Name) },
        { title: text(Abteilung) }
    ],
    styles: {},
    highlights: [],
    timeEntries: [...],
    items: [...]
}
  • id *(obligatorio)*: ID único (p. ej. Nr del registro). Se necesita para arrastrar y soltar (resourceField) y collapsible.
  • title / subtitle: Fallback para la primera columna de etiqueta, si falta columns o la primera celda está vacía.
  • fontSize / fontWeight *(opcional, nivel item)*: Tipografía estándar para todas las celdas de etiqueta de esta fila, siempre que ni la columna de nivel superior ni columns[i] definan nada. Orden de prioridad (mayor primero): columns[i] → Item fontSize/fontWeight → styles.fontSize/styles.fontWeight.
  • columns *(por fila)*: Un objeto por columna de etiqueta (mismo número que columns de nivel superior): title, subtitle, opcional customLayout (HTML para esta celda), actions, opcional alignX, alignY, fontSize, fontWeight.
  • styles: Opcional (p. ej. fondo de fila; fontSize/fontWeight aquí actúan como último fallback de tipografía).
  • highlights *(opcional)*: Fondo de celda para esta fila (ausencias, horarios bloqueados); consulta la sección highlights por fila.
  • timeEntries: Citas/barras en esta fila. Espacio horizontal: fijo 4px hasta el borde de la columna (como el padding de fila arriba/abajo); en barras de varias columnas solo en el inicio y fin exteriores, no entre los días (no modificable mediante timeEntries[].styles).
  • items: Opcional. Subfilas (un nivel).

Estructura de un timeEntry (cita/barra)

{
    title: Bezeichnung,
    subtitle: Kunde,
    dateFrom: Datum_von,
    dateTo: Datum_bis,
    timeFrom: Zeit_von,
    timeTo: Zeit_bis,
    styles: {},
    dragAction: {},
    actions: [],
    tooltip: {},
    customLayout: "",
    value: ""
}
  • title: Texto en la barra, u objeto { value: …, width: … } (ver abajo). En indicaciones de hora se puede usar ##entrytime##.
  • subtitle: Opcional. Segundo bloque de texto en la barra (string u objeto como en title).
  • direction *(opcional)*: "vertical" u "horizontal" – título y subtitle uno bajo el otro o uno junto al otro.
  • dateFrom, dateTo: Fecha de inicio y fin (obligatorio).
  • timeFrom, timeTo: Opcional. Hora en milisegundos (0 = medianoche). Sin indicación, la entrada se muestra como de todo el día.
  • styles: Propiedades similares a CSS (backgroundColor, color, borderRadius, padding).
  • dragAction: Configuración para arrastrar y soltar.
  • actions: Array de acciones al hacer clic en la barra (como en otros widgets). El anterior campo único clickAction sigue siendo compatible y se ejecuta como una entrada de actions.
  • tooltip: Opcional. Overlay al pasar el ratón con información adicional (ver abajo).
  • customLayout: Opcional. Layout propio en lugar de title/subtitle/value.
  • value: Opcional. Contenido HTML adicional en la barra (después del bloque título/subtitle).

Forma de objeto para title / subtitle: { value: TextOderHtml, width: "fraction" | "auto" | CSS-Länge }

- value: Texto o HTML a mostrar (como antes); ##entrytime## posible. - width *(opcional, default "fraction"): - "fraction" – usa el espacio restante en la fila; el texto largo se recorta con puntos suspensivos. - "auto" – ancho de contenido; no se reduce a favor del compañero (p. ej. para horas que deben permanecer totalmente visibles). Un texto muy largo puede terminar con puntos suspensivos en el borde de la barra igualmente. - Longitud CSS** (p. ej. "72px", "4.5rem") – ancho base fijo (flex-basis) para este bloque.

Si title y subtitle son solo strings (sin objeto) y direction no está configurado, se colocan uno bajo el otro. Si al menos un campo usa la forma de objeto (sin direction), se colocan uno junto al otro (Flex + width). Con direction: "horizontal" o "vertical" fuerzas la alineación.

title: { value: text(Bezeichnung), width: "fraction" },
subtitle: { value: "##entrytime##", width: "auto" },

tooltip – información al pasar el ratón sobre la barra

Tooltip opcional al pasar el ratón por timeEntry. El overlay se cuelga de document.body (flecha + sombra), no se recorta con la barra y permanece abierto de forma estable al pasar el ratón — incluso si Ninox vuelve a renderizar en segundo plano. Es posible mover el ratón hacia el tooltip (widgets/botones interactivos).

tooltip: {
    value: "Kunde: Meier GmbH" + newline() + "Status: geplant",
    width: "280px",
    maxWidth: "360px",
    maxHeight: "300px",
    position: "auto",
    styles: {
        backgroundColor: "#1f2937",
        color: "#fff"
    },
    trigger: "hover"
}
  • value *(obligatorio)*: Contenido — string de texto/HTML o descriptor de nueva generación { widget: "arc-widget-layout", uid: "tt-" + Nr, data: { … } }. ID completo del registro (arc-widget-…), config bajo data, uid propio. Widgets anidados con acciones funcionan.
  • width / maxWidth / maxHeight: Opcional. Longitudes CSS; con maxHeight el contenido hace scroll internamente.
  • position: "top" | "bottom" | "left" | "right" | "auto" (default "auto" — prefiere arriba, cambia si falta espacio).
  • styles: Opcional. entre otros backgroundColor, color, borderRadius, padding, boxShadow. Para un contorno continuo alrededor de la caja y la flecha: borderWidth + borderColor (SVG stroke en la forma de la burbuja).
  • trigger: v1 solo "hover" (reservado para un futuro "click").

Técnicamente: el tooltip es una burbuja SVG (un path para rectángulo redondeado + flecha integrada), portada a document.body. Fill y stroke se aplican a toda la forma — sin triángulo CSS separado.

Un clic en la barra sigue ejecutando actions. Sin tooltip no cambia nada.

Ejemplos

1) Oscuro + borde (texto)

tooltip: {
    value: "Kunde: Meier GmbH" + newline() +
        "Status: geplant" + newline() +
        "Notiz: Parkplatz hinter dem Gebäude",
    width: "280px",
    position: "auto",
    styles: {
        backgroundColor: "#1f2937",
        color: "#fff",
        borderWidth: "1px",
        borderColor: "rgba(255,255,255,0.28)"
    }
}

2) Claro suave (claro + borde)

tooltip: {
    value: html("<strong>Wartung Anlage Nord</strong><br>Dauer: 3 Tage<br>Ersatzteil: Filterkit #442"),
    maxWidth: "300px",
    position: "bottom",
    styles: {
        backgroundColor: "#ffffff",
        color: "#1f2937",
        borderWidth: "1px",
        borderColor: "rgba(15,23,42,0.14)",
        borderRadius: "10px",
        boxShadow: "0 10px 28px rgba(15, 23, 42, 0.12)"
    }
}

3) Claro + widget (vertical, botón a todo lo ancho)

tooltip: {
    value: {
        widget: "arc-widget-layout",
        uid: "tt-" + Nr,
        data: {
            direction: "vertical",
            gap: "8px",
            width: "100%",
            blocks: [
                {
                    width: "100%",
                    value: html("<div style='font-weight:600;color:#0f172a'>Termin-Details</div>")
                },
                {
                    width: "100%",
                    value: html("<div style='color:#334155;font-size:12px'>Kunde: Schmidt AG<br>Thema: Angebot Q3</div>")
                },
                {
                    width: "100%",
                    value: {
                        widget: "arc-widget-button",
                        uid: "tt-btn-" + Nr,
                        data: {
                            title: "Öffnen",
                            width: "100%",
                            height: "30px",
                            fontSize: "12px",
                            backgroundColor: "#3b82f6",
                            fontColor: "#fff",
                            borderRadius: "6px",
                            actions: [{ type: "popup", recordId: Nr }]
                        }
                    }
                }
            ]
        }
    },
    width: "240px",
    position: "top",
    styles: {
        backgroundColor: "#ffffff",
        color: "#0f172a",
        borderWidth: "1px",
        borderColor: "rgba(15,23,42,0.16)",
        borderRadius: "12px",
        padding: "12px"
    }
}

4) Posición izquierda / derecha

tooltip: {
    value: "Zusatzinfo neben dem Balken",
    width: "240px",
    position: "right", // oder "left"
    styles: {
        backgroundColor: "#ffffff",
        color: "#0f172a",
        borderWidth: "1px",
        borderColor: "rgba(15,23,42,0.16)"
    }
}

Consejo: En la barra a menudo conviene establecer direction: "vertical", para que título y subtitle queden uno bajo el otro y el subtitle permanezca visible.

styles – estilo de las barras de cita

styles: {
    backgroundColor: "#3b82f6",
    color: "#fff",
    borderRadius: "6px",
    padding: "4px 8px"
},

dragAction – mover citas

Define qué campos se actualizan al arrastrar.

dragAction: {
    recordId: Nr,
    dateFrom: fieldId(Nr, "Datum_von"),
    dateTo: fieldId(Nr, "Datum_bis"),
    resourceField: fieldId(Nr, "Bearbeiter"),
    enabled: true,
    changeFieldValues: [{
        fieldId: fieldId(Nr, "CacheTrigger"),
        value: now()
    }]
},
  • recordId: ID del registro de la cita (normalmente Nr).
  • dateFrom, dateTo: Field IDs para fecha de inicio y fin. Se actualizan al mover horizontalmente.
  • resourceField: Opcional. Field ID para el recurso (p. ej. responsable). Se actualiza al mover verticalmente (cambio de fila) con el id de la fila de destino — solo si la fila de origen y la de destino tienen la misma profundidad en la jerarquía de items (_depth igual). Necesario, por ejemplo, para que ninguna cita se arrastre de una fila de equipo a una fila de empleado (o al revés); empleado bajo equipo A → empleado bajo equipo B está permitido.
  • enabled: Opcional. false: sin arrastre para esta barra (p. ej. sumas de parent). Si se omite, el arrastre está activo en cuanto se define dragAction.
  • changeFieldValues: Opcional. Array de { fieldId, value } – se escribe después de un arrastre exitoso (la fecha/hora y/o el recurso han cambiado). Uso típico: actualizar campos de caché o de trigger. Estructura igual que en las acciones de Create (ghost.actions).

⚠️ Nota: Sin dragAction, arrastrar y soltar está desactivado. El arrastre vertical entre diferentes profundidades (p. ej. fila de equipo ↔ fila de empleado) no es posible; dentro de la misma profundidad (p. ej. solo filas de empleado) sí es posible incluso entre diferentes parents (equipos).

actions – clic en cita

actions: [{
    type: "popup",
    recordId: Nr
}],
  • type: "popup" abre el registro en una ventana popup.
  • recordId: ID del registro de la cita clicada.

Varias entradas en el array se ejecutan sucesivamente. Legacy: Un único objeto** clickAction (sin array) sigue funcionando.

actions – clic en celda de etiqueta

En items[].columns[i] se puede definir opcionalmente actions. Si el array no está vacío, un clic en la celda ejecuta las mismas acciones de Ninox. Nota: En la primera columna de etiqueta, en grupos contraídos** (collapsible) el clic tiene prioridad para expandir/contraer; ahí no se ejecutan actions adicionales en la celda.

items: (select Fahrzeuge).[{
    id: Nr,
    columns: [
        { title: text(Bezeichnung), subtitle: "Fahrzeug" },
        {
            title: "⌂",
            actions: [{
                type: "popup",
                recordId: Nr
            }]
        }
    ],
    timeEntries: [...]
}]

columns pertenece a la fila correspondiente bajo items. Un clic en la segunda columna (aquí ⌂) abre el registro de la fila (Nr). Se ejecutan sucesivamente tantas entradas como se quiera en el array actions.

ghost – barra de fila para nuevas entradas (wrapper)

A nivel de cada entrada en items[] (no en columns[]) se puede definir opcionalmente un objeto ghost — independiente por fila (recurso). Una fila sin ghost no tiene franja de creación.

Campos:

- title – opcional, se usa como tooltip del navegador (atributo title) en el botón de más (p. ej. «Crear cita»). - position – opcional, controla la visualización y el layout del botón ghost por columna: - bottomRight (default, puede omitirse) – botón cuadrado pequeño (28×28 px), absoluto en la columna correspondiente abajo a la derecha; no ocupa toda la anchura de columna. El botón está fuera del grid CSS de la fila (absoluto respecto a la fila), para que los timeEntries permanezcan en la misma fila de grid que sin ghost. Stacking: el botón queda justo por encima de las barras normales (z-index 11), por debajo del hover de barra (10) y de la barra activa/en arrastre (100). - bottomLeft, topRight, topLeft – mismo botón, otra esquina de la columna. - timeEntry – comportamiento clásico: todo el ancho de columna en la primera fila de grid (con 4px de margen horizontal como las barras de cita), desplaza las barras de cita visibles a la fila siguiente (align-content: start en la fila). - actions – obligatorio, al menos una acción de Ninox; normalmente type: "create" con campos precargados. Un clic en el botón de más ejecuta estas acciones con el valor de esta columna (ver marcadores). - styles – opcional, objeto con propiedades CSS en camelCase (como en timeEntries[].styles), p. ej. backgroundColor, fontColor (color de texto incl. icono de más mediante currentColor), fontSize, fontWeight, borderRadius, paddingX / paddingY (se combinan en padding) o padding (shorthand), border, boxShadow. El legacy color se mapea como fontColor al color de fuente; si fontColor está definido, tiene prioridad. Se aplican al botón; gridColumn / gridRow los define el widget para la colocación en la cuadrícula (sobrescribe posibles valores propios en styles).

Representación (default bottomRight entre otros): Por columna, un área absoluta con clic transparente sobre la fila (sin elemento de grid — evita el desplazamiento de las barras). El botón de más es blanco, con sombra ligera, esquina según position. Hover de columna (ratón en la columna): El botón se hace visible con fondo blanco semitransparente y desenfoque backdrop-filter (frosted glass). Directamente sobre el botón: blanco opaco, sin blur — legibilidad total. Mediante styles puedes definir, por ejemplo, backgroundColor (sobrescribe los colores estándar).

Representación (timeEntry): Como una barra estrecha sobre el ancho de columna en la fila 1 (con 4px de margen izquierda/derecha como las barras de cita); los timeEntries de la fila empiezan debajo.

Visibilidad / hover:

  • Todas las posiciones excepto timeEntry: El botón de más es invisible por defecto y aparece solo cuando el ratón está en algún lugar de esta columna de día/hora (incluso sobre una barra); la columna se determina según la posición del ratón sobre la fila. En dispositivos táctiles (sin hover preciso), los botones ghost permanecen visibles.

- timeEntry: Para cada columna se comprueba por separado si hay una barra de cita visible que llegue a la columna. Sin barra: con @media (hover: hover) la barra ghost está oculta inicialmente por opacidad, hasta que el ratón pasa sobre la celda ghost. Con barra en la columna: la barra ghost permanece visible. En táctil los elementos ghost permanecen visibles.

Marcadores (en cualquier valor string dentro de la acción, de forma recursiva):

- ##columnValue## – valor en milisegundos de la columna bajo el clic: en modo día inicio del día (startDate + índice de columna), en modo hora inicio del intervalo de tiempo (startTime + índice × amount). - ##clickedDate## – alias con la misma semántica (compatibilidad con Calendar Grid / Week).

items: (select Mitarbeiter).[{
    id: Nr,
    ghost: {
        position: "bottomRight",
        title: "Termin anlegen",
        styles: {
            backgroundColor: "rgba(0, 0, 0, 0.08)",
            fontColor: "#333333",
            borderRadius: "6px",
            paddingY: "4px",
            paddingX: "8px"
        },
        actions: [{
            type: "create",
            tableId: "B",
            popup: true,
            changeFieldValues: [
                { fieldId: fieldId(Nr, "Datum"), value: "##columnValue##" },
                { fieldId: fieldId(Nr, "Bearbeiter"), value: number(Nr) }
            ]
        }]
    },
    timeEntries: [...]
}]

Los clics en las barras de cita (timeEntries) siguen disparando solo las actions de cada barra, no ghost.actions.

Ejemplo – modo horario: ##columnValue## es el inicio del intervalo de tiempo clicado en milisegundos (como timeFrom en las barras).

arcCustomCalendarTimeline({
    uniqueId: "timeline-fleet-neu",
    mode: "time",
    timeSettings: {
        startTime: 6,
        duration: 12,
        amount: 0.25
    },
    columnWidth: "60px",
    rowHeight: "36px",
    height: "700px",
    dateSettings: {
        header: {
            title: {
                label: "##hour##:##minute##",
                fontSize: "11px",
                fontColor: "#333"
            }
        }
    },
    columns: [
        { title: "Fahrzeug", width: "160px" },
        { title: "Info", width: "80px" }
    ],
    items: (select Fahrzeuge).[{
        id: Nr,
        ghost: {
            title: "Neue Fahrt",
            actions: [{
                type: "create",
                tableId: "B",
                popup: true,
                changeFieldValues: [
                    { fieldId: fieldId(Nr, "Startzeit"), value: "##columnValue##" },
                    { fieldId: fieldId(Nr, "Fahrzeug"), value: number(Nr) }
                ]
            }]
        },
        timeEntries: [...]
    }]
})

Alternativamente puedes usar ##clickedDate## en lugar de ##columnValue## — ambos se resuelven igual.

weekStart

Día de inicio de la semana (0 = domingo, 1 = lunes, …). Afecta al orden de los días.

weekStart: 1,

timeSettings – modo horario (Time Mode)

Si en lugar de días quieres mostrar horas como columnas, puedes activar el modo horario. Es ideal para diagramas de flota, planes de turnos o planificación diaria de intervenciones, donde el eje X representa un solo día.

El modo horario se activa automáticamente en cuanto se define timeSettings — o explícitamente con mode: "time".

arcCustomCalendarTimeline({
    uniqueId: "fleet-timeline",
    mode: "time",
    timeSettings: {
        startTime: 6,
        duration: 12,
        amount: 0.25
    },
    columnWidth: "60px",
    rowHeight: "36px",
    height: "700px",
    dateSettings: {
        header: {
            title: {
                label: "##hour##:##minute##",
                fontSize: "11px",
                fontColor: "#333"
            }
        }
    },
    columns: [
        { title: "Fahrzeug / Tag", width: "160px" },
        { title: "Info", width: "80px" }
    ],
    items: (select Fahrzeuge).[{
        id: Nr,
        title: Bezeichnung,
        fontSize: "12px",
        fontWeight: "600",
        columns: [
            { title: text(Bezeichnung), subtitle: "Fahrzeug" },
            { title: "⌂" }
        ],
        items: (select Einsatztage where Fahrzeug = Nr).[{
            id: Nr,
            title: Wochentag,
            fontSize: "11px",
            columns: [
                { title: text(Wochentag) },
                { title: "" }
            ],
            timeEntries: (select Fahrten where Einsatztag = Nr).[{
                title: Route,
                timeFrom: Startzeit,
                timeTo: Endzeit,
                styles: {
                    backgroundColor: text(Farbe),
                    color: "#fff"
                }
            }]
        }]
    }]
})

startTime

A partir de qué hora empieza la línea de tiempo (p. ej. 6 = 06:00 h).

startTime: 6,
startTime: 8,

duration

Cuántas horas se muestran (p. ej. 12 = 12 horas desde startTime).

duration: 12,
duration: 8,

amount

Intervalo de columna en horas. Determina la granularidad de la división de tiempo.

amount: 1,
amount: 0.5,
amount: 0.25,
  • 1 = columnas por hora (08:00, 09:00, …)
  • 0.5 = columnas de 30 minutos (08:00, 08:30, 09:00, …)
  • 0.25 = columnas de 15 minutos (08:00, 08:15, 08:30, …)

Marcadores de cabecera en modo horario

En modo horario hay marcadores adicionales disponibles para dateSettings.header.days.label:

  • ##hour## – Hora con cero inicial (06, 07, …)
  • ##minute## – Minuto con cero inicial (00, 15, 30, …)
  • ##time## – Hora completa (06:00, 08:15, …)

columnWidth

Ancho de una columna de tiempo (alias de dayWidth en modo horario).

columnWidth: "60px",
columnWidth: "80px",

timeEntries en modo horario

En modo horario, timeEntries usa los campos timeFrom/timeTo en lugar de dateFrom/dateTo (en milisegundos desde medianoche):

timeEntries: [{
    title: "RVS GZ-NU-KE",
    timeFrom: 27000000,
    timeTo: 41400000,
    styles: {
        backgroundColor: "#0066cc"
    }
}]

💡 Conversión: Horas × 3600000 (p. ej. 07:30 = 7,5 × 3600000 = 27000000)

Arrastrar y soltar en modo horario

En modo horario, al arrastrar y soltar se actualizan timeFrom/timeTo en lugar de dateFrom/dateTo:

dragAction: {
    recordId: Nr,
    timeFrom: fieldId(Nr, "Startzeit"),
    timeTo: fieldId(Nr, "Endzeit"),
    resourceField: fieldId(Nr, "Einsatztag")
}

columns (nivel superior)

Define las columnas de etiqueta izquierdas (junto al área de tiempo). Por entrada en el array: title (aparece en la fila con las etiquetas de día), opcional subtitle, opcional width (ancho CSS, p. ej. "200px"). Si falta width, se aplica labelWidth (por defecto 120px).

Opcional: alignX: "left" \| "center" \| "right" (por defecto left), alignY: "top" \| "center" \| "bottom" (por defecto center) – alineación de la cabecera y el contenido de celda en esta columna. fontSize y fontWeight (valores CSS, p. ej. "13px", "600" o "bold") se aplican a cabecera y celdas de esta columna, siempre que ni items[].columns[i] ni el item-fontSize/fontWeight estén definidos. Por celda se puede sobrescribir en items[].columns[i] alignX, alignY, fontSize, fontWeight.

Cabecera de las columnas de etiqueta (Name, Abteilung): El color estándar procede de dateSettings.header.days (backgroundColor, fontColor). Se puede sobrescribir por columna con columns[n].backgroundColor y columns[n].fontColor.

Sin columns o array vacío: una columna con labelWidth.

items – filas de datos y anidación

Todos los recursos se llaman uniformemente items. Lista plana: items: [{ id, title, subtitle, timeEntries, … }].

Anidación (un nivel): Un item puede contener items: [...]. El parent y los hijos se renderizan como filas propias una bajo la otra; la primera columna de etiqueta en los hijos aparece con sangría. Más de un nivel no está previsto actualmente en la Timeline (la estructura de datos se puede ampliar más adelante). items[].columns (por fila): Array con una entrada por columna de etiqueta (misma longitud que columns de nivel superior). Campos por celda: title, subtitle, opcional customLayout, opcional actions, opcional alignX / alignY, opcional fontSize / fontWeight (máxima prioridad para tipografía). Después actúan item-fontSize/fontWeight, luego la columna de nivel superior, luego styles. Entradas faltantes → celda vacía. Fallback: Si falta columns o la primera celda no tiene contenido, se usan title/subtitle del item solo para la primera columna.

Parent con subfilas: La fila parent tiene timeEntries como cualquier otra fila (p. ej. barras de suma). Los hijos están en items y tienen sus propios valores de columns.

columns: [
    { title: "Fahrzeug / Tag", width: "160px" },
    { title: "Info", width: "80px" }
],
items: [{
    id: "v1",
    title: "A-MS 419",
    subtitle: "GPS",
    columns: [
        { title: "A-MS 419", subtitle: "GPS" },
        { title: "⌂", subtitle: "Fzg." }
    ],
    timeEntries: [{ title: "Tagesblock", timeFrom: ... }],
    items: [{
        id: "v1-mo",
        title: "Mo",
        columns: [{ title: "Mo" }, { title: "" }],
        timeEntries: [...]
    }]
}]

collapsible – expandir y contraer grupos

Si usas entradas jerárquicas (items con sub-items), puedes contraer y expandir la fila parent (p. ej. nombre de equipo o vehículo) mediante una prop del widget. El estado se persiste por uniqueId en el navegador (localStorage).

Configuración

arcCustomCalendarTimeline({
    uniqueId: "timeline-teams-" + Nr,
    collapsible: {
        enabled: true,
        iconPosition: "left",
        iconCollapse: "",
        iconExpand: ""
    },
    columns: [ { title: "Team / Person", width: "200px" }, { title: "Termine", width: "120px" } ],
    items: [ /* Parent mit items */ ]
})
PropertyBedeutung
enabledtrue: Toggle-Icon in der ersten Label-Spalte der Parent-Zeile; Klick klappt alle Unterzeilen ein/aus.
iconPosition*(Optional)* "left" oder "right" – Icon vor/neben dem Text (Standard: left).
iconCollapse*(Optional)* HTML/SVG für aufgeklappt (Standard: Chevron unten).
iconExpand*(Optional)* HTML/SVG für eingeklappt (Standard: Chevron rechts).
  • Se aplica a filas con items (hijos). id del item parent debe ser único (estado de plegado).
  • styles en el parent/hijo actúan sobre toda la fila de etiqueta (fondo de las celdas).

---

Con Custom Calendar Timeline llevas planificación basada en recursos y total flexibilidad a tu base de datos Ninox — ideal para planificación de intervenciones, vista de capacidades, gestión de recursos y diagramas de flota.

Happy Widgeting 🥳