fabric js not working in angular 11 for HTML 5 canvas - html5-canvas

I am trying to add textbox on canvas, I am using angular 11 and fabric library.
NPM that I have installed
npm i fabric
npm i #types/fabric
HTML
<canvas id="myCanvas" width="1000" height="700" style="border:1px solid #000000;">
</canvas>
app componnet
import { Component } from '#angular/core';
import { fabric } from 'fabric'
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'TestProject';
canvas : any;
constructor(){
this.canvas = new fabric.Canvas('myCanvas');
this.canvas.add(new fabric.Textbox('Hello Fabric!'));
}
}
When I run this code only canvas is visible nothing else.

You are trying to instantiate the canvas during construction time of your component. At that time the actual Canvas Element, is not available on the DOM yet. You need to run the fabric instantiation inside the ngAfterViewInit lifecycle hook of your component, to make sure the Canvas is ready. Something like this:
import { Component, AfterViewInit } from '#angular/core';
import { fabric } from 'fabric'
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
title = 'TestProject';
canvas : any;
ngAfterViewInit() {
this.canvas = new fabric.Canvas('myCanvas');
this.canvas.add(new fabric.Textbox('Hello Fabric!'));
}
}

Related

How to create dismissable Clarity labels?

In the Clarity Components documentation there is a working example for "Dimissing labels", but unfortunately there is no example code for this case.
See https://v2.clarity.design/labels
The documentation says - A label can be dismissed. Use a close icon at the right-most side of a label to dismiss it.
How do I create the label in the example?
I tried the following without success (just hoping for the best)
<span class="label" >james#test.com<clr-icon shape="close" ></clr-icon></span>
There is not an implementation of this behavior, rather it is just a CSS/HTML example that shows what the pattern would look like. It is up to the application to handle the 'dismissing' of the label by removing the label on click of the close button.
You can write a directive, say dismissable and have it add a X icon to labels, and which could emit an event whenever user clicks the X.
import { Directive, ElementRef, Renderer2, AfterViewInit, Output, EventEmitter } from '#angular/core';
#Directive({
selector: '[dismissable]'
})
export class DismissabelDirective implements AfterViewInit {
#Output()
close = new EventEmitter();
constructor(private renderer: Renderer2, private elRef: ElementRef) {
}
ngAfterViewInit() {
let icon = this.renderer.createElement('clr-icon');
icon.setAttribute('shape', 'close');
icon.style.margin = '1rem;'
this.renderer.setStyle(icon, 'margin-left', '0.5rem');
this.renderer.setStyle(icon, 'margin-right', '-0.25rem');
this.renderer.setStyle(icon, 'cursor', 'pointer');
this.renderer.appendChild(this.elRef.nativeElement, icon);
this.renderer.listen(icon, 'click', () => {this.close.emit(); return true;})
}
}
You could use it like below:
app.component.html
<div class="container">
<span class="label" dismissable (close)="delete(item)" *ngFor="let item of items">{{item}}</span>
</div>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
items = ['Apple', 'Orange', 'Banana'];
delete(item) {
const index: number = this.items.indexOf(item);
if (index !== -1) {
this.items.splice(index, 1);
}
}
}
Here is complete StackBlitz: https://stackblitz.com/edit/clarity-light-theme-v2-dismissable-labels

Nativescript 6.0 How to get the focuschangeListener for Searchbar in Android

