Angular 4 - Working with HTMLCanvasElement - html

Hy every one,
I'm starting to learn Angular and I've decided to start with the implementation of the Langton Ant algorithm.
Project
The source of the standalone viewer is here: https://github.com/Phreno/langton
The source of the Angular version is here: https://stackblitz.com/edit/langton-ng?embed=1&file=app/langton/langton.main.component.ts&view=editor
I use a HTML5 canvas to display the walk.
Template
<p>Langton ant</p>
<canvas #canvas_box width='420' height='420' style="background: #fff; margin:20px"></canvas>
Component
import { LangtonGridService } from './langton.grid.service';
import { CellCoordinate } from './grid/grid.coordinate'
import { Component, ViewChild, AfterViewInit } from '#angular/core'
import { LangtonStep } from './langton.utils'
#Component({
selector: 'langton-main',
templateUrl: "template/langton.template.html",
})
export class LangtonMainComponent implements AfterViewInit{
DIRECTION_UP:number=2;
DIRECTION_RIGHT:number=1;
DIRECTION_LEFT:number=-1;
DIRECTION_DOWN:number=-2;
COLOR_FOG:string='white';
COLOR_GRID:string='gainsboro';
COLOR_FLAG:string='red';
COLOR_FREE:string='aqua';
COLOR_CURRENT:string='black';
MAX_ITERATION:number=15000;
STEP_TIMER:number=100;
grid:LangtonGridService;
#ViewChild('canvas_box')
canvas:HTMLCanvasElement;
lineCount:number;
columnCount:number;
state:any={};
roadmap:Array<LangtonStep>=[];
ngAfterViewInit(){
this.setGrid(new LangtonGridService(this.getCanvas()));
this.getGrid().drawBoard(this.COLOR_GRID);
this.walk();
}
private getCanvas():HTMLCanvasElement{
return this.canvas;
}
private getGrid():LangtonGridService{
return this.grid;
}
private setGrid(grid:LangtonGridService):void{
this.grid = grid;
}
private getState():any{
return this.state;
}
private getRoadmap():Array<LangtonStep>{
return this.roadmap;
}
private setLineCount():void{
this.lineCount = this.getGrid().computeLines().length;
}
private setColumnCount():void{
this.columnCount = this.getGrid().computeColumns().length;
}
private getLineCount():number{
return this.lineCount;
}
private getColumnCount():number{
return this.columnCount;
}
private getStart():LangtonStep{
var middleColumn:number = Math.round(this.getColumnCount()/2);
var middleLine:number = Math.round(this.getColumnCount()/2);
var start:CellCoordinate=new CellCoordinate(middleColumn, middleLine);
var color=this.COLOR_FLAG;
var direction=this.DIRECTION_UP;
var step:LangtonStep = new LangtonStep(start, color, direction);
return step;
};
private memorize(step:LangtonStep):void{
this.getState()[step.getAddress()]=step;
}
private track(step:LangtonStep):void{
this.getRoadmap().push(step);
}
private tracked(step:LangtonStep):boolean{
var state:string=typeof(this.getState()[step.getAddress()]);
var exist:boolean='undefined'.localeCompare(state)!==0;
return exist;
}
private turnRight(step:LangtonStep):LangtonStep{
var cellCoordinate:CellCoordinate;
var direction:number;
var color:string;
var next:LangtonStep;
switch(step.direction){
case this.DIRECTION_UP:
cellCoordinate=new CellCoordinate(step.coordinate.column+1, step.coordinate.line);
direction = this.DIRECTION_RIGHT;
break;
case this.DIRECTION_DOWN:
cellCoordinate=new CellCoordinate(step.coordinate.column-1, step.coordinate.line);
direction = this.DIRECTION_LEFT;
break;
case this.DIRECTION_LEFT:
cellCoordinate=new CellCoordinate(step.coordinate.column, step.coordinate.line+1);
direction = this.DIRECTION_UP;
break;
case this.DIRECTION_RIGHT:
cellCoordinate=new CellCoordinate(step.coordinate.column, step.coordinate.line-1);
direction = this.DIRECTION_RIGHT;
break;
default:
console.error('erreur dans la direction');
};
color=this.COLOR_FLAG;
next = new LangtonStep(cellCoordinate,color,direction);
return next;
}
private turnLeft(step:LangtonStep):LangtonStep{
var cellCoordinate:CellCoordinate;
var direction:number;
var color:string;
var next:LangtonStep;
switch(step.direction){
case this.DIRECTION_UP:
cellCoordinate=new CellCoordinate(step.coordinate.column-1, step.coordinate.line);
direction = this.DIRECTION_RIGHT;
break;
case this.DIRECTION_DOWN:
cellCoordinate=new CellCoordinate(step.coordinate.column+1, step.coordinate.line);
direction = this.DIRECTION_LEFT;
break;
case this.DIRECTION_LEFT:
cellCoordinate=new CellCoordinate(step.coordinate.column, step.coordinate.line-1);
direction = this.DIRECTION_UP;
break;
case this.DIRECTION_RIGHT:
cellCoordinate=new CellCoordinate(step.coordinate.column, step.coordinate.line+1);
direction = this.DIRECTION_RIGHT;
break;
default:
console.error('erreur dans la direction');
};
color=this.COLOR_FREE;
next = new LangtonStep(cellCoordinate,color,direction);
return next;
};
private getColorFromMemory(step:LangtonStep):string{
var color:string;
if(this.tracked(step)){
color=this.getState()[step.getAddress()].color;
} else {
color = this.COLOR_FOG;
}
return color;
};
private print(step:LangtonStep):void{
this.getGrid().fillCell(step.coordinate, step.color);
};
private enlight(cell:CellCoordinate):void{
this.getGrid().strokeCell(cell, this.COLOR_CURRENT);
}
private darken(cell:CellCoordinate):void{
this.getGrid().strokeCell(cell, this.COLOR_GRID);
}
private turn(step:LangtonStep):LangtonStep{
var next:LangtonStep;
switch(step.color){
case this.COLOR_FOG:
next=this.turnRight(step);
break;
case this.COLOR_FLAG:
next=this.turnLeft(step);
break;
case this.COLOR_FREE:
next=this.turnRight(step);
break;
default:
console.error('La couleur venue du ciel');
break;
}
next.setColor(this.getColorFromMemory(next));
return next;
}
private walk(step:LangtonStep=this.getStart()):void{
var self:LangtonMainComponent=this;
var forward:Function=function(step:LangtonStep):LangtonStep{
var next:LangtonStep=self.turn(step);
self.print(step);
self.darken(step.coordinate);
self.enlight(next.coordinate);
self.memorize(step);
self.track(step);
return next;
}
var iteration=0;
var run:number = setInterval(function():void{
if(self.MAX_ITERATION===iteration++){
clearInterval(run);
} else{
step=forward(step);
}
}, self.STEP_TIMER);
}
}
Problem
ERROR TypeError: Cannot read property 'getContext' of undefined
at GridDrawer.getContext (grid.drawer.ts:17)
at GridDrawer.openLayer (grid.drawer.ts:21)
at LangtonGridService.drawBoard (langton.grid.service.ts:109)
at LangtonMainComponent.ngAfterViewInit (langton.main.component.ts:51)
at callProviderLifecycles (provider.js:585)
at callElementProvidersLifecycles (provider.js:556)
at callLifecycleHooksChildrenFirst (provider.js:540)
at checkAndUpdateView (view.js:390)
at callViewAction (view.js:732)
at execComponentViewsAction (view.js:661)
Question
My first try was to set the canvas in the component constructor.
After some search, I understand that I've to import AfterViewInit interface to work with.
But in each case I reach the same error about undefined canvas.
I'm pretty sure the solution is obvious but I can't found it.
Thanks a lot for your help and have a good day.
Etienne.

