cordova でのスマホアプリ開発 ５

## canvasを組み込んでみる

cordova と ionic と html5 でアプリっぽいアプリを作ってみる

 

環境はこんな感じ

```
C:\cordova_app>ionic info
[WARN] You are not in an Ionic project directory. Project context may be missing.

Ionic:

   Ionic CLI : 5.2.3

Utility:

   cordova-res : not installed
   native-run  : 0.2.7 (update available: 0.2.8)

System:

   NodeJS : v10.16.0
   npm    : 6.9.0
   OS     : Windows 10
```

以前[cordova でのスマホアプリ開発 ２]()から ionic のバージョンが少し上がりました



##### paper

http://paperjs.org/examples/chain/

挫折しましたー

全然動かない、原因もさっぱりー



##### お絵描き

急にかっこいい事しようとしてはいけません

１つ１つ組み込んで確認することが大事（戒め

なので

１．canvas の表示

２．canvas に線を引く

３．エミュレータでの確認

の順番で実装する



##### canvas の表示

新規に blank でアプリケーションを作成

```
C:\cordova_app>ionic start helloCanvas

Let's pick the perfect starter template!

Starter templates are ready-to-go Ionic apps that come packed with everything you need to build your app. To bypass this
prompt next time, supply template, the second argument to ionic start.

? Starter template: blank
√ Preparing directory .\helloCanvas - done!
√ Downloading and extracting blank starter - done!

Installing dependencies may take several minutes.

  ──────────────────────────────────────────────────────────────────────────────

         Ionic Advisory, tailored solutions and expert services by Ionic

                             Go to market faster
                    Real-time troubleshooting and guidance
        Custom training, best practices, code and architecture reviews
      Customized strategies for every phase of the development lifecycle

               Learn more: https://ion.link/advisory

  ──────────────────────────────────────────────────────────────────────────────


> npm.cmd i

> node-sass@4.12.0 install C:\cordova_app\helloCanvas\node_modules\node-sass
> node scripts/install.js

Cached binary found at C:\Users\****\AppData\Roaming\npm-cache\node-sass\4.12.0\win32-x64-64_binding.node

> core-js@2.6.9 postinstall C:\cordova_app\helloCanvas\node_modules\core-js
> node scripts/postinstall || echo "ignore"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> node-sass@4.12.0 postinstall C:\cordova_app\helloCanvas\node_modules\node-sass
> node scripts/build.js

Binary found at C:\cordova_app\helloCanvas\node_modules\node-sass\vendor\win32-x64-64\binding.node
Testing binary
Binary is fine
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

added 1121 packages from 1051 contributors and audited 54002 packages in 35.548s
found 0 vulnerabilities

> git.exe init
Initialized empty Git repository in C:/cordova_app/helloCanvas/.git/
> git.exe add -A
> git.exe commit -m "Initial commit" --no-gpg-sign

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got '****.(none)')
[WARN] Error encountered during commit. Disabling further git operations.

[INFO] Next Steps:

       - Go to your newly created project: cd .\helloCanvas
       - Run ionic serve within the app directory to see your app
       - Build features and components: https://ion.link/scaffolding-docs
       - Get Ionic DevApp for easy device testing: https://ion.link/devapp
```

canvas 用の page を paint として作成

```
C:\cordova_app\helloCanvas>ionic g
? What would you like to generate? page
? Name/path of page: paint
> ng.cmd generate page paint
CREATE src/app/paint/paint.module.ts (538 bytes)
CREATE src/app/paint/paint.page.html (124 bytes)
CREATE src/app/paint/paint.page.spec.ts (684 bytes)
CREATE src/app/paint/paint.page.ts (252 bytes)
CREATE src/app/paint/paint.page.scss (0 bytes)
UPDATE src/app/app-routing.module.ts (517 bytes)
[OK] Generated page!
```

html に canvas を設置

```paint.page.html
<div id="container" #container>
  <canvas id="canvas" #canvas></canvas>
</div>
```

ビルドエラーは出なかった

![test_canvas1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464760/a81c4bf3-78ab-49b2-b3db-69ddfb26e8cb.png)


表示できてるかもわからないので、canvas に背景色をつけてみる