I implement the project in Nativescript angular. In nativescript 5.0 I was get the focus change listener using the following code. After updating 6.0 I face the issue in android.
Reason: The Search bar extends the androidx widget anyone help how to fix the issue in 6.0.
<SearchBar id="searchBarMall"
[hint]="searchMall" (loaded)="searchBarloaded($event)"
(textChange)="onTextChanged($event)" (clear)="onClear($event)"
(submit)="onSubmit($event)"
textFieldHintColor="gray"></SearchBar>
Typescript
import { SearchBar } from "tns-core-modules/ui/search-bar";
import { Component, OnInit } from "#angular/core";
import { Page, isAndroid } from "tns-core-modules/ui/page";
#Component({
selector: "Home",
moduleId: module.id,
templateUrl: "./home.component.html",
styleUrls: ["./home.component.css"]
})
export class HomeComponent implements OnInit {
searchPhrase: string;
private searchbar: any;
onSearchSubmit(args): void {
let searchBar = <SearchBar>args.object;
console.log("You are searching for " + searchBar.text);
}
constructor(private _page: Page) {
}
ngOnInit(): void {
}
searchBarloaded(args) {
if (isAndroid) {
let self = this;
let searchBar = <SearchBar>args.object;
searchBar.android.setOnQueryTextFocusChangeListener(new android.view.View.OnFocusChangeListener({
onFocusChange: function (v: any, hasFocus: boolean) {
console.log("Focus" + hasFocus);
}
}));
this.searchbar.android.setFocusable(false);
this.searchbar.android.clearFocus();
}
}
ngAfterViewInit() {
this.searchbar = <SearchBar>this._page.getViewById("searchBarMall");
}
}
Use setOnQueryTextFocusChangeListener on nativeView.
this.searchbar.android.setOnQueryTextFocusChangeListener(new android.view.View.OnFocusChangeListener({
onFocusChange:function(v : any , hasFocus:boolean){
if(hasFocus){
...
}else{
...
}
}
}));

kendo ui for angular AutoComplete wont open

iam trying to use the autocomplete component
data is loaded (i can see it on the HTML)
but when user types inside the textbox
nothing happens
any idea why ?
thank u
the HTML:
<kendo-autocomplete [data]="data"
[placeholder]="'e.g. Denmark'"
class="countries" >
</kendo-autocomplete>
the TS:
import { Component, OnInit, NgModule } from '#angular/core';
#Component({
selector: 'app-product-search-box',
templateUrl: './product-search-box.component.html',
styleUrls: ['./product-search-box.component.css']
})
export class ProductSearchBoxComponent implements OnInit {
public data: Array<string> = ["Albania", "Andorra", "Armenia", "Austria", "Azerbaijan"];
constructor() {
}
ngOnInit() {
}
}
proof that data is loaded:
Make sure you have imported the BrowserAnimationsModule required for the popup animations:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platformbrowser/animations';
import { HttpModule } from '#angular/http';
import { DropDownsModule } from '#progress/kendo-angular-dropdowns';
import 'hammerjs';
import { AppComponent } from './app.component';
#NgModule({
imports: [ BrowserModule, BrowserAnimationsModule, HttpModule,
DropDownsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Everything in the provided code seems fine otherwise. You should also check for console errors like already suggested.
Here is an working example:
EXAMPLE

NativeScript handling back button event

I am trying to handle the hardware back button in a NativeScript app. I am using NativeScript version 2.3.0 with Angular.
Here is what I have in main.ts file
// this import should be first in order to load some required settings (like globals and reflect-metadata)
import { platformNativeScriptDynamic, NativeScriptModule } from "nativescript-angular/platform";
import { NgModule,Component,enableProdMode } from "#angular/core";
import { AppComponent } from "./app.component";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { routes, navigatableComponents } from "./app.routing";
import { secondComponent } from "./second.component";
import {AndroidApplication} from "application";
#Component({
selector: 'page-navigation-test',
template: `<page-router-outlet></page-router-outlet>`
})
export class PageNavigationApp {
}
#NgModule({
declarations: [AppComponent,PageNavigationApp,secondComponent
// ...navigatableComponents
],
bootstrap: [PageNavigationApp],
providers:[AndroidApplication],
imports: [NativeScriptModule,
NativeScriptRouterModule,
NativeScriptRouterModule.forRoot(routes)
],
})
class AppComponentModule {
constructor(private androidapplication:AndroidApplication){
this.androidapplication.on("activityBackPressed",()=>{
console.log("back pressed");
})
}
}
enableProdMode();
platformNativeScriptDynamic().bootstrapModule(AppComponentModule);
I am importing application with
import {AndroidApplication} from "application";
Then in the constrouctor of appComponentModule I am registering the event for activityBackPressed and just doing a console.log.
This does not work.
What am I missing here?
I'm using NativeScript with Angular as well and this seems to work quite nicely for me:
import { RouterExtensions } from "nativescript-angular";
import * as application from "tns-core-modules/application";
import { AndroidApplication, AndroidActivityBackPressedEventData } from "tns-core-modules/application";
export class HomeComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
if (application.android) {
application.android.on(AndroidApplication.activityBackPressedEvent, (data: AndroidActivityBackPressedEventData) => {
if (this.router.isActive("/articles", false)) {
data.cancel = true; // prevents default back button behavior
this.logout();
}
});
}
}
}
Note that hooking into the backPressedEvent is a global thingy so you'll need to check the page you're on and act accordingly, per the example above.
import { Component, OnInit } from "#angular/core";
import * as Toast from 'nativescript-toast';
import { Router } from "#angular/router";
import * as application from 'application';
#Component({
moduleId: module.id,
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.css']
})
export class MainComponent {
tries: number = 0;
constructor(
private router: Router
) {
if (application.android) {
application.android.on(application.AndroidApplication.activityBackPressedEvent, (args: any) => {
if (this.router.url == '/main') {
args.cancel = (this.tries++ > 0) ? false : true;
if (args.cancel) Toast.makeText("Press again to exit", "long").show();
setTimeout(() => {
this.tries = 0;
}, 2000);
}
});
}
}
}
Normally you should have an android activity and declare the backpress function on that activity. Using AndroidApplication only is not enough. Try this code:
import {topmost} from "ui/frame";
import {AndroidApplication} from "application";
let activity = AndroidApplication.startActivity ||
AndroidApplication.foregroundActivity ||
topmost().android.currentActivity ||
topmost().android.activity;
activity.onBackPressed = function() {
// Your implementation
}
You can also take a look at this snippet for example
As far as I know, NativeScript has a built-in support for this but it's not documented at all.
Using onBackPressed callback, you can handle back button behaviour for View components (e.g. Frame, Page, BottomNavigation).
Example:
function pageLoaded(args) {
var page = args.object;
page.onBackPressed = function () {
console.log("Returning true will block back button default behaviour.");
return true;
};
page.bindingContext = homeViewModel;
}
exports.pageLoaded = pageLoaded;
What's tricky here is to find out which view handles back button press in your app. In my case, I used a TabView that contained pages but the TabView itself handled the event instead of current page.

