無精・短気・傲慢

perlの事 いろいろ

位置情報を取得(Geolocation API)

 JavaScriptで位置情報を取得

Webブラウザのgeolocationオブジェクトを使うと、JavaScriptで現在位置(緯度/経度/高度と移動中なら速度/方向)を取得することができます。サンプルを作ってみました。最初に位置情報を取得する許可を求められます。

 geolocation

geolocationは、Webブラウザ上のアプリケーション(JavaScript)で位置情報を利用するための仕組みです。navigatorが持つオブジェクトの形で実装され、現在ではパソコン用も含めほとんどのWebブラウザで利用できるようになっています。

 位置情報を取得するgetCurrentPosition()

getCurrentPosition()を呼び出すと、すぐに制御が返されます(次の文が実行される)。そして、位置情報の取得に成功すると、引数に渡した関数にPositionオブジェクトが渡されます。

Positionオブジェクトには、取得した位置情報と取得時間が格納されているので、その情報を使って処理を行うわけです。

navigator.geolocation.getCurrentPosition(success[, error[, [options]])

引数

  • success
    • コールバック関数で、GeolocationPosition オブジェクトを唯一の入力引数として受け取るものです。
  • error
    • 任意のコールバック関数で、GeolocationPositionError オブジェクトを唯一の入力引数として受け取るものです。
  • option
    • 任意の PositionOptions オブジェクトです。

 位置情報を取得し続けるwatchPosition()

watchPosition()は、getCurrentPosition()と同じ引数で呼び出しますが、呼び出した後は位置情報の更新があった時など継続的に位置情報が更新され、引数に渡した関数に通知されます。

 -

 SOURCE

<html lang="ja">
<head>
<meta charset=utf-8>
<script>
//ユーザーの現在の位置情報を取得
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);

/***** ユーザーの現在の位置情報を取得 *****/
function successCallback(position) {
   var gl_text = "緯度:" + position.coords.latitude + "<br>";
       gl_text += "経度:" + position.coords.longitude + "<br>";
       gl_text += "高度:" + position.coords.altitude + "<br>";
       gl_text += "緯度・経度の誤差:" + position.coords.accuracy + "<br>";
       gl_text += "高度の誤差:" + position.coords.altitudeAccuracy + "<br>";
       gl_text += "方角:" + position.coords.heading + "<br>";
       gl_text += "速度:" + position.coords.speed + "<br>";
   document.getElementById("show_result").innerHTML = gl_text;
}

/***** 位置情報が取得できない場合 *****/
function errorCallback(error) {
   var err_msg = "";
   switch(error.code)
   {
       case 1:
           err_msg = "位置情報の利用が許可されていません";
           break;
       case 2:
           err_msg = "デバイスの位置が判定できません";
           break;
       case 3:
           err_msg = "タイムアウトしました";
           break;
   }
   document.getElementById("show_result").innerHTML = err_msg;
   //デバッグ用→ document.getElementById("show_result").innerHTML = 
error.message;
}
</script>
<title>Geolocation API サンプル</title>
</head>
<body>
<p>あなたの現在位置</p>
<div id="show_result"></div>
</body> 
</html>

WSLのvimでクリップボードを使う

windowsではXserverが無い為?にWSLのvimではクリップボードを共有する事が出来ません。Xserverを導入することでクリップボードを共有できる事を『WSL上のvimでクリップボードを共有する方法』で教えてもらいました。

   windowsにXserverを導入する

  1. ここ(VcXsrv Windows X Server)からVcXsrvをダウンロードしインストールする。
  2. インストールした「XLaunch」を起動する。(全てデフォルトでOK)
  3. .profileにexport DISPLAY=localhost:0.0を追加
  4. .vimrcにset clipboard=unnamedplusを追加

これでvimでyankした文字列をクリップボードに保存できwindowsアプリにてペースト(Ctrl+v)出来ます。また、windowsのアプリでコピー(Cirl+C)した文字列をvimにてペースト(pとか)できます。

   256倍便利

windowsアプリとクリップボードを共有出来るとやっぱり便利。てか、クリップボードを共有出来ないと不便すぎるでしょう。あっちこっちコピペは良くやりますから・・・

