devicePixelRatioと画面サイズ

devicePixelRatioと画面のサイズ

ピクセルが2倍になった状態で
そのまま文字や画像を表示すると見かけ上のサイズが半分になり
小さく表示される

このため、鮮明な解像度の画面を使うときには
文字や画像を拡大表示することで
ちょうど良い大きさに拡大している

このときに、何倍かするかという値が
window.devicePixelRatio

この値は、iPhone4以降なら 2.0
ほとんどのAndroidなら 1.5

あと、元々の画像の解像の値を
物理値、物理座標といい

修正された値は、
論理値、論理座標という

これは少し面倒だけど
マウスイベントとか、タッチイベントの座標や
cssでの設定は論理座標になるため
Javascriptで制御するときには、論理座標になる

スクリーンに対する情報は
screen.height
screen.availHeight
window.innerHeight
window.outerHeight
などの値から情報を得られる

注意点としては、OSにより値が
物理値か、論理値か変わると言うこと

iOSはすべて論理値なのに、Androidは物理値のものもある

screen.height
画面の高さ
これは、ステータスバーなども含む
Androidでは物理値扱い

screen.availHeight
利用できるスクリーンの高さ
Androidでは物理値

screen.innerHeight
描画領域の内サイズ
どっちも論理値になる

screen.outerHeight
描画領域の外サイズ
Androidでは物理値

Webアプリをネイティブアプリみたいに見せるには

Webアプリをネイティブアプリみたいにみせる

Webアプリをネイティブアプリみたいに見せるには
アプリアイコンの登録と
ブラウザバーやメニューを非表示にする

まずは、アプリアイコンの登録

これは、HTMLファイルのheadへ
アプリアイコンへの設定をすることでできる

<link rel="apple-touch-icon-precomposed" href="../images/icon_file.png"/>

というように、
href=””には、アイコンファイルへのパスを記述する

アイコンのサイズは
144×144がオススメ

これは、アイコンのサイズが小さいと、
解像度の高い端末だとボケて表示されてしまうから

次に、アドレスバーの削除

Androidでは、

<meta name="apple-mobileweb-app-capable"

が使えないため、Javascriptで制御する

Androidでは、画面が1pxでも下へ移動するとURLバーが隠れるため
この特性を使う

$(document).on("mobileinit",function(){
if(navigator.userAgent.match(/Android|iPhone/i)){
$(document).on("pagechange",function()e,data){
//1pxずらしてアドレスバーを隠す
var hide_addressbar = function(){
if(document.body.scrollTop==0){
window.scrollTo(0,1);
}
}

/*ページ縦幅がスクリーンの縦幅より狭い場合
ページ縦幅をスクリーン+1して
スクロールできるようにする*/
if(navigator.userAgent.match(/Android/i)){
var pageHeight = $(document).height();
var windowHeight = window.outerHeight / window.devicePixelRatio;

if(windowHeight => pageHeight){
pageHeight = windowHeight+1;
$('BODY').css('height',(pageHeight)+'px');
}
}
hide_addressbar();

//スクロール時に強制的に 1pxずらす
$(window).on('scrollStop',function(){
hide_addressbar();
});
});
}

});

これは、Androidは、ページがスクリーンより短いと
縦にスクロールできないため
ページの縦幅を
スクリーンの縦幅+1px広げることで
スクリーン可能にしている

それが

if(navigator.userAgent.match(/Android/i)){
var pageHeight = $(document).height();
var windowHeight = window.outerHeight / window.devicePixelRatio;

if(windowHeight => pageHeight){
pageHeight = windowHeight+1;
$('BODY').css('height',(pageHeight)+'px');
}
}
hide_addressbar();

の部分

ただし、これだけだとせっかく隠しても
ユーザーが上にスクロールすると
隠したアドレスバーが出てしまう

このため、その対処として
スクロール時に画面が一番上に達したか
チェックし、
到達したなら強制的に1px下げることでアドレスバーを隠す

その処理が

$(window).on('scrollStop',function(){
hide_addressbar();
});

2つのグラフ間の塗りつぶし

2つのグラフ間の塗りつぶし

塗りつぶしをするには
fillBetweenを使う

opts={

fillBetween:{
series1: 1,
series2: 2,
color:rgba(227,167,121,0.2),
baseSeries:0,
fill:true
}
}

これは、トレンドを出すときに使える
株価とか為替のレンジ範囲分析とか

次に、基準値の表示

グラフ上に、閾値や基準値を表示するには
canvasOverlayプラグインを使う

canvasOverlayプラグインを使うには
HTMLでライブラリーを読み込む

