Zaznaczanie komórek, wierszy i kolumn w tabeli HTML
HTML potrafi coraz więcej
Jeszcze nie tak dawno arkusze kalkulacyjne były całkowicie poza zasięgiem aplikacji internetowych. Postęp jest jednak nieunikniony, a same strony stają się coraz bardziej skomplikowane. Tym razem za cel postawiłem sobie stworzenie tabeli, której komórki będą mogły być zaznaczane przez użytkownika myszką. To otwiera szereg zastosowań, w szczególności związanych z obliczeniami i analizą danych - coś na kształt arkusza kalkulacyjnego. Żeby nie przedłużać, przejdźmy do przykładu.
Tabela w działaniu
Użytkownik ma możliwość zaznaczania dowolnych komórek (prostokątne obszary) i realizowania dla nich operacji sumy. Żebym nie musiał tłumaczyć, zapraszam do przetestowania.
11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 |
12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 |
13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 |
14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 |
15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 |
16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 |
17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 |
18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 |
Suma wartości w zaznaczonych komórkach:
Pełny listing HTML i JavaScript
Uznałem, że całe rozwiązanie zostanie zrealizowane w HTML i JavaScript, bez udziału bibliotek zewnętrznych. Zdarza się, czego nie popieram, że dla kilku lub kilkunastu linijek kodu dołączane są całe bilioteki, zajmujące nieraz kilkadziesiąt kilobajtów. Realizacja tego samego zadania w jQuery byłaby pewnie prostsza, ale czasem warto się wysilić i oszczędzić użytkownikom niepotrzebnego transeru.
<head>
<title>Zaznaczanie komórek w tabeli HTML</title>
</head>
<body>
<style>
.SimpleTable{border-collapse:collapse;}
.SimpleTable, .SimpleTable td{border: 1px solid black;padding:2px;}
.White{background:#FFFFFF}
.Selected{background:#A0FFA0}
</style>
<table id="MyTable" class="SimpleTable">
<tr><td>11</td><td>21</td><td>31</td><td>41</td><td>51</td><td>61</td><td>71</td><td>81</td></tr>
<tr><td>12</td><td>22</td><td>32</td><td>42</td><td>52</td><td>62</td><td>72</td><td>82</td></tr>
<tr><td>13</td><td>23</td><td>33</td><td>43</td><td>53</td><td>63</td><td>73</td><td>83</td></tr>
<tr><td>14</td><td>24</td><td>34</td><td>44</td><td>54</td><td>64</td><td>74</td><td>84</td></tr>
<tr><td>15</td><td>25</td><td>35</td><td>45</td><td>55</td><td>65</td><td>75</td><td>85</td></tr>
<tr><td>16</td><td>26</td><td>36</td><td>46</td><td>56</td><td>66</td><td>76</td><td>86</td></tr>
<tr><td>17</td><td>27</td><td>37</td><td>47</td><td>57</td><td>67</td><td>77</td><td>87</td></tr>
<tr><td>18</td><td>28</td><td>38</td><td>48</td><td>58</td><td>68</td><td>78</td><td>88</td></tr>
</table>
<p>Suma wartości w zaznaczonych komórkach: <b><span id="Result"/></b></p>
<script>
function Mouse(){
this.IsDown = false;
}
Mouse.prototype.OnDown = function(cell,mouseEventArgs){
this.IsDown = true;
this.UnselectAllCells();
this.SelectedRow = cell.Row;
this.SelectedColumn = cell.Column;
this.SelectCell(cell);
mouseEventArgs.preventDefault();
}
Mouse.prototype.AttachTableCells = function(tableID){
this.Table = document.getElementById(tableID);
for (var r=0; r<this.Table.rows.length; r++)
for (var c=0; c<this.Table.rows[r].cells.length; c++){
var cell = this.Table.rows[r].cells[c];
cell.Row = r;
cell.Column = c;
cell.addEventListener("mouseover", this.OnMoveOver.bind(this, cell), false);
cell.addEventListener("mousedown", this.OnDown.bind(this, cell), false);
}
window.addEventListener("mouseup", this.OnUp.bind(this), false);
}
Mouse.prototype.OnMoveOver = function(cell,mouseEventArgs){
if (this.IsDown){
var minRow = Math.min(cell.Row, this.SelectedRow);
var maxRow = Math.max(cell.Row, this.SelectedRow);
var minCol = Math.min(cell.Column, this.SelectedColumn);
var maxCol = Math.max(cell.Column, this.SelectedColumn);
for (var r=0; r<this.Table.rows.length; r++){
for (var c=0; c<this.Table.rows[r].cells.length; c++){
var cell = this.Table.rows[r].cells[c];
if (cell.Row>=minRow && cell.Row<=maxRow &&
cell.Column>=minCol && cell.Column<=maxCol)
this.SelectCell(cell);
else
this.UnselectCell(cell);
}
}
}
}
Mouse.prototype.UnselectCell = function(cell){
cell.className = "White";
cell.IsSelected = false;
}
Mouse.prototype.SelectCell = function(cell){
cell.className = "Selected";
cell.IsSelected = true;
}
Mouse.prototype.UnselectAllCells = function(){
for (var r=0; r<this.Table.rows.length; r++)
for (var c=0; c<this.Table.rows[r].cells.length; c++)
this.UnselectCell(this.Table.rows[r].cells[c]);
}
Mouse.prototype.OnUp = function(mouseEventArgs){
this.IsDown = false;
var result = document.getElementById("Result");
var sum = 0;
for (var r=0; r<this.Table.rows.length; r++)
for (var c=0; c<this.Table.rows[r].cells.length; c++)
if (this.Table.rows[r].cells[c].IsSelected)
sum += parseInt(this.Table.rows[r].cells[c].innerHTML);
result.innerHTML = sum;
}
window.addEventListener("load", function(){
var mouse = new Mouse();
mouse.AttachTableCells("MyTable");
}, false);
</script>
</body>
</html>
Proces inicjalizacyjny
Cała zabawa zaczyna się po załadowaniu strony (zdarzenie load obiektu window). To tam tworzony jest obiekt Mouse, w którym umieszczone są wszystkie potrzebne metody. Warto zwrócić uwagę na to, że nie ma żadnej zmiennej globalnej - dzięki temu może jednocześnie istnieć kilka takich samych obiektów, a każdy z nich pracuje niezależnie. Ten obiekt Mouse posiada metodę AttachTableCells, która "udoskonala" tabelę. Jednym z tych ulepszeń jest numeracja wierszy i kolumn - takie podejście znacznie upraszcza przyszłą pracę, bo z łatwością możemy określić, z którą komórką mamy do czynienia i gdzie się ona znajduje w strukturze tabeli. Drugim ulepszeniem jest podpięcie zdarzeń:
- mouseover - Zdarzenie wywoływane jest w momencie najechania myszą na komórkę tabeli, obsługiwane w metodzie OnMoveOver.
- mousedown - Zdarzenie wciśnięcia przycisku, obsługiwane w metodzie OnDown.
Oprócz tego nasłuchiwane jest zdarzenie zwolnienia przycisku myszy mouseup i obsługiwane w metodzie OnUp. Dzieje się to na poziomie całego okna - to na wypadek, gdybyśmy uciekli kursorem poza obszar tabeli.
Funkcje i zmienne pomocnicze
Zwrócę jeszcze uwagę na kilka detali. Po pierwsze, podczas tworzenia obiektu (wiem, to nie obiekt, ale wygodniej mi go tak traktować) ustawiana jest zmienna IsDown. Określa ona, czy przycisk myszy jest wciśnięty, czy nie. Po drugie, aby nie mieszać kodu zaznaczania i odznaczania komórek, napisałem sobie trzy metody:
- UnselectCell - Odznacza komórkę tabeli, jako parametr przyjmuje obiekt przetwarzanej komórki.
- SelectCell - Zaznacza komórkę tabeli, jako parametr przyjmuje obiekt przetwarzanej komórki.
- UnselectAllCells - Odznacza wszystkie komórki obsługiwanej tabeli.
Cała reszta to już logika właściwa. Przyjrzyjmy się jej dokładniej.
Wciśnij, przeciągnij i zaznacz komórki, zwolnij
Kategoria:HTMLJavaScript
Komentarze:
Kiedyś widziałem skrypt, gdzie podświetlały się wszystkie komórki w wierszu i kolumnie do komórki nad którą była myszka, ale teraz nie mogę tego znaleźć. Równie dobrze mogłyby się podświetlać wszystkie komórki w całym wierszu i całej kolumnie.