Espruino:Примеры/Графический веб-интерфейс

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Графический веб-интерфейс[1]

В этом руководстве мы сделаем интерактивную графическую репрезентацию дома. При клике на окна этого дома будут загораться соответствующие светодиоды на полосе светодиодов.

Это можно сделать, встроив в HTML-файл SVG-изображение. С SVG-элементами можно обращаться как с обычными HTML-элементами – при клике на них можно запускать JavaScript-код и менять их атрибуты (в данном случае – чтобы поменять цвет на желтый, создав эффект загоревшегося света в окне).

Нам понадобятся

Подсоединение

Код

Сначала нам надо запустить программу Inkscape и нарисовать дом. Я просто обвёл линиями фото модели домика.

Теперь нажмите на File > Save As и выберите пункт Plain SVG. Это удалит из изображения все ненужные теги Inkscape. Вот исходный код моего изображения:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<! Сделано в Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   width="400"
   height="400"
   id="svg2">
  <metadata
     id="metadata19">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs17" />
  <g
     transform="translate(0,-652.36218)"
     id="layer1">
    <path
       d="m 298.14029,720.42948 23.40489,71.44408 -7.4832,139.54296 -62.09459,78.69208 M 256.01376,857.36476 251.64895,1013.2945 81.605295,945.43453 65.389325,821.03539 M 100.3929,693.74746 56.130595,818.31663 250.69365,873.11433 299.09559,717.9604 z"
       id="path3002"
       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 85.426505,868.97264 -2.8659,-29.62898 9.23458,-10.19492 11.782055,17.52251 1.9106,28.03603 z"
       id="path3004"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 116.63302,877.5746 -2.8659,-28.03603 8.59771,-9.23914 12.41892,14.6552 1.9106,28.03602 z"
       id="path3006"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 171.40364,894.45994 -1.59217,-30.58476 11.14518,-9.55774 13.37422,17.20393 0.31843,30.26617 z"
       id="path3008"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 208.02352,905.61063 -0.9553,-30.90335 12.10049,-9.23914 14.96638,18.47829 -0.63686,29.31039 z"
       id="path3010"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 96.571685,934.28384 -3.8212,-29.94757 12.737355,3.5045 3.50277,30.58476 z"
       id="path3012"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 124.27543,943.84158 -3.18433,-29.62899 12.10048,4.46028 2.22904,30.58476 z"
       id="path3014"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 182.54882,965.82437 -1.27374,-32.17771 14.32952,4.77887 -0.63686,31.85914 z"
       id="path3016"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 213.75533,978.24943 0.31843,-32.4963 15.60326,4.77887 -0.31843,33.77067 z"
       id="path3018"
       style="fill:#ececec;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 146.08815,965.98367 -2.38825,-47.94798 23.24566,8.28337 0.79609,47.62939 z"
       id="path3022"
       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
  </g>
</svg>

Теперь удаляем метаданные, добавляем атрибуты onclick к каждому элементу path, который нужно сделать кликабельным, и меняем id на что-то более удобочитаемое (в коде ниже я их менять не стал). Наконец, помещаем это SVG-изображение внутрь HTML-файла вместе со скриптом, который будет запрашивать у Espruino веб-страницу при клике на каждое окно.

<html><body>
<script>
  function toggle(n) {
    var e = document.getElementById("path"+n);
    var lit = e.style.fill != "rgb(236, 236, 236)";
    lit = !lit; // переключаем
    e.style.fill = lit ? "#ffff30" : "#ececec";
    var xmlhttp=new XMLHttpRequest();
    xmlhttp.open("GET","set?l"+n+"="+lit,false);
    xmlhttp.send();
  }