<script src="js/jqplot/plugins/jqplot.canvasOverlay.min.js"></script>

次に、Javascriptのオプション項目で
canvasOverlayを設定

設定するには
objects:{

}
の中で各種項目を設定していく

opts={

canvasOverlay:{
show:true,
objects:{
{verticalLine:{
x:2,
lineWidth:2,
lineCap:'butt',
shadow:false
}},
{dashedHorizontalLine:{
y:5,
lineWidth:2,
dashPattern:[8,16],
lineCap:'round',
shadow:false
}}
}
},
}

となる

objectsの中では、最初に線種を設定する
利用できるものとして

verticalLine
垂直線

dashedVerticalLine
垂直線(点線)

horizontalLine
水平線

dashedHorizontalLine
水平線(点線)

lineWidth
線の幅

lineCap
線の端の設定
buttは端形、roundなら丸くする

dashPattern
波線の長さと間隔の指定
dashPattern:[8,16],
というように、配列みたいに指定

shadow
陰を付けるかどうかをtrue/falseで指定

Ajaxによるデータ取得

Ajaxによるデータ取得

Javascriptファイルの中にデータを記述するのではなく
株価やFXのレートのようにリアルタイムで変化するデータを表示したり
他のサービスのデータを取得して表示したい場合
Ajaxを使ってサーバーからデータを取得し
グラフを描画することができる

Ajaxを利用したデータの読みこみをするなら
jqplot.json2プラグインを読み込む

<script src="js/jqplot/plugins/jqplot.json2.min.js"></script>

Ajaxでデータを読み込む関数を定義し
dataReadererオプションに設定する

var dataAjaxReaderer = function(url,plot,options){
var ret = null;

$.ajax({
async:false,
url:url,
dataType:”json”,
success:function(data){
ret = data;
},
error:function(XMLHttpRequest,textStatus,errorThrown){
alert(“読みこみ失敗:”+errorThrown);
}
});
return ret;
};

var opts = {
title:”グラフタイトル”,
dataReaderer:ajaxDataReaderer,
axes:{
xaxis:{

}
}
}
[/javascript]

このとき、グラフを描くには
データ配列ではなく、データのURLを指定する

今回は、ローカルのファイルなので
ファイルバスを指定する

plot = $.jqplot('chart','./data.json',opts);

chartは
div id=”chart”
で、表示する領域

./data.jsonはファイルパス

opts は設定したオプション

次に、data.jsonの中身

今回は、JSON形式のデータ

[
[[1,1],[2,2],[3,5],[4,2],[5,4]],
[[1,6],[2,4],[3,3],[4,4],[5,5]]
]

数字ならこれでいいけど、文字列なら
“”で囲む

[
["etc",2.1],
["Android 4.4",9.6],
["Android 4.3",35.9],
["Android 4.2",50.4],
["Android 4.0",2.5]
]

とする

グラフのカスタマイズ

グラフのカスタマイズ

グラフの色を変更するには
seriesColorsオプションを使う

opts= [

seriesColors :[
 "#FF0000",
 "#00FF00",
],

]

複数グラフを作成するならかなり使える

次に、日付
グラフの軸に日付を付けることができる
株価チャートとか、経済指標とかのグラフを作るなら有効な手法

軸に日付を使うなら
jqplot.dateAxisReadererプラグインを使う
これを使うには、まずHTMLで

<script src="js/jqplot/plugins/jqplot.dateAxisReaderer.min.js"></script>

で必要なライブラリーを読み込む

次に、Javascriptで日付データを配列で作成し
オプションのX軸を描画するxaxisで
設定する

日付のデータは
月/日/年
のフォーマットで記述する

data = [
["2014/03/20",17.5],
["2014/03/21",16.5],
....
],
opts={
axes:{
xaxis:{
renderer:$.jqplot.DateAxisReaderer,
tickReaderer:$.jqplot.CanvasTickReaderer,tickOptions:{
formatString:"'%Y/%#m/%#d'",
angle:-30
}
},

}
}

となる

日付を利用したいのなら
renderer:

$.jqplot.DateAxisReaderer
を指定し

formatString:
でフォーマットを指定する

指定できるフォーマットは
%Y
2014 みたいな4桁の西暦

%y
14 みたいな2桁の西暦

%m
03 みたいな2桁の月

%#m

%B
September みたいな英語での月の名前

%b
Sep みたいな英語のニュースででる省略された月の名前

%d
03 みたいな2桁の日付

%#d
日付

%A
曜日

%a
省略型の曜日
日曜日ならSun

%H
03 など24時間表記の時間

%#H
3などの24時間表記の時間