```paint.page.scss
#container {
  width: 100%;
  height: 100%;
}
#canvas {
  width: 90%;
  height: 90%;
  background-color: #EEEEEE;
}
```

canvas の配置は問題なさげ

![test_canvas2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464760/1448408b-4c96-9541-d3d2-41511b0e297b.png)


##### canvas に線を引く

線を引く為に、canvas にクリックと移動のイベントを登録する

```paint.page.html
<div id="container" #container>
  <canvas id="canvas" #canvas (touchstart)="drawing($event)" (touchmove)="moved($event)"></canvas>
</div>
```

スクリプト側には canvas の要素とイベントを記載する

```paint.page.ts
import { Component, OnInit, ElementRef, ViewChild, Renderer } from '@angular/core';


@Component({
  selector: 'app-paint',
  templateUrl: './paint.page.html',
  styleUrls: ['./paint.page.scss'],
})
export class PaintPage implements OnInit {

  @ViewChild('canvas') canvasEl : ElementRef;
  private _canvas : any;

  saveX: number;
  saveY: number;

  selectedColor = '#CC3333';

  constructor() { }

  ngOnInit() {
  }

  ionViewDidEnter() {
    this._canvas = this.canvasEl.nativeElement;
    this._canvas.width = 400;
    this._canvas.height = 400;
  }

  drawing(ev) {
    var canvasPosition = this._canvas.getBoundingClientRect();
    this.saveX = ev.touches[0].pageX - canvasPosition.x;
    this.saveY = ev.touches[0].pageY - canvasPosition.y;
  }

  moved(ev) {
    var canvasPosition = this._canvas.getBoundingClientRect();

    let ctx = this._canvas.getContext('2d');
    let currentX = ev.touches[0].pageX - canvasPosition.x;
    let currentY = ev.touches[0].pageY - canvasPosition.y;

    ctx.lineJoin = 'round';
    ctx.strokeStyle = this.selectedColor;
    ctx.lineWidth = 3;

    ctx.beginPath();
    ctx.moveTo(this.saveX, this.saveY);
    ctx.lineTo(currentX, currentY);
    ctx.closePath();

    ctx.stroke();

    this.saveX = currentX;
    this.saveY = currentY;
  }

}
```

chrome のデベロッパーツールを起動し、Toggle device toolbar にチェックを入れる

canvas に線が引けた

※デベロッパーツールを使わない場合や、他のブラウザでは動かなかった…

　HTML5のお作法があるのかなぁ

![test_canvas3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464760/4cd2d00c-5a68-a2e2-3d02-68a476bdad3a.png)



##### canvas と描画のずれ

で、線は引けたけど、実際のポインタと描画位置にずれが発生する

Y座標が大きくなるのに比例してどんどんずれも大きくなっている

イベントで取得した位置と canvas の位置が合ってないのかなー

canvas を全画面に表示した場合、ずれがどうなるか確認してみる



container と canvas を 100% に設定して

```paint.page.scss
#container {
  width: 100%;
  height: 100%;
}
#canvas {
  width: 100%;
  height: 100%;
  background-color: #EEEEEE;
}
```

container のサイズを canvas に設定する

```
  @ViewChild('container') canvasContainerEl : ElementRef;
  private _container : any;

  ionViewDidEnter() {
    this._container = this.canvasContainerEl.nativeElement;
    this._canvas = this.canvasEl.nativeElement;
    this._canvas.width = this._container.clientWidth;
    this._canvas.height = this._container.clientHeight;
  }
```

ずれ無く線を描画できるようになった

![test_canvas4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464760/d6522412-9f67-c729-5472-cead2443faf6.png)



##### エミュレータでの確認

アプリケーションとして配置するとブラウザのように url で遷移ができなくなるので、リンクを作成

```home.page.html
  <div class="ion-padding">
    <a target="_blank" rel="noopener" href="../paint">CANVAS PAINT.</a>
  </div>
```

アプリケーションとしてエミュレータに配置

```
C:\cordova_app\helloCanvas>ionic cordova run android --native-run
```

遷移して canvas の正常動作を確認

![test_canvas56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464760/4994959a-50e1-e9df-9adc-2a33455567b2.png)

[cordova でのスマホアプリ開発 ６](https://qiita.com/flour_planaria/items/bd10e1f8807755ad3e21)