2020年9月21日月曜日

ESP32/arduino:WiFi接続時のスマホ画面とPC画面の切り替え

目的:

WiFi接続時、スマホからのアクセス画面をスマホ用にする。(スマホ対応)

背景:

WiFi接続時、スマホから接続した場合に ボタン間隔が狭い等、操作しにくい場合がある。
この為、PCからアクセスした場合とスマホからアクセスした場合で画面表示を変えて操作しやすくする。

方法:

HTML を レスポンシブデザインとして、ウィンドウ幅によりデザインを分ける。
  1. viewportを設定する。
    <head> ~ </head> 部分に、以下の様な metaタグ を記述する。
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
    
  2. ウィンドウ幅に応じて styleタグ を分ける。
    以下の様に、styleタグを 分ける。
    <style media="screen and (min-width: 769px)">
     ....  (PC用 設定)
    </style>
    <style media="screen and (max-width:768px)">
     ....  (スマホ用 設定)
     </style>
  3. 必要に応じて、HTML を修正する。 
* ウィンドウ幅で切り替えているため、PC でも ブラウザの幅を狭めれば スマホ用表示になる。

 例:

ESP32/arduino:LED調光_WEBからと外付けのボリュームからを切り替えて調光
をスマホ対応にした 時の画面 と HTML を示す。(スケッチ、レスポンス用HTML は変更なし)
PC用 画面
スマホ用画面
*スマホ時は、全体に間隔を広げ、ラジオボタンの形状を変更している。