%I
03などの12時間表記の時間

%#I
3などの12時間表記の時間

%M
2桁表記で分を表示

%#M
分を表示

%S
2桁で秒を表示

%#S
秒を表示

基本的に#を付けないなら2桁表記になる

マップ操作のイベント処理

マップ操作のイベント処理

まずは構文

void setOnMapClickListener(GoogleMap.OnMapClickLister listener)
マップ上のクリックを検知するリスナーを設定

void setOnMapLongClickListener(GoogleMap.OnMapLongClickListener listener)
マップ上の長押しを見地するリスナーを設定

void setOnCameraChangeListener(GoogleMap.OnCameraChangeListener listener)
マップ上でのカメラの返歌を検知するリスナーを設定

oid setOnInfoWindowClickListener(GoogleMap.OnInfoWindowClickListenr lister)
ピン上の情報がクリックされたことを検知するリスナーを設定
これは他のAPIとの組み合わせに使えそう

void onMapClick(LatLng point)
マップ上でクリックされたときに呼び出される

void onMapLongClick(LatLng point)
マップ上で長押しされたときに呼び出される

void onCameraChange(CameraPosition position)
マップ上でカメラが変更されたとき呼び出される

onInfoWindowClick(Marker marker)
ピン上の情報がクリックされたときのイベント処理

次に引数のメモ
listener
各イベントを検知するためのリスナー

point
マップ上で操作を行った位置情報

marker
クリックされたMarker インスタンス

マップ上のイベントは各リスナーを登録することで検知可能になる

では実践

クリック時
長押し時
マップを移動したとき
それぞれの状態のときに
Toast で座標を表示する

変更するのは MainActivity のみ

まずはクリックから

		//click event処理
		map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
			
			@Override
			public void onMapClick(LatLng point) {
				// TODO Auto-generated method stub
				
			}
		});

の中に処理を書いていく

Ubuntu の場合 Eclipse で Alt + / で
コードの補完が使えるため
すべて打ち込まなくても簡単に記述できる

中の処理は

Toast.makeText(getApplicationContext(), "クリックされた座標は "+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();

としてトーストで座標を表示する

		//click event処理
		map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
			
			@Override
			public void onMapClick(LatLng point) {
				// TODO Auto-generated method stub
				Toast.makeText(getApplicationContext(), "クリックされた座標は "+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();
			}
		});

次に長押しイベント
これもコード補完をつかって

		//長押しイベント
		map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
			
			@Override
			public void onMapLongClick(LatLng point) {
				// TODO Auto-generated method stub
				//長押しで行う処理
			}
		});

として処理内容を追加するだけ

今回もトーストで表示なので

Toast.makeText(getApplicationContext(), "長押しされた座標は "+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();

全体としては

		//長押しイベント
		map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
			
			@Override
			public void onMapLongClick(LatLng point) {
				// TODO Auto-generated method stub
				Toast.makeText(getApplicationContext(), "長押しされた座標は "+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();
			}
		});

そしてカメラの状態変化イベント処理
つまりマップを移動の処理

		//カメラ状態変化処理
		map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
			
			@Override
			public void onCameraChange(CameraPosition position) {
				// TODO Auto-generated method stub
				//カメラの状態変化のときの処理
			}
		});

これも座標をtoast で表示

LatLng point = position.target;
				Toast.makeText(getApplicationContext(), "カメラの状態が変化した座標は"+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();

一度座標を変数に格納してから使っている

全体としては


		//カメラ状態変化処理
		map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
			
			@Override
			public void onCameraChange(CameraPosition position) {
				// TODO Auto-generated method stub
				LatLng point = position.target;
				Toast.makeText(getApplicationContext(), "カメラの状態が変化した座標は"+point.latitude+", "+point.longitude, Toast.LENGTH_SHORT).show();
			}
		});

このように
それぞれの動作の中に処理を書けばいろいろな動作をマップでさせることができる

google map にピンマーカー表示

google map にピンマーカー表示

やり方は
GoogleMap インスタンスを取得
マーカーの表示位置などを格納したMarkerOptions インスタンスを生成

addMarker() でマーカー追加

続いて構文メモ

GoogleMap getMap()
GoogleMap インスタンスを取得

LatLng(double latitude,double longitude)
マーカーの表示位置用インスタンス

MarkerOptions position(LatLng position)
マーカーの表示位置を設定

MarkerOptions title(String title)
マーカーのタイトルを設定

MarkerOptions snippet(String snippet)
マーカーのスニペット設定

MarkerOptions icon(BitmapDescriptar icon)
マーカー上に表示するアイコンを設定