I finally found the solution. The problem comes from HTMLCanvasElement and I resolve the binding using ElementRef instead.
Template
<canvas #canvas_box width='420' height='420' style="background: #fff; margin:20px"></canvas>
Component
export class LangtonMainComponent implements AfterViewInit{
/* ... */
#ViewChild('canvas_box') canvas:ElementRef;
ngAfterViewInit(){
this.canvas.nativeElement.width = this.grid.getCanvasWidth();
this.canvas.nativeElement.height = this.grid.getCanvasHeight();
this.drawBoard();
this.walk();
}
/* ... */
}

Related

Add setStragy to VectorSource

I use openlayers js library version 6.15.1
I have a class that inherits VectorSource. I don't know what to do in my constructor cause I would like my own stategy. I can't call super({ strategy: this._myStrategy, ... }) so how to do it?
Can I add the function setStrategy in VectorSource prototype? Or is there a better solution?
You could wrap the this for the custom strategy function inside another function which is valid in super
class CustomVectorSource extends VectorSource {
constructor(options) {
options = options || {};
const strategy = options.strategy;
options.strategy = function (extent, resolution) {
if (typeof this.customStrategy_ !== 'function') {
return [];
}
return this.customStrategy_(extent, resolution);
};
super(options);
this.customStrategy_ = strategy;
}
setStrategy(strategy) {
this.customStrategy_ = strategy;
}
}
https://codesandbox.io/s/vector-wfs-forked-08vw80?file=/main.js

