Ionicにp5js
を入れて絵を簡単に描けるようにしました。
またCapacitorのFilesystem APIを使って描いた画像をスマホに保存できるようにしました。
main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { defineCustomElements } from '@ionic/pwa-elements/loader';
// Call the element loader after the platform has been bootstrapped
defineCustomElements(window);
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
home.page.html
<ion-header [translucent]="true"> <ion-toolbar> <ion-title> p5Paint </ion-title> </ion-toolbar> </ion-header> <ion-content [fullscreen]="true"> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">p5Paint</ion-title> </ion-toolbar> </ion-header> <div id="canvasContainer" class="canvas-container"></div> <ion-range min="2" max="30" color="primary" [(ngModel)]="lineWidth"> <ion-icon size="small" slot="start" name="brush"></ion-icon> </ion-range> <input type="color" [(ngModel)]="strokeColor" name="head" value="0"> <ion-button expand="full" (click)="addPhotoToGallery()"> <ion-icon slot="start" name="download"></ion-icon> save image </ion-button> <ion-grid> <ion-row> <ion-col size="6" *ngFor="let photo of photoService.photos; index as position"> <ion-img src="{{ photo.base64 ? photo.base64 : photo.webviewPath }}"> </ion-img> </ion-col> </ion-row> </ion-grid> </ion-content>
home.page.ts
import { Component, ElementRef, OnInit } from '@angular/core'; import { PhotoService } from '../services/photo.service'; import * as p5 from 'p5'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { photos = this.photoService.photos; canvasX = 400; canvasY = 250; lineWidth = 3; strokeColor=0; constructor(private el: ElementRef,public photoService: PhotoService) { } ngOnInit() { const p5obj = new p5(p => { p.setup = () => { this.setup(p); }; p.draw = () => { this.draw(p); }; }, this.el.nativeElement); this.photoService.loadSaved(); } setup(p) { const c = document.querySelector('#canvasContainer'); p.createCanvas(this.canvasX, this.canvasY) .parent(c); p.background(220); } draw(p) { p.strokeWeight(this.lineWidth); p.stroke(this.strokeColor); if(p.mouseIsPressed){ p.line(p.mouseX,p.mouseY,p.pmouseX,p.pmouseY); } } addPhotoToGallery() { this.photoService.addNewToGallery(); } }
photo.service.ts
import { Injectable } from '@angular/core'; import { Plugins, Capacitor, FilesystemDirectory } from '@capacitor/core'; const { Filesystem, Storage } = Plugins; @Injectable({ providedIn: 'root' }) export class PhotoService { public photos: Photo[] = []; private PHOTO_STORAGE: string = "photos"; dataUrl:any; // other code constructor() { } public async addNewToGallery() { // canvas get const c:any=document.querySelector('#canvasContainer canvas'); this.dataUrl=c.toDataURL(); // Save the picture and add it to photo collection const savedImageFile = await this.savePicture(this.dataUrl); this.photos.unshift(savedImageFile); Storage.set({ key: this.PHOTO_STORAGE, value: JSON.stringify(this.photos.map(p => { // Don't save the base64 representation of the photo data, // since it's already saved on the Filesystem const photoCopy = { ...p }; delete photoCopy.base64; return photoCopy; })) }); } public async loadSaved() { // Retrieve cached photo array data const photos = await Storage.get({ key: this.PHOTO_STORAGE }); this.photos = JSON.parse(photos.value) || []; console.log(this.photos); // more to come... } private async savePicture(cameraPhoto: any) { // Convert photo to base64 format, required by Filesystem API to save const base64Data = await this.readAsBase64(cameraPhoto); // Write the file to the data directory const fileName = new Date().getTime() + '.jpeg'; const savedFile = await Filesystem.writeFile({ path: fileName, data: base64Data, directory: FilesystemDirectory.Data }); // Use webPath to display the new image instead of base64 since it's // already loaded into memory return { filepath: fileName, webviewPath: this.dataUrl }; } private async readAsBase64(cameraPhoto: any) { // Fetch the photo, read as a blob, then convert to base64 format const response = await fetch(cameraPhoto.webPath!); const blob = await response.blob(); return await this.convertBlobToBase64(blob) as string; } convertBlobToBase64 = (blob: Blob) => new Promise((resolve, reject) => { const reader = new FileReader; reader.onerror = reject; reader.onload = () => { resolve(reader.result); }; reader.readAsDataURL(blob); }); } interface Photo { filepath: string; webviewPath: string; base64?: string; }