<!DOCTYPE html><html lang='ja'>
<head> 
  <meta charset='UTF-8'>
  <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
  <style media="screen and (min-width: 769px)">
       #base          {font-size:16pt;text-align:center;width:300px;border:solid 4px #93ff93; }
       #radio_box     {font-size:12pt;float:left ;text-align:left; width:45%; }
       #disp_box      {font-size:12pt;float:right;text-align:left; width:50%; }
       #brightness    {font-size:12pt;text-align:right; }
       #val_box       {font-size:10pt;text-align:center; clear:both ;}
       #ctl_box       {text-align:center; }
       input.radio    {margin-left:8px; width:30px;}
       input.value    {margin-left:8px; width:30px;}
       input.setbutton{margin-left:8px; width:40px;}
       input.slider   {margin-left:8px; width:250px;}
       input.button   {margin:0px 15px; width:100px;}
  </style>
  <style media="screen and (max-width:768px)">
       #base             {font-size:20pt;text-align:center; width:97%; border:solid 4px #008000; }
       #radio_box        {font-size:18pt;float:left ;text-align:left; width:45%; }
       #disp_box         {font-size:18pt;float:right;text-align:left; width:50%; line-height:30pt; }
       #brightness       {font-size:18pt;text-align:right; }
       #val_box          {font-size:16pt;text-align:center; clear:both ; width:100% ; }
       #ctl_box          {text-align:center; height: 100px }
       input.radio       {margin-left:8px; width:30px; vertical-align:middle ; display:none; }
       input.radio:checked + label.lbl { background: #00FF00 ; color: #FF0080 ; }
       label.lbl         {display:block ; margin: 0px calc(90% - 120px) 10px 10% ; text-align:center ; height:50px; line-height:50px; border: 1px solid #006DD9; border-radius:8px;}
       output.brightness {margin-right:50px }
       input.value       {margin-left:8px; margin-top:30px; width:50px; height:30px ; font-size:16pt; }
       input.setbutton   {margin-left:8px; width:50px; height:30px ; font-size:16pt; }
       input.slider      {margin-top:20px; margin-bottom:20px; width:95%; height:80px }
       input.button      {margin:0px 5% ; width:30%; height:50px ; font-size:18pt; background: #008000 ; color:#ffffff ; }
  </style>
  <title>Color LED Controller</title>
</head>

<body>
<div id="base">
  <p>LED ON/OFF</p>
  <div id="radio_box">
    <form method="get"> 
      <input class='radio' type='radio' name='remote' id="rad_lo" value='local' $checked_lo onclick='disp_ctrl(this.value); submit(this.value)'>
      <label for="rad_lo" class="lbl">Local<br></label>
      <input class='radio' type='radio' name='remote' id="rad_rm" value='remote' $checked_rm onclick='disp_ctrl(this.value); submit(this.value)'>
      <label for="rad_rm" class="lbl">Remote<br></label>
    </form>
  </div>
  <div id="disp_box">
      <span> brightness value</span><br>
      <div id="brightness"><output class='brightness' id="o1">$led_brightness</output></div>
  </div>
  <div id="val_box">
    <form method="get">
      <span > LED brightness (0-255)</span> 
      <input class='value'  type='text' name='led_v' value=$led_brightness id='led_v' disabled>
      <input class='setbutton' type='submit' name='set' id='set' value='SET' disabled>
    </form> 
    <form method='get'> 
      <input class="slider" type="range" name='led_s' id='led_s' value=$led_brightness min="0" max="255" step="1" disabled
        onchange="setval(this.value);" oninput="setval(this.value)"; onmouseup="submit(this.form)": ontouchend="submit(this.form)">
    </form> 
  </div>
  <div id="ctl_box">
    <form method='get'>
      <input class='button' type='submit' name='on' id="on" value='ON' disabled >
      <input class='button' type='submit' name='off' id="off" value='OFF' disabled><br>
    </form>
  </div>
</div>


<script>
var polling = null ;

function setval(ledval){
 var xhr = new XMLHttpRequest();
        xhr.open("get", "?slid="+ledval );
        xhr.setRequestHeader('Cache-Control', 'no-cache');
        xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
        xhr.responseType = 'document' ;

        xhr.onreadystatechange = function() {
          if( (xhr.readyState == 4) && (xhr.status == 200) ) {
            document.getElementById('led_v').value = xhr.response.getElementById("output1").innerHTML;
            document.getElementById('o1').value = xhr.response.getElementById("output1").innerHTML;
          }
        }

        ntimeout = function(e) {
          xhr.abort() ;
        }
        xhr.send();
}


function getval(){
 var xhrget = new XMLHttpRequest();
        xhrget.open("get", "?pol" );
        xhrget.setRequestHeader('Cache-Control', 'no-cache');
        xhrget.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
        xhrget.responseType = 'document' ;

        xhrget.onreadystatechange = function() {
          if( (xhrget.readyState == 4) && (xhrget.status == 200) ) {
            document.getElementById('o1').value = xhrget.response.getElementById("output1").innerHTML;
          }
        }

        ntimeout = function(e) {
          xhrget.abort() ;
        }
        xhrget.send();
}

function disp_ctrl( radioid ) {
   if(radioid == 'remote') {
      document.getElementById('led_v').disabled = false;
      document.getElementById('set').disabled = false;
      document.getElementById('led_s').disabled = false;
      document.getElementById('on').disabled = false;
      document.getElementById('off').disabled = false;
      clearInterval(polling);
   } else {
      document.getElementById('led_v').disabled = true;
      document.getElementById('set').disabled = true;
      document.getElementById('led_s').disabled = true;
      document.getElementById('on').disabled = true;
      document.getElementById('off').disabled = true;
      polling = setInterval(getval,100) ;
   }

}

window.onload = function() {
    if(document.getElementById("rad_rm").checked) {
      document.getElementById('led_v').disabled = false;
      document.getElementById('set').disabled = false;
      document.getElementById('led_s').disabled = false;
      document.getElementById('on').disabled = false;
      document.getElementById('off').disabled = false;
      clearInterval(polling);
    } else if(document.getElementById("rad_lo").checked) {
      document.getElementById('led_v').disabled = true;
      document.getElementById('set').disabled = true;
      document.getElementById('led_s').disabled = true;
      document.getElementById('on').disabled = true;
      document.getElementById('off').disabled = true;
      polling = setInterval(getval,100) ;
    }
}

</script>

</body>
</html>

以下、覚書など。
  ( 行# 4 )
viewportの設定。

  ( 行# 5 ~ 17 )
styleタグに メディア属性を設定。769px 以上の幅の場合は PC画面とし、従来の設定のままとする。但し、行#10 は html 内で font-size を変更していた為、style の設定を変更。

  ( 行# 18 ~ 33 )
スマホ用の styleタグ。
styleタグに メディア属性を設定。768px 以下の幅の場合は スマホ画面とし、スマホ用の設定を記述。
全体に 間隔が広がるように margin、font-size 等の設定を変更。
ラジオボタンの形状変更の為、通常のラジオボタンの表示を消し ( display:none; )、
Label タグ を設定して、"input.radio:checked + label.lbl" (行#26) で、chkeck 時の動作 (Label の 色を変更)

  ( 行# 42 ~ 45 )
スマホ用に ラジオボタンの形状を変更する為、labelタグを追加し、表示文字列は Label で設定。

  ( 行# 50 )
表示位置をずらすため、class の設定を追加。(PC画面には影響なし)

  ( 行# 50 )
font-size を style で設定する為に削除。


0 件のコメント:

コメントを投稿