</script>
<svg
   width="400"
   height="400">
  <g
     id="layer1"
     transform="translate(0,-652.36218)">
    <path
       id="path3002"
       style="fill:none;stroke:#000000;stroke-width:1px;"
       d="m 298.14029,720.42948 23.40489,71.44408 -7.4832,139.54296 -62.09459,78.69208 M 256.01376,857.36476 251.64895,1013.2945 81.605295,945.43453 65.389325,821.03539 M 100.3929,693.74746 56.130595,818.31663 250.69365,873.11433 299.09559,717.9604 z" />
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 85.426505,868.97264 -2.8659,-29.62898 9.23458,-10.19492 11.782055,17.52251 1.9106,28.03603 z"
       id="path1" onclick="toggle(1)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 116.63302,877.5746 -2.8659,-28.03603 8.59771,-9.23914 12.41892,14.6552 1.9106,28.03602 z"
       id="path2" onclick="toggle(2)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 171.40364,894.45994 -1.59217,-30.58476 11.14518,-9.55774 13.37422,17.20393 0.31843,30.26617 z"
       id="path3" onclick="toggle(3)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 208.02352,905.61063 -0.9553,-30.90335 12.10049,-9.23914 14.96638,18.47829 -0.63686,29.31039 z"
       id="path4" onclick="toggle(4)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 96.571685,934.28384 -3.8212,-29.94757 12.737355,3.5045 3.50277,30.58476 z"
       id="path5" onclick="toggle(5)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 124.27543,943.84158 -3.18433,-29.62899 12.10048,4.46028 2.22904,30.58476 z"
       id="path6" onclick="toggle(6)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 182.54882,965.82437 -1.27374,-32.17771 14.32952,4.77887 -0.63686,31.85914 z"
       id="path7" onclick="toggle(7)"/>
    <path
       style="fill:#ececec;stroke:#000000;stroke-width:1px;"
       d="m 213.75533,978.24943 0.31843,-32.4963 15.60326,4.77887 -0.31843,33.77067 z"
       id="path8" onclick="toggle(8)"/>
    <path
       style="fill:none;stroke:#000000;stroke-width:1px;"
       d="m 146.08815,965.98367 -2.38825,-47.94798 23.24566,8.28337 0.79609,47.62939 z"
       id="path3022"/>
  </g>
</svg>
</body></html>

Если кликнуть на второе окно, код выше запросит страницу /set?l2=true.

Сохраните этот HTML-файл на диск, а затем при помощи этого конвертера преобразуйте его в строку. Вы, конечно, можете просто сохранить этот HTML-файл на SD-карту (и в этом случае преобразование в строку не понадобится), но благодаря сохранению файла в переменную Espruino сможет использовать его, не имея никакой SD-карты вовсе.

Наконец, пишем Espruino-код, который будет обслуживать нашу веб-страницу – то есть включать и выключать светодиоды при запросе страницы /set.