How to implement D3 in Angular 2

I want to implement this code from d3.js to angular 2 component, but i don't know how to call js file into component ts file. I have found some code for line chart, with index.html and lineChart.js. How can I call javascript in ngAfterViewInit or afterViewInit.
Example how chart looks like http://plnkr.co/edit/Jijnm8W4sRzAAsLMTvgV?p=preview
So I want to call this in component ts in ngAfterViewInit.
Here is code for component:
import {Component, Directive, ViewChild, ElementRef, Renderer} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
declare var d3: any;
declare var jQuery: any;
#Directive({
})
class H3 {}
#Component({
selector: 'my-app',
})
export class D3 {
constructor(public renderer: Renderer, public el: ElementRef){ }
ngOnInit() {
}
ngAfterViewInit() {
}
}
You could use something like that:
declare var d3: any;
export class D3 {
constructor(public renderer: Renderer, public el: ElementRef){ }
ngOnInit() {
}
ngAfterViewInit() {
var el:HTMLElement = this.el.nativeElement;
var root = d3.select(el);
root.append('svg')
(...)
}
}
See this question for more details:
Using D3.js with Angular 2
npm install --save d3
check d3 version in package.json and check it in node_modules too.
then, in the component.ts, import it as below
import * as d3 from 'd3';
Write your javascript codes in component.ts class
This is for d3-V4 .I ususally prefer d3-ng2-service. It's easy to install and use.
npm install d3-ng2-service --save
Add D3Service to the providers in the app.module.ts
In your .ts file import the necessary D3 libraries like
import { D3Service, D3,
Axis,
Path,
ScaleLinear,
ScaleOrdinal,
} from 'd3-ng2-service';
After that in the class constructor save the d3 instance in a class variable
constructor( private _d3Service: D3Service) {
this.d3 = this._d3Service.getD3();
}
Now you can freely use the d3 variable to build svg objects
ngAfterViewInit(){
this.buildSVG();
}
buildSVG(): void {
let d3=this.d3;
var svg = d3.select("body").append("svg")
3 .attr("width", 200)
4 .attr("height", 200);
}
Please follow the following 3 steps
step 1: install D3 and the D3 type definitions from npm.
npm install d3 && npm install #types/d3 --save-dev
step 2: import d3 inside the ts file
import * as d3 from 'd3';
step 3: implement the logic
For reference

Resources