In response to this facebook post. I created a simple bus seat reservation user interface using Vue.js and SVG. I started by preparing an SVG image of the bus seat and then render the SVG elements using Javascript (VueJS). You can use a raster image (sprite) for this but I prefer to use vector graphics (SVG) because it allows me to control the stroke and background color programmatically.

The bus seat vector image looks like this

Bus Seat

The SVG code for the bus seat is shown below

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> 
<title>Bus Seat</title> 
<path class="cls-ra" d="M36,17.3H80.4a8.88,8.88,0,0,1,6.72-7.25A5.77,5.77,0,0,0,81.57,6H36a5.72,5.72,0,0,0-5.76,5.66A5.71,5.71,0,0,0,36,17.3Z"/> 
<path class="cls-ra" d="M80.29,82.79H36A5.66,5.66,0,1,0,36,94.1H81.47a6.13,6.13,0,0,0,5.44-3.41A8.77,8.77,0,0,1,80.29,82.79Z"/> 
<path class="cls-ra" d="M80.08,79.7V20.5H35.92A8.85,8.85,0,0,1,27.17,13h-18a4,4,0,0,0-4.06,4V82.79a4,4,0,0,0,4.06,3.95H27.28a8.65,8.65,0,0,1,8.75-7Z"/> 
<path class="cls-ra" d="M89.15,12.93a5.71,5.71,0,0,0-5.76,5.65V82.15a5.76,5.76,0,0,0,11.52,0V18.58A5.71,5.71,0,0,0,89.15,12.93Z"/> 
<path class="cls-ra" d="M90.21,9.94a8.93,8.93,0,0,0-8.74-7H36a8.94,8.94,0,0,0-8.75,6.93H9.15A7.22,7.22,0,0,0,2,17V82.79a7.06,7.06,0,0,0,7.15,7h18a8.85,8.85,0,0,0,8.75,7.26H81.47A8.91,8.91,0,0,0,90,90.9a8.81,8.81,0,0,0,8-8.75V18.58A8.84,8.84,0,0,0,90.21,9.94ZM36,6H81.57a5.77,5.77,0,0,1,5.55,4.06A8.88,8.88,0,0,0,80.4,17.3H36a5.71,5.71,0,0,1-5.76-5.65A5.72,5.72,0,0,1,36,6ZM27.28,86.74H9.15a4,4,0,0,1-4.06-3.95V17a4,4,0,0,1,4.06-4h18a8.85,8.85,0,0,0,8.75,7.47H80.08V79.7H36A8.65,8.65,0,0,0,27.28,86.74ZM81.47,94.1H36a5.66,5.66,0,1,1,0-11.31H80.29a8.77,8.77,0,0,0,6.62,7.9A6.13,6.13,0,0,1,81.47,94.1ZM94.91,82.15a5.76,5.76,0,0,1-11.52,0V18.58a5.76,5.76,0,0,1,11.52,0Z"/> 
</svg>

Interacting with SVG elements using Vue.js

Let us analyze the index.html for better understand how it works

34<body>
35<div id="root">
36    <div class="container">
37        <div class="row">
38            <div class="col-8 py-5">
39                <div>
40                    <table class="mx-auto">
41                        <tr v-for="idxr, r in rows">
42                            <td v-for="idxc, c in cols" class="pl-2" style="width: 50px">
43                                <svg @click="onSeatSelected(idxr, idxc)"
44                                     v-if="!isAisle(idxr, idxc)"
45                                     id="Layer_1" data-name="Layer 1"
46                                     xmlns="http://www.w3.org/2000/svg"
47                                     viewBox="0 0 100 100">
48                                    <path :class="classifier(idxr, idxc)" d="M36,17.3H80.4a8.88,8.88,0,0,1,6.72-7.25A5.77,5.77,0,0,0,81.57,6H36a5.72,5.72,0,0,0-5.76,5.66A5.71,5.71,0,0,0,36,17.3Z"/>
49                                    <path :class="classifier(idxr, idxc)" d="M80.29,82.79H36A5.66,5.66,0,1,0,36,94.1H81.47a6.13,6.13,0,0,0,5.44-3.41A8.77,8.77,0,0,1,80.29,82.79Z"/>
50                                    <path :class="classifier(idxr, idxc)" d="M80.08,79.7V20.5H35.92A8.85,8.85,0,0,1,27.17,13h-18a4,4,0,0,0-4.06,4V82.79a4,4,0,0,0,4.06,3.95H27.28a8.65,8.65,0,0,1,8.75-7Z"/>
51                                    <path :class="classifier(idxr, idxc)" d="M89.15,12.93a5.71,5.71,0,0,0-5.76,5.65V82.15a5.76,5.76,0,0,0,11.52,0V18.58A5.71,5.71,0,0,0,89.15,12.93Z"/>
52                                    <path :class="classifier(idxr, idxc)" d="M90.21,9.94a8.93,8.93,0,0,0-8.74-7H36a8.94,8.94,0,0,0-8.75,6.93H9.15A7.22,7.22,0,0,0,2,17V82.79a7.06,7.06,0,0,0,7.15,7h18a8.85,8.85,0,0,0,8.75,7.26H81.47A8.91,8.91,0,0,0,90,90.9a8.81,8.81,0,0,0,8-8.75V18.58A8.84,8.84,0,0,0,90.21,9.94ZM36,6H81.57a5.77,5.77,0,0,1,5.55,4.06A8.88,8.88,0,0,0,80.4,17.3H36a5.71,5.71,0,0,1-5.76-5.65A5.72,5.72,0,0,1,36,6ZM27.28,86.74H9.15a4,4,0,0,1-4.06-3.95V17a4,4,0,0,1,4.06-4h18a8.85,8.85,0,0,0,8.75,7.47H80.08V79.7H36A8.65,8.65,0,0,0,27.28,86.74ZM81.47,94.1H36a5.66,5.66,0,1,1,0-11.31H80.29a8.77,8.77,0,0,0,6.62,7.9A6.13,6.13,0,0,1,81.47,94.1ZM94.91,82.15a5.76,5.76,0,0,1-11.52,0V18.58a5.76,5.76,0,0,1,11.52,0Z"/>
53                                </svg>
54                            </td>
55                        </tr>
56                    </table>
57                </div>
58            </div>
59            <div class="col-4 pt-3">
60                <div class="card" v-show="selectedSeat != null" style="display: none">
61                    <div class="card-header">
62                        Properties
63                    </div>