また、Xserverを導入する事で目玉や丸い時計を起動出来ます。

  • Xアプリインストール
    • sudo apt install x11-apps

カレンダー表示

 SOURCE

 menu.pm

sub panel_content{
    my $s = shift;
    my $m = $s->app->model;
    my $text = <<END_SCRIPT
   <pre>
   @{[`date +"%a %b %d %Y"`]}
   @{[$m->make_cal($m->today())]}
   </pre>
END_SCRIPT
}

 model.pm

sub make_days{
    my ($s,$y,$m,$d,$dumy) = @_;
    my @days = map{[$y,$m,$_]} (1 .. $s->end_day($y*100+$m));
    my $w = $s->getwday($y,$m,$s->end_day($y*100+$m));
    my ($yy,$mm,$dd) = (0,0,0);
    for ($w+1 .. 6){
        ($yy,$mm,$dd) = $s->adddate($y,$m,$s->end_day($y*100+$m),$dd+1);
        push(@days,[$yy,$mm,$dd]);
    }
    $d = 1;
    $w = $s->getwday($y,$m,$d);
    while($w--){
        ($y,$m,$d) = $s->adddate($y,$m,$d,-1);
        unshift(@days,[$y,$m,$d]);
    }
    return @days;
}
sub make_cal{
    my ($s,$y,$m,$d,$dumy) = @_;
    my $cal = '';
    $cal .= "<table border=0 width=50%>";
    $cal .= $s->tag("tr",$s->tag("td",qw(日 月 火 水 木 金 土)));
    my $i = 0;
    $cal .= join ("",map {$s->day_class($i++,$y,$m,$_) } $s->make_days($y,$m,$d));
    $cal .= "</table>";
    return $cal;
}
sub day_class{
    my ($s,$i,$y,$m,$d) = @_;
    my $text ='';
    my $class = $s->holiday(-date=>$d->[0]*10000+$d->[1]*100+$d->[2]);
    if($class ne ''){
        $class = 'hol';
    }else{
        $class = qw(Sun Mon Tue Wed Thu Fri Sat)[$i % 7];
    }
    $class .= ' today' if ($s->isToday($d->[0],$d->[1],$d->[2]));
    $class = 'Non' if($m != $d->[1]);
    $text .= '<tr>' if($i % 7 == 0);
    $text .= qq{<td class="$class">$d->[2]</td>};
    $text .= '</tr>' if($i % 7 == 6);
    return $text;
}
#------------------------------------------------------------------
sub holiday{
#------------------------------------------------------------------

=head2 祝日計算 [holiday]

=over 2

祝日なら祝日の名前を返す

=item $name = holiday(-date=>YYYYMMDD)

 西暦年月日より祝日の判断を行う

=back

=cut

    my $s = shift;
    my %x = (
        1 => {1 => "元旦",},
        2 => {11 => "建国記念日",
            23 => "天皇誕生日"},
        4 => {29 => "昭和の日",},
        5 => {3 => "憲法記念日",
            4 => "みどりの日",
            5 => "こどもの日",},
        8 => {11 => "山の日",},
        11 => {3 => "文化の日",
            23 => "勤労感謝の日",},
        @_);
    my($y,$m,$d) = $s->ymd_split($x{-date});
    $m = $m+0;
    $d = $d+0;
    $x{1}{$s->get_w_day($y,1,2,1)} = "成人の日";
    $x{7}{$s->get_w_day($y,7,3,1)} = "海の日";
    $x{9}{$s->get_w_day($y,9,3,1)} = "敬老の日";
    $x{10}{$s->get_w_day($y,10,2,1)} = "スポーツの日";
    my ($vernal,$autumnal)=$s->get_equinox_day($y);
    $x{3}{$vernal} = "春分の日";
    $x{9}{$autumnal} = "秋分の日";
    my($yy,$mm,$dd) = $s->adddate($y,$m,$d,-1);
    if($s->getwday($yy,$mm,$dd) == 0 and defined $x{$mm}{$dd}){
        $x{$m}{$d} = "振替の休日";
    }
    if($s->getwday($yy,5,5) <= 2){
        $x{5}{6} = "国民の休日";
    }
    return $x{$m}{$d};
}
#------------------------------------------------------------------
sub get_w_day{
#------------------------------------------------------------------

=head2 $y年$m月第$n曜日の日を返す [get_w_day]

=over 2

=item $d = get_w_day($y,$m,$n,$wday)

 $y: 年
 $m: 月
 $n: 第何曜日かを指定[1&#12316;5]
 $n: 曜日 [0&#12316;6] (0:日曜 1:月曜 2:火曜 3:水曜 4:木曜 5:金曜 6:土曜)
 $d: 対象の日付を返す

=back

=cut

   my $s = shift;
   my ($y,$m,$n,$wday) = @_;
   my $st_wday = $s->getwday($y,$m,1);
   my $end_day = $s->end_day($y*100+$m);
   my $d;
   if($wday >= $st_wday){$n--;}
   $d = 7 * $n + $wday + 1 - $st_wday;
   if($d > $end_day or $d <= 0){$d = '';}
   return $d;
}
#------------------------------------------------------------------
sub get_equinox_day{
#------------------------------------------------------------------

=head2 春分の日秋分の日を求める [get_equinox_day]

=over 2

 指定した年の春分日・秋分日をもとめる
(1980年から2099年に適用)
 ($vernal,$autumnal)=get_equinox_day($y);

=back

=cut

    my $s = shift;
    my ($yy)=@_;
    my ($vernal) = int(20.8431+0.242194*($yy-1980)-int(($yy-1980)/4));
    my ($autumnal)=int(23.2488+0.242194*($yy-1980)-int(($yy-1980)/4));

    return ($vernal,$autumnal);
}
#------------------------------------------------------------------
sub end_day{
#------------------------------------------------------------------

=head2 末日算出 [end_day]

=over 2

入力年月から末日を計算する。

=item $day = end_day($DATE)

 $DATE: 日付 YYYYMM or YYYY/MM
 $day: $DATEの末日(28or29or30or31)

=back

=cut
   my $s = shift;
   my $yymm = shift;
   my @end = (31,28,31,30,31,30,31,31,30,31,30,31);
   $yymm =~ /^(\d{1,4})\D*(\d{1,2})$/;
   my ($y,$m) = ($1,$2);
   if($2 != 2){return $end[$m - 1];}
   if($y % 400 == 0 or $y % 100 != 0 and $y %4 == 0){
       return 29;
   }else{  return $end[$m - 1];}
}

 demo.css

.Sun{color:RED;}
.Sat{color:BLUE;}
.hol{color:RED;}
.today{
    box-shadow:  3px 3px 7px 1px rgba(0,0,0,0.4);
    transform: scale(1.05,1.05);
}
.Non{color:GRAY;}

ツェラーの公式(Zeller's congruence):曜日計算

ツェラーの公式(ツェラーのこうしき、英: Zeller's congruence)とは西暦(グレゴリオ暦またはユリウス暦)の年・月・日から、その日が何曜日であるかを算出する公式である。クリスティアン・ツェラー (Christian Zeller) が考案した。ユリウス通日を求め、そこから曜日を求める計算と本質は同じである。ウィキペディア(Wikipedia)より

 ツェラーの公式の導出

ツェラーの公式はフェアフィールド (Fairfield) の公式の変形である。

 フェアフィールドの公式

1年1月1日(0年13月1日) ~ y 年 m 月 d の日数を求める。ただし、m = 1, 2 の場合は、y = y - 1, m = m + 12とし、1年を、3月1日 ~ 14月28日(閏年は29日)と再定義する。

1年1月1日(0年13月1日)を含めた、y 年 m 月 d 日迄の日数は以下の通り。

 1年1月1日(0年13月1日) ~ 1年2月28日(0年14月28日)

  ・・・  31 + 28 (日)

 1年3月1日 ~ ( y - 1 ) 年14月末日(この時点では閏年は考慮しない)

  ・・・  365 ( y - 1 ) (日)

 1年1月1日(0年13月1日) ~ ( y - 1 ) 年14月末日の閏年の回数

  ・・・  [ ( 1 + ( y - 1 ) ) / 4 ) ] - [ ( 1 + ( y - 1 ) ) / 100 ) ] + [ ( 1 + ( y - 1 ) ) / 400 ) ]

      = [ y / 4 ] - [ y / 100 ] + [ y / 400 ] (日)

 y年3月1日 ~ y 年 ( m - 1 ) 月末日

  ・・・  [ 306 ( m + 1 ) / 10 ] - 122 (日) (以下表を参照)

 y 年 m 月1日 ~ y 年 m 月 d 日

  ・・・  d (日)

 3月1日 ~ ( m - 1 )月末日迄の日数と、[ 306 ( m + 1 ) / 10 ] - 122 の値は完全に一致している。

当月(m) 前月(m-1) 日数(Σ) [306(m+1)/10]-122
3   0 0
4 3 31 31
5 4 61 61
6 5 92 92
7 6 122 122
8 7 153 153
9 8 184 184
10 9 214 214
11 10 245 245
12 11 275 275
13 12 306 306
14 13 337 337

従って、1年1月1日 ~ y 年 m 月 d 日の日数は、上記全てを合算した、

  31 + 28 + 365 ( y - 1 ) + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 306 ( m + 1 ) / 10 ] - 122 + d

