When preparing diner after a day of programming on a Vue project, I was intrigued by the workings of our induction cooker. A lot is going on once you start interacting with it to cook a meal: you turn on the cooker, put some pots and pans on the heaters, turn on individual heaters, start a timer, and so on. That’s a lot of actions, mutations and states… At that moment, I thought it would be fun to create an induction cooker in Vue.
Goal and setup
The goal of this project is to create a UI for the induction cooker focusing on the interaction between the user and the device. I’ll use the Vue CLI to quickly scaffold the project and <svg> elements to draw the cooker on the page. With the HTML set up, it is time to add interaction to the page, so we need a state and a way to manipulate it.
In this post, I’ll show how to create the cooker itself using <svg> elements.
Project and demo
Once the project is fully functioning I’ll put it online as a demo. Until then, the code is available on Github and you can grab the repo and play along.
Using <svg> to draw the induction cooker
As you have seen in the image above, the induction cooker is a black square with 4 heating points and a panel to operate the cooker. It consists mainly of simple forms like rectangles (with rounded corners), circles, and lines. For the operating panel, we need some icons and I’ll use font awesome icons there.
Vue CLI project setup
I am using the Vue CLI user interface, which you can start up with the command
vue ui. I create a new project with presets Vuex, Vue Router, ESLint, and Babel. Once everything is installed, navigate to Tasks, choose ‘serve’ and start the task. This is equivalent to running
npm run serve from the terminal if you’re not using the Vue CLI UI. Open the app to see your app in action.
Root <svg> element
Let’s start working in the Home.vue component. Remove the contents of the template and the reference to the HelloWorld component. Instead, add the root <svg> element as a starting point for the cooker (see code snippet below).
I also quickly remove the <nav> from App.vue and inserted a Google font which will be used for the numbers on the operating panel.
Nesting <svg> elements
A quick word on nesting <svg> elements might be in place here as it will be used a lot in this project. All <svg> items (such as <rect>, <circ> and <line>) added to the root element are positioned relative to this root. To visualize this, I added a rectangular shape with a width and height of 100% and a starting point (0,0). This fills up the whole page with a grey background (Home.vue: line 6).
Then I add the main element for the cooker. I could have used a <rect> again, but since we’ll have many more <svg> elements coming inside this element, it is much easier to create a new <svg> element, position it with respect to the root and all consecutive child elements will be positioned relative to this new element. This makes the math easier as you’ll see shortly. (Home.vue: lines 9-11).
With this code in place, our cooker looks like this:
Adding individual heating points
Within the black square in the middle, we add four heating points. The heating points look like a giant ‘plus’ with a circle in the middle. Although the four lines of the plus are of equal length for an individual heating point, they differ from one heating point to another to enable smaller and larger cooking pans.
So, let’s create the CookerHeatingPoint.vue component and add four of them to the black square. The following props are passed to each individual heating point:
- row: to know if this heating point is in the top or bottom ‘row’
- col: to know if the heating point is in the left or right ‘column’
- line-length: to define the size of the ‘plus’ (we’ll use this prop in the next post)
Given the row and col props and the available space for each heating point (a width of 250 and a height of 225, so there’s room for the operating panel at the bottom), it’s possible to calculate the top-left coordinates of each heating point.
As you can see in the code snippet below, I add a new <svg> element and set the top-left coordinate using the computed properties ‘x’ and ‘y’ which are based on the row and col props (CookerHeatingPoint.vue: line 2). Additionally, I add a rectangle filling the new <svg> element with a red background and some text to show where each heating point lands on the cooker. The <rect> and <text> elements are just to explain the positioning and will be removed in the next step.
The individual heating points are added to the Home component as you can see here:
This concludes the setup of the induction cooker. In the next post, the CookerHeatingPoint.vue component will be extended with actual heating points created with <circ> and <line> svg elements and a lot of computed properties. Additionally, the operating panel will be added which is computationally a lot easier. Stay tuned for the next post!