Marker addMarker(MarkerOptions options)
マーカーを追加

そして引数のメモ

latitude
緯度

longitude
経度

position
マーカーの表J位置を示すLatLngインスタンス

title
マーカーのタイトル用文字列

options
マーカー表示用オプション

あと
画面上にピン状マーカーを表示したいのなら
getMap() で
GoogleMap メソッドを取得し
addMarker() でピンの追加をする

マーカーのパラメータは
MarkerOptionsインスタンスを生成して設定する

では実験
サンプルを元にカスタマイズしていく

レイアウトファイルはそのまま使う
使うのは zoom.xml

MainActivity を書き換えるけど
前回作成した東京駅を表示するマップを改造する

		setContentView(R.layout.zoom);

		FragmentManager fragmentManager = getSupportFragmentManager();
		SupportMapFragment fragment =(SupportMapFragment)fragmentManager.findFragmentById(R.id.fragmentMap);
		
		//google map instance 取得
		GoogleMap map = fragment.getMap();
		
		//表示位置の生成(東京駅)
		LatLng posTokyoStation = new LatLng(35.681382, 139.766084);
		
		//東京駅の表示
		CameraPosition.Builder builder=new CameraPosition.Builder();
		//カメラの表示位置の指定
		builder.target(posTokyoStation);
		//ズームレベル
		builder.zoom(13.0f);
		//カメラの向きの指定(北向きなので0)
		builder.bearing(0);
		//カメラの傾き設定
		builder.tilt(25.0f);
		//マップの表示位置変更
		map.moveCamera(CameraUpdateFactory.newCameraPosition(builder.build()));

はそのまま使い

ピンの追加コードを書いていく

		//ピン設定
		MarkerOptions options=new MarkerOptions();
		//ピンの場所を東京駅にする
		options.position(posTokyoStation);
		//マーカーの吹き出しの名前
		options.title("東京駅");
		
		//ピンの追加
		map.addMarker(options);

基本的にはこれでOK

これでピンをタップすると
東京駅
と表示される

これを応用すればAPIとかと合わせてお店とかできそう

様々なグラフの作成、その2

様々なグラフの作成 その2

次に、バブルチャート

これは、2次元グラフに各ポイントの数値の大きさを円の大きさで表すグラフ

シェアの割合とか、規模の大きさをわかりやすくするときに使うグラフ

これを使うには
まずHTMLファイルで

<script src="js/jqplot/plugins/jquery.jqplot.min.js"></script>
<script src="js/jqplot/plugins/jqplot.bubbleReaderer.min.js"></script>

でライブラリーの読みこみ

表示するjQueryMobileのページIDはbubble

<div data-role="page" id="bubble">
</div>

そして、divで表示領域の設定

<div id="bubblechart"></div>

後は、Javascriptで表示

$(document).on("pageshow","#bubble",function(e){

//バブルチャートのデータの用意
//横軸、縦軸、円の大きさ、ラベル
var bubbledata = [
[4224273,835338, 22954,"Mac"],
[3004640,520414,21858,"Windows"],
[3434543,440676,18418,"Linux"]
];

var opts={
title:'自分的OS普及状態'
seriesDefaults:{
renderer:$.jqplot.BubbleReaderer,
rendererOptions:{
//バブルの透明度
bubbleAlpha:0.6,
//バブルを選択した時の透明度
highlightAlpha:0.8
},
shadow:true,
//バブルの影の透明度
shadowAlpha:0.05
},

//ラベル関連設定
axes:{
xaxis:{
label:'販売されたマシンの数'
},
labelReaderer:$.jqplot.CanvasAxisLabelReaderer,
tickReaderer:$.jqplot.CanvasTickReaderer,
tickOptions:{angle:-60}
},
yaxis:{
label:'搭載OS',
labelReaderer:$.jqplot.CanvasAxisLabelReaderer,
tickReaderer:$.jqplot.CanvasAxisTickReaderer
}
},
};

//バブルチャートの表示
$.jqplot.config.enablePlugins = true;
bubbleplot = $.jqplot('bubblechart',[bubbledata],opts);

});

バブルチャートを使うなら
レンダラは
$.jqplot.BubbleReaderer
を使う

そして、データは
[横軸、縦軸、円の大きさ、ラベル]
の順番で記述

rendererOptions:{

}
では、見た目の設定をしている

bubbleAlpha
バブルの透明度

highlightAlpha
バブルを選択した時の透明度

shadowAlpha
バブルの影の透明度

となる

様々なグラフの作成

様々なグラフの作成

水平棒グラフの作成の場合、

まずはデータ定義で