曜日は7日間で循環しているので、上記【※】式の 7 の剰余を求めることで、曜日が判明する。即ち、

  h = ( 365y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 306 ( m + 1 ) / 10 ] d - 428 ) mod 7 ・・・【I】

 ツェラーの公式への変形

【I】式が 7 の剰余である事を利用すると、以下の通り変形できる。

  h = ( 7 ( 52 y - 62) + y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 153 ( m + 1 ) / 5 ] + 6 + d ) mod 7

   = (          y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 153 ( m + 1 ) / 5 ] + 6 + d ) mod 7

ここで、[ ] (ガウス記号)の性質( [ a ] + b = [ a + b ] , ただし b は整数)を利用すると、

  h = ( y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 153 ( m + 1 ) / 5 + 6 ] + d ) mod 7

   = ( y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ ( 153 m + 153 + 30 ) / 5 ] + d ) mod 7

   = ( y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ ( 153 m + 183 ) / 5 ] + d ) mod 7

   = ( y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ ( 35 ( 4 m + 5 ) + 13 m + 8 ) / 5 ] + d ) mod 7

   = ( y + [ y / 4 ] - [ y / 100 ] + [ y / 400 ] + [ 7 ( 4 m + 5 ) + ( 13 m + 8 ) / 5 ] + d ) mod 7