How to fix DOMException error in google chrome?

I work with sounds in a browser game. I wrote sound manager. everything works fine, but not in Google chrome. I handled the error "uncaught (in promise) domexception", after the sounds were played in 50 percent of cases, in other cases it returns the error DOMException. What could be the problem?
export class AudioFile{
private audio: HTMLAudioElement;
private fileMP3: string;
private fileOGG: string;
private volume = 1;
private loop = false;
constructor(MP3:string, OGG:string) {
this.audio = new Audio();
this.fileMP3 = MP3;
this.fileOGG = OGG;
this.audio.canPlayType('audio/mpeg') ? this.audio.src = this.fileMP3 : this.audio.src = this.fileOGG;
this.audio.load();
this.audio.volume = this.volume;
this.audio.loop = this.loop;
}
public play() {
this.audio.currentTime = 0;
const playPromise = this.audio.play();
if (playPromise !== undefined) {
playPromise.then(_ => {
})
.catch(error => {
console.log(error);
});
}
}
public stop() {
this.audio.pause();
}
}
``````````````sound manager`````````````
export class SoundManager {
private sounds = new Map();
private static _soundManager: SoundManager;
constructor(){
if (SoundManager._soundManager) {
throw new Error("Instantiation failed: "+
"use Singleton.getInstance() instead of new.");
}
SoundManager._soundManager = this;
}
public static get instance(): SoundManager {
if (this._soundManager)
return this._soundManager;
else
return this._soundManager = new SoundManager();
}
preload() {
const pathMP3 = SoundConfig.PATHMP3;
const pathOGG = SoundConfig.PATHOGG;
for (const item in SoundConfig.SOUNDS) {
const name = SoundConfig.SOUNDS[item].NAME;
this.sounds.set(name, new AudioFile(pathMP3 + name + '.mp3', pathOGG + name + '.ogg'));
}
}
getSound(id: string): AudioFile {
return this.sounds.get(id);
}
}
Thank you spendr.
error: DOMException
code: 0
message: "play() failed because the user didn't interact with the document first.
Game runs through the iframe and I was needed to add a feature policy for autoplay.
<iframe src="..." allow="autoplay">
The article that helped me in solving the problem

Ionic 3/Google Distance Matrix API

The basic idea I am trying to execute is:
I have a list of branches, each having lat, lng attributes in them, which contain latitude, and longitude. I want to use the Google Distance Matrix API to find the distance and duration to each one of them.
This is my code..
Branches.ts (page which shows all the branches, where I also want to show the distance and duration)
//other imports
import { TravelDetailsProvider } from '../../providers/travel-details/travel-details';
#IonicPage()
#Component({
selector: 'page-branches',
templateUrl: 'branches.html',
})
export class BranchesPage {
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public branchProvider: BranchProvider,
public travelProvider: TravelDetailsProvider
){
}
ionViewDidLoad() {
this.getBranches();
}
getBranchDistanceAndTime(){
for(let branch of this.allBranches){
this.travelProvider.getTravelDetails(branch);
}
}
}
I know that I should probably assign the value which is returned to a variable on my branches.ts and iterate them on the view but for some reason I cannot get a value to return from the getTravelDetails() method
Travel-details.ts
declare var google;
var service = new google.maps.DistanceMatrixService();
#Injectable()
export class TravelDetailsProvider {
private travelDetailsObject: any = {};
constructor(public http: HttpClient) {
}
getTravelDetails(branch){
service.getDistanceMatrix(
{
origins: [new google.maps.LatLng(6.870128,79.880340)],
destinations: [new google.maps.LatLng(branch.lat, branch.lng)],
travelMode: 'DRIVING'
}, this.callback);
}
callback(response, status) {
let travelDetailsObject;
if (status == 'OK') {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
var element = results[j];
var distance = element.distance.text;
var duration = element.duration.text;
var from = origins[i];
var to = destinations[j];
travelDetailsObject = {
distance: distance,
duration: duration
}
}
}
this.travelDetailsObject = travelDetailsObject;
}
}
}
When I run this code, I get an error: Uncaught TypeError: Cannot set property 'travelDetailsObject' of null
After doing some research, I ran into this github issues page. I'm wondering if this is the problem I am having
https://github.com/rollbar/rollbar.js/issues/344
Thanks for any help
You may try
constructor() {
this._mx = new google.maps.DistanceMatrixService();
}
getDistanceMatrix(req: DistanceMatrixRequest): Observable<DistanceMatrixResponse> {
return Observable.create((observer) => {
this._mx.getDistanceMatrix(req, (rsp, status) => {
// status checking goes here
observer.next(rsp);
observer.complete();
});
});
}

ActionScript 3 Error #1009 null object reference

I'm having some errors with a command system I built for my flash project. One of the commands is intro which essentially restarts the project, or is meant to (The intro starts at frame 0 of the first scene). But when it runs a reference error is thrown on what I have determined to be line 21 (Through commenting code out until it no longer errors) which is the thisRef.gotoAndPlay line of the intro function.
Here is my code:
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.system.fscommand;
import flash.events.KeyboardEvent;
import flash.media.Sound;
public class Main extends MovieClip {
/* The real frame number */
public var realFrameNo:int = 0;
/* Whether startup has been ran or not */
public var startupRan:Boolean = false;
/* Whether or not the beggining text is there */
public var placeholderPresent:Boolean = true;
/* Commands recognized by the computer [command:string,handler:void] */
public var commandList = new Array(["intro",function(thisRef:Main) {
gotoAndPlay(0,"Intro");
}],
["exit",function(thisRef:Main) {
fscommand("quit");
}]);
/* Helper functions */
public function isAlphabetic(value:String):Boolean
{
var result:String = value.match(/[a-zA-Z]*/)[0];
return value.length == result.length;
}
public function getSceneNo():int
{
return (realFrameNo > 0 ? Math.floor( (realFrameNo / stage.frameRate) ) : 0 );
}
public function getSceneName(sceneNo:int):String
{
switch(sceneNo)
{
default:
return "Intro";
case 0:
return "Intro";
case 1:
return "MainMenu";
}
}
/* Main functions */
public function Main()
{
this.addEventListener('enterFrame',function() {
if(!this.startupRan)
realFrameNo += 1;
/* Main menu init */
if(getSceneNo() == 1 && !this.startupRan && currentFrame == 2)
{
stop();
this.startupRan = true;
/* Add keyboard events */
stage.addEventListener(KeyboardEvent.KEY_DOWN,function(event:KeyboardEvent){
var letter:String = String.fromCharCode(event.charCode).toUpperCase();
if(event.keyCode == 8)
updateMonitor("");
else if(event.keyCode == 13)
evalInput();
else if(isAlphabetic(letter))
updateMonitor(letter);
});
/* Add button events */
btnQ.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("Q"); });
btnW.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("W"); });
btnE.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("E"); });
btnR.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("R"); });
btnT.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("T"); });
btnY.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("Y"); });
btnU.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("U"); });
btnI.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("I"); });
btnO.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("O"); });
btnP.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("P"); });
btnA.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("A"); });
btnS.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("S"); });
btnD.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("D"); });
btnF.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("F"); });
btnG.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("G"); });
btnH.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("H"); });
btnJ.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("J"); });
btnK.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("K"); });
btnL.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("L"); });
btnZ.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("Z"); });
btnX.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("X"); });
btnC.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("C"); });
btnV.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("V"); });
btnB.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("B"); });
btnN.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("N"); });
btnM.addEventListener(MouseEvent.CLICK,function(){ updateMonitor("M"); });
btnDel.addEventListener(MouseEvent.CLICK,function(){ updateMonitor(""); });
btnEnter.addEventListener(MouseEvent.CLICK,function(){ evalInput(); });
btnReturn.addEventListener(MouseEvent.CLICK,function(){ evalInput(); });
}
});
}
public function updateMonitor(letter:String)
{
if(this.placeholderPresent) //Remove placeholder
lblInput.text = letter;
else if(letter == '' || letter == null) //Backspace
{
lblInput.text = lblInput.text.substr(0,lblInput.text.length-1);
}
else //Append text
lblInput.appendText(letter);
if(lblInput.text == "")
{
lblInput.text = "Type something to begin..";
this.placeholderPresent = true;
}
else
this.placeholderPresent = false;
}
public function evalInput():void
{
if(this.placeholderPresent) //Don't eval the starting text
return;
lblOutput.text = "Scanning for commands...";
for(var i:int = 0; i < this.commandList.length; i++)
{
if(lblInput.text.toLowerCase() == this.commandList[i][0])
{
this.commandList[i][1](this);
lblOutput.appendText("\nCommand ran.");
return;
}
}
lblOutput.appendText("\nNo command recognized.");
}
}
}
Full stack trace:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main/evalInput()[H:\Year 2\Units\Unit 43 - Multimedia Design\Flash Application\Main.as:144]
at Function/<anonymous>()[H:\Year 2\Units\Unit 43 - Multimedia Design\Flash Application\Main.as:71]

TypeScript variable that is a typed function

I want to have a variable in a TypeScript class that is of the type "boolean isVisible()".
How do I declare it?
How do I assign this function for another instantiated object to this variable?
How do I call this function?
ps - This seems so basic but 10 minutes of searching and I couldn't find it.
function boolfn() { return true; }
function strfn() { return 'hello world'; }
var x: () => boolean;
x = strfn; // Not OK
x = boolfn; // OK
var y = x(); // y: boolean
Here's one way of doing it, though I'll be happy to work with you to figure out exactly what you're trying to achieve.
export module Sayings {
export class Greeter {
isVisible(): boolean {
return true;
}
}
}
var greeter = new Sayings.Greeter();
var visible = greeter.isVisible();
You could also use a property instead of a function. Your original question talks about a "variable" and a "function" as if they're the same thing, but that's not necessarily the case.
export module Sayings {
export class Greeter {
isVisible: boolean = false;
}
}
var greeter = new Sayings.Greeter();
var visible = greeter.isVisible;
greeter.isVisible = true;
Or something like this maybe?
export module Sayings {
export class Greeter {
constructor(public isVisible: () => boolean) {
}
}
}
var someFunc = () => {
return false;
}
var greeter = new Sayings.Greeter(someFunc);
var visible = greeter.isVisible();