Dash-full-calendar component

Dash Full Calendar

As software developers specialized in this framework specifically we working in a lot of different data types. A lot of which can be better explained through unique components and callbacks to dash apps that can better articulate information or function with users. Plotly has a great selection of components but calendar based we are left with limited elegant options of calendar based components. With that, I decided to build out this project dash-full-calendar.

I feel with the introduction of ag grid and dash mantine components specifically the DatePicker component I feel like this design I’ve created could be a nice addition.

I used dash-extensions and connected the endpoints, and this is just be base demo calendar. This project is open source for anyone interested in building off this. I plan on building it out it further but wanted to share with anyone interested in a new calendar component.

The only similar calendar based project I could find was:

plotly_calplot

Interested if anyone else has other calendar or date based components you find useful or are building out.

But with that,
cheers

4 Likes

Thanks for sharing, @PipInstallPython .
It’s impressive that with just three lines of code in the app.py file, we’re able to display the calendar.

If we would like to add new calendar events, we would have to define them inside the full_calendar_deferscript js file. Is that correct?

calendar

1 Like

Thats correct, honestly shocked myself at how easy and few lines of codes where needed to get this working. At the moment the full_calendar_deferscript is the only way to add events to the calendar. This is just to showcase of what is a possible for this component in plotly and dash as a concept, I mainly wanted to highlight the functionality, drag and drop of the individual events dates and the calendar itself as a component. Hasn’t been fully fleshed out or developed just an initial findings.

I built another version of this application with more functionality here: GitHub - pip-install-python/dps-Event-Calendar where I was able to build this out with a django application, with the functionality of a rich text editor creating events, adding them into a database and allowing python to embed those events directly into the calendar. Also built out a modal pop up for events OnClick so they could render not only the event name but the context like picture or full articles to the event when clicked.

This dash version is just initial findings, have only spent a day getting this to run and I’d like to get the project to the same state as my django applicaiton.

2 Likes

That would be so helpful if you were able to get this project to the same state as your django app.

Thanks @PipInstallPython

Thought you guys might be interested, but with dash 2.16 (once some flaky things get ironed out) you can enable any component to interact with the dash eco system, including these calendar events.

Slight modifications on your posted code:

app.py

from dash import *
import dash_mantine_components as dmc


app = Dash(__name__, external_scripts=['https://cdn.jsdelivr.net/npm/fullcalendar/index.global.min.js'])
app.layout = html.Div([
                html.Div(className="card card-calendar", style={"height": "100%"}, children=[
                        html.Div(className="card-body p-3", children=[
                            html.Div(id="calendar", **{"data-bs-toggle": "calendar"})
                        ])
                    ]),
    dmc.Modal(id='modal'),
    dmc.Modal(id='add_modal', children=[dcc.Input(id='add_modal_date')])
])

app.clientside_callback(
    """(id) => {setTimeout(() => {createCalendar(id)}, 1000); return dash_clientside.no_update}""",
    Output('calendar', 'id'), Input('calendar', 'id')
)

if __name__ == "__main__":
    app.run(debug=True)

assets/calendar.js

function createCalendar(id) {
    if (!document.querySelector(`#${id}`)) {
        return
    }
    var calendar = new FullCalendar.Calendar(document.getElementById(id), {
      contentHeight: 'auto',
      initialView: "dayGridMonth",
      headerToolbar: {
        start: 'title', // will normally be on the left. if RTL, will be on the right
        center: '',
        end: 'today prev,next' // will normally be on the right. if RTL, will be on the left
      },
      selectable: true,
      editable: true,
      initialDate: '2021-12-01',
      events: [{
          title: 'Call with Dave',
          start: '2021-11-18',
          end: '2021-11-18',
          className: 'bg-gradient-danger'
        },

        {
          title: 'Lunch meeting',
          start: '2021-11-21',
          end: '2021-11-22',
          className: 'bg-gradient-warning'
        },

        {
          title: 'All day conference',
          start: '2021-11-29',
          end: '2021-11-29',
          className: 'bg-gradient-success'
        },

        {
          title: 'Meeting with Mary',
          start: '2021-12-01',
          end: '2021-12-01',
          className: 'bg-gradient-info'
        },

        {
          title: 'Winter Hackaton',
          start: '2021-12-03',
          end: '2021-12-03',
          className: 'bg-gradient-danger'
        },

        {
          title: 'Digital event',
          start: '2021-12-07',
          end: '2021-12-09',
          className: 'bg-gradient-warning'
        },

        {
          title: 'Marketing event',
          start: '2021-12-10',
          end: '2021-12-10',
          className: 'bg-gradient-primary'
        },

        {
          title: 'Dinner with Family',
          start: '2021-12-19',
          end: '2021-12-19',
          className: 'bg-gradient-danger'
        },

        {
          title: 'Black Friday',
          start: '2021-12-23',
          end: '2021-12-23',
          className: 'bg-gradient-info'
        },

        {
          title: 'Cyber Week',
          start: '2021-12-02',
          end: '2021-12-02',
          className: 'bg-gradient-warning'
        },

      ],
      views: {
        month: {
          titleFormat: {
            month: "long",
            year: "numeric"
          }
        },
        agendaWeek: {
          titleFormat: {
            month: "long",
            year: "numeric",
            day: "numeric"
          }
        },
        agendaDay: {
          titleFormat: {
            month: "short",
            year: "numeric",
            day: "numeric"
          }
        }
      },
      eventClick: function (info) {
        dash_clientside.set_props('modal', {'children': [JSON.stringify(info.event)], 'title': info.event.title, 'opened': true})
      },
      dateClick: function(info) {
        dash_clientside.set_props('add_modal_date', {'value': info.dateStr})
        dash_clientside.set_props('add_modal', {'title': `New Event - ${info.dateStr}`, 'opened': true})
      }
    });

    calendar.render();

    var ctx1 = document.getElementById("chart-line-1").getContext("2d");

    var gradientStroke1 = ctx1.createLinearGradient(0, 230, 0, 50);

    gradientStroke1.addColorStop(1, 'rgba(255,255,255,0.3)');
    gradientStroke1.addColorStop(0.2, 'rgba(72,72,176,0.0)');
    gradientStroke1.addColorStop(0, 'rgba(203,12,159,0)'); //purple colors

    new Chart(ctx1, {
      type: "line",
      data: {
        labels: ["Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        datasets: [{
          label: "Visitors",
          tension: 0.5,
          borderWidth: 0,
          pointRadius: 0,
          borderColor: "#fff",
          borderWidth: 2,
          backgroundColor: gradientStroke1,
          data: [50, 45, 60, 60, 80, 65, 90, 80, 100],
          maxBarThickness: 6,
          fill: true
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: {
            display: false,
          }
        },
        interaction: {
          intersect: false,
          mode: 'index',
        },
        scales: {
          y: {
            grid: {
              drawBorder: false,
              display: false,
              drawOnChartArea: false,
              drawTicks: false,
            },
            ticks: {
              display: false
            }
          },
          x: {
            grid: {
              drawBorder: false,
              display: false,
              drawOnChartArea: false,
              drawTicks: false,
            },
            ticks: {
              display: false
            }
          },
        },
      },
    });
}

Notice the events above are passing info back to the eco system via dash_clientside.set_props and the calendar is responding:

eventClick

dateClick


To find out more about the interactions of fullcalendar, checkout this documentation:

4 Likes

Watching this with great interest! An integrated FullCalendar component in Dash is exactly what I’ve been looking for!

3 Likes