Cooking with Gantt Charts

Nick Felker
3 min readMay 31, 2024

--

Several years ago I built a website to help me manage my recipes, pulling them from a machine-readable format and rendering them into a clean UI. I wrote a blog post about it.

Since then, I’ve been cooking a bunch. I actually am already very happy with how the website works, but I did want to try out a few new ideas.

First is adding a new preheat option. I noticed that a lot of recipes start with telling me to preheat my oven.

"steps": [{
"description": "Preheat the oven to 325 degrees Fahrenheit.",
"ingredients": [],
"equipment": [],
"prepTime": {
"amount": 0,
"unit": "minutes"
},
"cookTime": {
"amount": 0,
"unit": "minutes"
}
},

After writing that out a few times, I thought it’d make sense to extract that out to its own top-level field.

 "spec": "v0.1.0",
"tags": "dessert, dairy",
"servings": 6,
"preheat": 162.778,
"steps": [{
...

I’m writing it in Celsius, as that seems more universal even though my oven uses Fahrenheit. That does make the values a bit wonky so I’m not sure if this is the right way of defining it.

I don’t want to deal with unit conversion, and I can round the degrees without an issue, so it’s not a priority.

  fahrenheit(celsius: number) {
return Math.round((celsius * 9 / 5) + 32)
}
  <strong *ngIf="data.preheat">
<i class="material-icons header">local_fire_department</i>
{{data.preheat | number: '1.0-0'}}° C ({{fahrenheit(data.preheat)}}°F)
</strong>

Either way, it does look good when displayed in the UI.

I also wanted to add a Gantt Chart. It can be a useful way to visually a number of different steps to a project over time. I found a Gantt Chart Angular widget on GitHub and downloaded it to my project.

When I load the recipe’s instructions, I take into considering the cookTime and prepTime of each step.

this.ganttItems = steps.map((step: any, i: number) => {
const entry: GanttItem = {
id: i.toString(),
title: step.description,
start: timeNow,
expandable: false,
}
if (step.prepTime && step.prepTime.unit) {
timeNow += unitConversion(step.prepTime.amount, step.prepTime.unit, 'minutes')!*60_000 ?? 0
}
if (step.cookTime && step.cookTime.unit) {
timeNow += unitConversion(step.cookTime.amount, step.cookTime.unit, 'minutes')!*60_000 ?? 0
}
entry.end = timeNow
if (i > 0) {
entry.links = [(i - 1).toString()]
}
return entry
});

I take all this information and create GanttItemobjects. Except for the first one, each subsequent one directly depends on the preceding one. In the future, it might make sense to define steps that can be parallelized. If one pot is cooking, you can multitask with another part of the meal.

This chart has a number of customizable view options. One of these is the scale. For a long time the chart’s time-steps were limited to days, weeks, and months. A recent update added support for hours (minutes?) making it possible to define a window of time.

@ViewChild('gantt') gantt?: NgxGanttComponent
ganttItems: GanttItem[] = []
ganttViewType: GanttViewType = GanttViewType.hour
ganttViewOptions: GanttViewOptions = {
start: new GanttDate().addMinutes(-5),
end: new GanttDate().addHours(1),
min: new GanttDate().addMinutes(-5),
max: new GanttDate().addHours(1).addMinutes(1),
cellWidth: 200,
dateFormat: {
week: 'w',
month: 'M',
quarter: 'QQQ',
year: 'yyyy',
yearMonth: 'yyyy MM',
yearQuarter: 'yyyy QQQ',
}
}
this.gantt!.scrollToDate(new GanttDate(Date.now())) // Now

I just define the chart in Angular by passing in these parameters.

<styled-card *ngIf="true">
<h1>Gantt Chart</h1>
<ngx-gantt #gantt
[items]="ganttItems"
[viewType]="ganttViewType"
[viewOptions]="ganttViewOptions"
[async]="true"
[draggable]="false"
>
<ngx-gantt-table>
<ngx-gantt-column name="{{data?.recipe}}" width="200px">
<ng-template #cell let-item="item">
<span title="{{item.title}}" style="font-size: 10pt;">
{{ item.title }}
</span>
</ng-template>
</ngx-gantt-column>
</ngx-gantt-table>
</ngx-gantt>
</styled-card>

Now when the recipe loads, the chart appears below the steps

There’s still more I want to do, particularly around integrating AI for parsing and transferring photographed recipes to this structured format. My mom has a box of old recipes, some of which are in a hard-to-decipher script. If I could quickly parse them, it could be a great tool.

One day it’d be neat to see if this format could be broadened to support smart home devices now that Matter exists. Hooking the preheat field to quickly set my oven would be neat.

I’ll keep everyone updated on how that goes.

--

--

Nick Felker

Social Media Expert -- Rowan University 2017 -- IoT & Assistant @ Google