さらに、h が 7 の剰余であることを利用して、 ・ ・ ・

 実装してみる

sub getwday{
   my $s = shift;
   my($year, $mon, $mday) = @_;

   if ($mon == 1 or $mon == 2) {
       $year--;
       $mon += 12;
   }
   return int($year + int($year / 4) - int($year / 100) + int($year / 400)
       + int((13 * $mon + 8) / 5) + $mday) % 7;
}

春分の日・秋分の日

春分の日・秋分の日は前年に決まる

春分の日」及び「秋分の日」については、国立天文台が、毎年2月に翌年の「春分の日」、「秋分の日」を官報で公表しています。

  春分の日・秋分の日を求める

公転時の誤差によって日にちの確定ができない春分の日ですが、何年後・何十年後の遠い将来まで予測することはできるのでしょうか。

地球の運行状態などが今のまま続くと仮定した場合、将来の春分日や秋分日も、計算で予測することが可能です。

 計算

1980年を基準に1980年から2099年までの春分の日・秋分の日を計算する

#------------------------------------------------------------------
sub get_equinox_day{
#------------------------------------------------------------------

=head2 春分の日秋分の日を求める [get_equinox_day] 

=over 2

指定した年の春分日・秋分日をもとめる
(1980年から2099年に適用)
($vernal,$autumnal)=get_equinox_day($y);

=back

=cut

   my $s = shift;
   my ($yy)=@_;
   my ($vernal) = int(20.8431+0.242194*($yy-1980)-int(($yy-1980)/4));
   my ($autumnal)=int(23.2488+0.242194*($yy-1980)-int(($yy-1980)/4));

   return ($vernal,$autumnal);
}

 