var page = "<html><body>\n<script>\n  function toggle(n) {\n    var e = document.getElementById(\"path\"+n);\n    var lit = e.style.fill != \"rgb(236, 236, 236)\";\n    lit = !lit; // переключаем\n    e.style.fill = lit ? \"#ffff30\" : \"#ececec\";\n    var xmlhttp=new XMLHttpRequest();\n    xmlhttp.open(\"GET\",\"set?l\"+n+\"=\"+lit);\n    xmlhttp.send();\n  }\n</script>\n<svg\n   width=\"400\"\n   height=\"400\">\n  <g\n     id=\"layer1\"\n     transform=\"translate(0,-652.36218)\">\n    <path\n       id=\"path3002\"\n       style=\"fill:none;stroke:#000000;stroke-width:1px;\"\n       d=\"m 298.14029,720.42948 23.40489,71.44408 -7.4832,139.54296 -62.09459,78.69208 M 256.01376,857.36476 251.64895,1013.2945 81.605295,945.43453 65.389325,821.03539 M 100.3929,693.74746 56.130595,818.31663 250.69365,873.11433 299.09559,717.9604 z\" />\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 85.426505,868.97264 -2.8659,-29.62898 9.23458,-10.19492 11.782055,17.52251 1.9106,28.03603 z\"\n       id=\"path1\" onclick=\"toggle(1)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 116.63302,877.5746 -2.8659,-28.03603 8.59771,-9.23914 12.41892,14.6552 1.9106,28.03602 z\"\n       id=\"path2\" onclick=\"toggle(2)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 171.40364,894.45994 -1.59217,-30.58476 11.14518,-9.55774 13.37422,17.20393 0.31843,30.26617 z\"\n       id=\"path3\" onclick=\"toggle(3)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 208.02352,905.61063 -0.9553,-30.90335 12.10049,-9.23914 14.96638,18.47829 -0.63686,29.31039 z\"\n       id=\"path4\" onclick=\"toggle(4)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 96.571685,934.28384 -3.8212,-29.94757 12.737355,3.5045 3.50277,30.58476 z\"\n       id=\"path5\" onclick=\"toggle(5)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 124.27543,943.84158 -3.18433,-29.62899 12.10048,4.46028 2.22904,30.58476 z\"\n       id=\"path6\" onclick=\"toggle(6)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 182.54882,965.82437 -1.27374,-32.17771 14.32952,4.77887 -0.63686,31.85914 z\"\n       id=\"path7\" onclick=\"toggle(7)\"/>\n    <path\n       style=\"fill:#ececec;stroke:#000000;stroke-width:1px;\"\n       d=\"m 213.75533,978.24943 0.31843,-32.4963 15.60326,4.77887 -0.31843,33.77067 z\"\n       id=\"path8\" onclick=\"toggle(8)\"/>\n    <path\n       style=\"fill:none;stroke:#000000;stroke-width:1px;\"\n       d=\"m 146.08815,965.98367 -2.38825,-47.94798 23.24566,8.28337 0.79609,47.62939 z\"\n       id=\"path3022\"/>\n  </g>\n</svg></body></html>\n";

// Светодиоды расположены не в правильном порядке,
// и здесь мы задаём правильный порядок:
var map = [undefined,7,6,5,4,0,1,2,3];

// 8 светодиодов – по одному для каждого окна:
var rgb = new Uint8Array(3*8);
// Настраиваем SPI для коммуникации со светодиодами:
SPI2.setup({baud:3200000, mosi:B15});

// Эта функция передаёт данные светодиодам:
function setLights() {
  SPI2.send4bit(rgb, 0b0001, 0b0011);
}

function onPageRequest(req, res) {
  var a = url.parse(req.url, true);
  res.writeHead(200, {'Content-Type': 'text/html'});
  // Если запрошена страница «/set»...
  if (a.pathname == "/set" && a.query) {
    for (var l in a.query) {
      if (l.length==2 && l[0]=="l") {
        var n = map[parseInt(l[1],16)];
        var v = JSON.parse(a.query[l]);
        rgb[n*3+0] = v ? (32+128*Math.random()) : 0;
        rgb[n*3+1] = v ? (32+128*Math.random()) : 0;
        rgb[n*3+2] = v ? (32+128*Math.random()) : 0;
        setLights();
      }
    }
    res.end();
  } else {
    // В противном случае просто отправляем веб-страницу:
    res.end(page);
  }
}

// Теперь просто инициализируем WiFi и наш сервер:
var wlan;

function onInit() {
  wlan = require("CC3000").connect();
  wlan.connect( "AccessPointName", "WPA2key", function (s) { 
    setLights();
    if (s=="dhcp") {
      console.log("Мой IP-адрес - это "+wlan.getIP().ip);
      require("http").createServer(onPageRequest).listen(80);
    }
  });
}

onInit();

Вставьте этот код в правую часть Web IDE (не забудьте поменять WiFi-настройки, т.е. вписать пароль и название своей WiFi-сети). Затем кликните на кнопку отправки кода в центре Web IDE.

На инициализацию CC3000 может понадобиться некоторое время (примерно минута-две). После подключения Espruino напечатает свой IP-адрес. Теперь скопируйте его, вставьте в адресную строку своего веб-браузера и кликните  ↵ Enter .

После этого в браузере должна открыться веб-страница с изображением домика. Клики по окнам этого домика будут зажигать соответствующие светодиоды в ленте светодиодов.

Файл:Graphical Web Interface chrome

См.также

Внешние ссылки