Я нашел решение. На самом деле я нашел отличный пост на github
https://github.com/shivs25/angular5-canvas-drawer. Я использовал это решение для реализации своего собственного.
Так что все кредиты достаются Билли Шиверсу. Молодец.
Вот решение
Настройки для линии и окружности могут быть установлены динамически, ниже приведен только пример линии и окружности
CircleComponent и шаблон HTML
import { Component } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
@Component({
selector: 'app-circle',
templateUrl: './circle.component.html',
styleUrls: ['./circle.component.css']
})
export class CircleComponent extends ShapeComponent {
constructor() {
super('circle');
}
}
HTML
<ng-template #elementTemplate>
<svg:circle [attr.cx]="50" [attr.cy]="50" [attr.r]="40" stroke="black" stroke-width="3" fill="red" />
</ng-template>>
LineComponent и HTML-шаблон
import { Component } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
@Component({
selector: 'app-line',
templateUrl: './line.component.html',
styleUrls: ['./line.component.css']
})
export class LineComponent extends ShapeComponent {
constructor() {
super('line');
console.log('linecomponent:constructor');
}
}
html
<ng-template #elementTemplate>
<svg:line [attr.x1]="100" [attr.y1]="100" [attr.x2]="200" [attr.y2]="200" style="stroke:#006600; stroke-width:1px" />
</ng-template>>
ShapeComponent и HTML
import { Component, OnInit, ViewChild, TemplateRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-shape',
templateUrl: './shape.component.html',
styleUrls: ['./shape.component.css']
})
export class ShapeComponent implements OnInit, AfterViewInit {
shapeType: string;
visible: boolean = true;
id: string = 'unknown';
@ViewChild('elementTemplate')
elementTemplate: TemplateRef<any>;
constructor(shapeType: string) {
console.log('shapecomponent constructor :', shapeType);
this.shapeType = shapeType;
}
setid(value: string): void {
this.id = value;
}
ngOnInit() {
console.log('ShapeComponent ngOnInit()');
}
ngAfterViewInit(): void {
console.log('!!!!!!!!! ShapeComponent ngAfterViewInit: ', this.elementTemplate);
}
}
html: нет
Перечисление для типов компонентов
export enum ShapeTypes {
Line,
Circle,
Rectangle
}
Компонент ShapeHolder
import { Component, OnInit, ViewChild, TemplateRef, AfterViewInit } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
import { LineComponent } from '../line/line.component';
import { CircleComponent } from '../circle/circle.component';
import { ShapeTypes } from '../model/shape-types';
@Component({
selector: 'app-shapeholder',
templateUrl: './shapeholder.component.html',
styleUrls: ['./shapeholder.component.css']
})
export class ShapeholderComponent implements OnInit, AfterViewInit {
@ViewChild('elementTemplate')
elementTemplate: TemplateRef<any>;
shapes: ShapeTypes[];
constructor() {
this.shapes = [];
this.shapes.push(ShapeTypes.Line);
this.shapes.push(ShapeTypes.Circle);
console.log('shapeholder shapes :', this.shapes);
}
ngOnInit() {
console.log('ShapeHolderComponent : ngOnInit()');
}
ngAfterViewInit(): void {
console.log('!!!!!!!!! ShapeHolder ngAfterViewInit: ', this.elementTemplate);
}
}
html, установить высоту в ширину в CSS для SVG
<svg>
<ng-container *ngFor="let shape of shapes; let i = index">
<ng-container svg-dynamic [componentData]="shape">
</ng-container>
</ng-container>
</svg>
И самая важная его часть, директива
import { Directive, Input, ViewContainerRef, Injector, ComponentFactoryResolver } from '@angular/core';
import { ShapeComponent } from './shape/shape.component';
import { LineComponent } from './line/line.component';
import { CircleComponent } from './circle/circle.component';
import { ShapeTypes } from './model/shape-types';
@Directive({
selector: '[svg-dynamic]'
})
export class SvgDynamicDirective {
constructor(private _viewContainerRef: ViewContainerRef, private _resolver: ComponentFactoryResolver) {
}
@Input() set componentData(data: ShapeTypes) {
console.log('set componentdata : ', data);
let injector = Injector.create([], this._viewContainerRef.parentInjector);
console.log('injector:', injector);
let factory = this._resolver.resolveComponentFactory(this.buildComponent(data));
console.log('factory:', factory);
let component = factory.create(injector);
console.log('component:', component);
let c: ShapeComponent = <ShapeComponent>component.instance;
console.log('viewContainerRef:', this._viewContainerRef);
console.log('elementTemplate:', c.elementTemplate);
this._viewContainerRef.clear();
this._viewContainerRef.createEmbeddedView(c.elementTemplate);
}
private buildComponent(data: ShapeTypes): any {
switch (data) {
case ShapeTypes.Line:
return LineComponent;
case ShapeTypes.Circle:
return CircleComponent;
}
return null;
}
}
И app.component HTML
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<app-shapeholder></app-shapeholder>
</div>
Приложение appponpon
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'demo1';
}
и app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ShapeComponent } from './shape/shape.component';
import { LineComponent } from './line/line.component';
import { ShapeholderComponent } from './shapeholder/shapeholder.component';
import { SvgDynamicDirective } from './svg-dynamic.directive';
import { CircleComponent } from './circle/circle.component';
@NgModule({
entryComponents: [
LineComponent,
ShapeComponent,
CircleComponent
],
declarations: [
AppComponent,
LineComponent,
ShapeComponent,
CircleComponent,
ShapeholderComponent,
SvgDynamicDirective,
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
И последний снимок экрана моего приложения
Надеюсь, вы найдете этот ответ полезным и сможете использовать его в своем приложении. Идея заключается в создании динамических шаблонов просмотров