閉じれる半透明のパネル

 半透明のパネルを追加

[html]

<div id="overlay" class="content">
    <div class="inner">
    @{[$s->panel_content()]}
            <div id="panel" class="panel hide"></div>
    </div>
</div>

[css]

.content{
  position:absolute;
  top: 375px;
  left:0px;
  width:60%;
  min-width:315px;
  display:none;
  z-index:100;
}
.inner{
  padding:10px;
  background-color:rgba(0,0,0,0.5);
}

 閉じたり開いたり

[JavaScript]

<script type="text/javascript">
    $(function() {
        $('#panel').toggle(
            function() {
                $(this).addClass('show').removeClass('hide');
                $('#overlay').stop().animate( { left : - $('#overlay').width()   + 20 + 'px' }, 300 );
            },
            function() {
                $(this).addClass('hide').removeClass('show');
                $('#overlay').stop().animate( { left : '0px' }, 300 );
            }
        );
        $('#overlay').fadeIn(500);
    });

</script>

 作ってみる

 画面

 SOURCE

diff --git a/toolmmt/lib/Tool/mmt/Controller/Menu.pm b/toolmmt/lib/Tool/mmt/Controller/Menu.pm
index ef1ca1f..8ed6945 100644
--- a/toolmmt/lib/Tool/mmt/Controller/Menu.pm
+++ b/toolmmt/lib/Tool/mmt/Controller/Menu.pm
@@ -62,4 +62,48 @@
      }
      return $text;
  }
+ sub make_panel{
+     my $s = shift;
+     my $text = <<END_SCRIPT;
+<link rel="stylesheet" type="text/css" href="/css/demo.css" />
+
+<div id="overlay" class="content">
+    <div class="inner">
+    @{[$s->panel_content()]}
+            <div id="panel" class="panel hide"></div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    \$(function() {
+        \$('#panel').toggle(
+            function() {
+                \$(this).addClass('show').removeClass('hide');
+                \$('#overlay').stop().animate( { left : - \$('#overlay').width() + 20 + 'px' }, 300 );
+            },
+            function() {
+                \$(this).addClass('hide').removeClass('show');
+                \$('#overlay').stop().animate( { left : '0px' }, 300 );
+            }
+        );
+        \$('#overlay').fadeIn(500);
+    });
+    window.onload = function(){
+//      document.getElementById("panel").click();
+    };
+
+</script>
+
+END_SCRIPT
+     return $text;
+ }
+ sub panel_content{
+     my $s = shift;
+     my $text = <<END_SCRIPT
+    <pre>
+    @{[`cal -3h`]}
+    @{[`date +"%a %b %d %Y"`]}
+    </pre>
+END_SCRIPT
+ }
  1;
diff --git a/toolmmt/public/css/demo.css b/toolmmt/public/css/demo.css
new file mode 100644
index 0000000..0941c15
--- /dev/null
+++ b/toolmmt/public/css/demo.css
@@ -0,0 +1,27 @@
+.content{
+  position:absolute;
+  top: 375px;
+  left:0px;
+  width:60%;
+  min-width:315px;
+  display:none;
+  z-index:100;
+}
+.inner{
+  padding:10px;
+  background:transparent url(/css/black.png) repeat top left;
+}
+.panel{
+  position:absolute;
+  height:86px;
+  width:20px;
+  right:0px;
+  top:10px;
+  cursor:pointer;
+}
+.hide{
+  background:transparent url(/css/hide.png) no-repeat center center;
+}
+.show{
+  background:transparent url(/css/show.png) no-repeat center center;
+}
diff --git a/toolmmt/templates/menu/menu.html.ep b/toolmmt/templates/menu/menu.html.ep
index ec27318..48724f8 100644
--- a/toolmmt/templates/menu/menu.html.ep
+++ b/toolmmt/templates/menu/menu.html.ep
@@ -1,5 +1,6 @@
 % layout 'default';
 % title 'menu' ;
+%== $self->make_panel();
 <table width=98%><tr><td style="vertical-align: top;">
 %   for my $r (@$_data){
 %       if ($r->{menukbn} =~ /^(H\d)/i){