In line 43, The code @click=“onSeatSelected(idxr, idxc) binds the SVG to a mouse-click event handler.

From line 48 to 52, The code :class=“classifier(idxr, idxc)" handles the binding that controls the background and line color.

109<script type="text/javascript">
110let app = new Vue({
111  el: "#root",
112  data: {
113    errors: [],
114    o: [],
115    selectedSeat: null,
116    rows: 5,
117    cols: 12,
118    seats: [],
119  },
120  computed: {
121  },
122  methods:
123      {
124        getSeat(r, c) {
125          for(let i = 0; i < this.seats.length; ++i) {
126            if(this.seats[i].position.r == r && this.seats[i].position.c == c) {
127              return this.seats[i];
128            }
129          }
130          return null;
131        },
132        generateSeats() {
133          for(let y = 1; y <= this.rows; ++y){
134            for(let x = 1; x <= this.cols; ++x) {
135              if(!this.isAisle(y, x)) {
136                this.seats.push({
137                  position: {r: y, c: x},
138                  status: "RA",
139                });
140              }
141            }
142          }
143        },
144        classifier(r, c){
145          let seat = this.getSeat(r,c);
146          if(seat != null){
147            if(this.selectedSeat != seat) {
148              switch(seat.status) {
149                case 'RA':
150                  return 'cls-ra';
151                case 'RB':
152                  return 'cls-rb';
153                case 'FA':
154                  return 'cls-fa';
155                case 'FB':
156                  return 'cls-fb';
157                case 'MA':
158                  return 'cls-ma';
159                case 'MB':
160                  return 'cls-mb';
161                default:
162                  return 'cls-ra';
163              }
164            } else {
165              return 'cls-selected';
166            }
167          }
168        },
169        isAisle(r, c) {
170          if(r == 3){
171            if(c >= 1 && c <= 11) {
172              return true;
173            }
174          }
175          return false;
176        },
177        onSeatSelected(r,c) {
178          if(this.selectedSeat == this.getSeat(r, c)) {
179            this.selectedSeat = null;
180          } else {
181            this.selectedSeat = this.getSeat(r, c);
182          }
183        },
184        seatStatus(status){
185          if(this.selectedSeat != null) {
186            if(this.selectedSeat.status == status)
187              return 'active';
188          }
189          return '';
190        },
191        changeSeatStatus(status) {
192          if(this.selectedSeat != null) {
193            for(let i = 0; i < this.seats.length; ++i) {
194              if(this.seats[i].position.r == this.selectedSeat.position.r && this.seats[i].position.c == this.selectedSeat.position.c) {
195                this.seats[i].status = status;
196                this.selectedSeat = null;
197                break;
198              }
199            }
200          }
201        },
202      },
203  beforeMount() {
204  },
205  mounted() {
206    this.generateSeats();
207  }
208});
209</script>

The classifier method implementation from line 144 to 168 handles the class setting of the seat image.

Demo

https://johnpili.com/demo/bus-seat-reservation-ui-concept-vuejs/

Video

Source Code

Get the source code here
https://github.com/johnpili/bus-seat-reservation-ui-concept-vuejs

Conclusion

Using Javascript framework like Vue.js makes it easy for developers to create an interactive HTML user interfaces. The next thing to do now is to integrate this UI to PHP, Java, Go, or Python to save the information to the database.