var bardata =[

[[30,1],[10,2],[40,3],[20,4]], //売上データ
[[5,1],[1,2],[7,3],[4,4]] //利益データ
];

このように、[値、カテゴリID]
というように指定する

カテゴリIDを設定したら
axesの中の yaxisでカテゴリ軸を利用する

axes:{

yaxis:{
renderer:$.jqplot.CategoryAxisReaderer,
ticks:['iPhoneアプリ開発','Androidアプリ開発','アフィリエイトサイト制作','電子書籍制作'];

}
}

次に、レンダラのオプションの
barDirectionへ
horizontalを設定する

seriesDefaults:{
renderer:$.jqplot.BarReaderer,
shadowAngle:135,
rendererOptions:{
barDirection:'horizontal'
}
},

今回は、
shadowAngle:135
で、影の角度を135度にしている

これは、デフォルトの状態だと
バーの影が
バーの延びているほうにかかり
終端が見えにくい為
shadowAngleで角度を変更しておく

次に、円グラフ

HTMLファイルで

<script src="js/jqplot/plugins/jqplot.pieReaderer.min.js"></script>

で必要なファイルの読みこみ

<div id="piechart"></div>

で表示領域の設定

そして、Javascriptファイルで制御

piedata = [
['etc',2.1],
['Nexus7',9.6],
['HTC J ONE', 35.3],
['ubuntu 12.04',50.6],
['ipod touch',2.4]
];

opts={
title:'使用頻度',
seriesDefaults:{
renderer:jQuery.jqplot.PieReaderer,
rendererOptions:{
showDataLabels:true,
padding:8
}
},

legend:{
show:true,
location:'ne',
rendererOptions:{
numberRows:2
},
}

}
pieplot = $.jqplot('piechart',[pieplot],opts);

データについては
[‘etc’,2.1],
[‘Nexus7’,9.6],
[‘HTC J ONE’, 35.3],
[‘ubuntu 12.04’,50.6],
[‘ipod touch’,2.4]
というように、配列で
[ラベル, 値]で定義する

そして、円グラフを使うには
レンダラで
$.jqplot.PieReaderer
を使う

ソースは

seriesDefaults:{
renderer:jQuery.jqplot.PieReaderer,
rendererOptions:{
showDataLabels:true,
padding:8
}
},

showDataLabels:

円グラフの要素の値を表示する設定
trueなら数字を表示しなくなる

grunt の準備

ドットインストールの less が完了したので grunt に挑戦
まずは環境の構築

node.js を使ったタスク自動化ツールが grunt

主にCSS JSのフロントエンドまわりのファイル圧縮
結合、最適化などの手順をスクリプト化するツール

スクリプト化すれば面倒な作業を一瞬で実行したり
自動化の手順を他の人と共有できる

公式サイトは
http://grunts.com/

必要な知識は
node.js
js
html
css
less

less のプリプロセッサーを題材にタスク自動化をする
あと linux コマンド
作業はvagrant の centos

localdev ディレクトリに移動して

vagrant up

で起動し

vagrant ssh

でログイン

mkdir grunt_lessons

でディレクトリをつくり

cd grunt_lessons

で移動してここで作業する

ipアドレスに関しては ifconfig で確認

node -v 

でヴァージョン確認
v0.10.24

npm -v

でこっちも確認
1.3.6

less の確認のため
lessc -v を実行したけど
lessc: コマンドが見つかりません
となるので
less をインストール

http://lesscss.org/#using-less
を参考にインストール

sudo npm install -g less

でインストール

途中、

npm WARN unmet dependency /usr/lib/node_modules/block-stream requires inherits@'~2.0.0' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/fstream requires inherits@'~2.0.0' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/fstream-ignore requires inherits@'2' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/fstream-npm requires inherits@'2' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/glob requires inherits@'2' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/npmconf requires inherits@'~2.0.0' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined
npm WARN unmet dependency /usr/lib/node_modules/tar requires inherits@'2' but will load
npm WARN unmet dependency undefined,
npm WARN unmet dependency which is version undefined

となっていたいたので、問題がおきたらその時対処の予定

lessc -v 

でバージョン確認したら
lessc 1.7.0 (LESS Compiler) [JavaScript]
となった

次に grunt コマンドのインストール

sudo npm install -g grunt-cli

結果としては

grunt-cli@0.1.13 /usr/lib/node_modules/grunt-cli
├── resolve@0.3.1
├── nopt@1.0.10 (abbrev@1.0.4)
└── findup-sync@0.1.3 (lodash@2.4.1, glob@3.2.9)

となっているので起動はできそう