Html 保持背景图像的响应性以及拖放元素的完整性,并响应wrt背景图像
我有一个工作堆栈闪电战: 我已经在包含背景图像的div上编写了角度和拖放元素的自定义拖放事件。我的目标是使div元素具有响应性,使新放置元素的位置与背景图像保持一致,从而也与背景图像成比例地响应 我尝试为父容器和子容器提供定位,因此父div会有响应,但子元素(删除的元素)不会与父背景图像保持完整,也不会保持比例 换句话说,当图像将被缩小或放大时,子元素(删除的元素)的大小也应按比例递增和递减,以保持其位置wrt图像的完整性 这里是拖放工作参考 指令 可降指令Html 保持背景图像的响应性以及拖放元素的完整性,并响应wrt背景图像,html,css,angular,Html,Css,Angular,我有一个工作堆栈闪电战: 我已经在包含背景图像的div上编写了角度和拖放元素的自定义拖放事件。我的目标是使div元素具有响应性,使新放置元素的位置与背景图像保持一致,从而也与背景图像成比例地响应 我尝试为父容器和子容器提供定位,因此父div会有响应,但子元素(删除的元素)不会与父背景图像保持完整,也不会保持比例 换句话说,当图像将被缩小或放大时,子元素(删除的元素)的大小也应按比例递增和递减,以保持其位置wrt图像的完整性 这里是拖放工作参考 指令 可降指令 import { Directiv
import { Directive, HostListener } from '@angular/core';
import { DroppableService } from '../_services/droppable.service';
@Directive({
selector: '[appDroppable]'
})
export class DroppableDirective {
constructor(private droppableService: DroppableService) { }
@HostListener('dragStart', ['$event'])
onDragStart(event: PointerEvent): void {
this.droppableService.onDragStart(event);
}
@HostListener('dragMove', ['$event'])
onDragMove(event: PointerEvent): void {
this.droppableService.onDragMove(event);
}
@HostListener('dragEnd', ['$event'])
onDragEnd(event: PointerEvent): void {
this.droppableService.onDragEnd(event);
}
}
import { Directive, ElementRef, EventEmitter, HostBinding, HostListener,
OnInit, Output, SkipSelf } from '@angular/core';
import { DroppableService } from '../_services/droppable.service';
@Directive({
selector: '[appDropzone]',
providers: [DroppableService]
})
export class DropzoneDirective implements OnInit {
@HostBinding('class.dropzone-activated') activated = false;
@HostBinding('class.dropzone-entered') entered = false;
@Output() drop = new EventEmitter<PointerEvent>();
@Output() remove = new EventEmitter<PointerEvent>();
private clientRect: ClientRect;
constructor(@SkipSelf() private allDroppableService: DroppableService,
private innerDroppableService: DroppableService,
private element: ElementRef) { }
ngOnInit(): void {
this.allDroppableService.dragStart$.subscribe(() => this.onDragStart());
this.allDroppableService.dragEnd$.subscribe(event =>
this.onDragEnd(event));
this.allDroppableService.dragMove$.subscribe(event => {
if (this.isEventInside(event)) {
this.onPointerEnter();
} else {
this.onPointerLeave();
}
});
this.innerDroppableService.dragStart$.subscribe(() =>
this.onInnerDragStart());
this.innerDroppableService.dragEnd$.subscribe(event =>
this.onInnerDragEnd(event));
}
private onPointerEnter(): void {
if (!this.activated) {
return;
}
this.entered = true;
}
private onPointerLeave(): void {
if (!this.activated) {
return;
}
this.entered = false;
}
private onDragStart(): void {
this.clientRect = this.element.nativeElement.getBoundingClientRect();
this.activated = true;
}
private onDragEnd(event: PointerEvent): void {
if (!this.activated) {
return;
}
if (this.entered) {
this.drop.emit(event);
}
this.activated = false;
this.entered = false;
}
private onInnerDragStart() {
this.activated = true;
this.entered = true;
}
private onInnerDragEnd(event: PointerEvent) {
if (!this.entered) {
this.remove.emit(event);
}
this.activated = false;
this.entered = false;
}
private isEventInside(event: PointerEvent) {
return event.clientX >= this.clientRect.left &&
event.clientX <= this.clientRect.right &&
event.clientY >= this.clientRect.top &&
event.clientY <= this.clientRect.bottom;
}
}
import { AfterContentInit, ContentChildren, Directive, ElementRef, QueryList
} from '@angular/core';
import { MovableDirective } from './movable.directive';
import { Subscription } from 'rxjs';
interface Boundaries {
minX: number;
maxX: number;
minY: number;
maxY: number;
}
@Directive({
selector: '[appMovableArea]'
})
export class MovableAreaDirective implements AfterContentInit {
@ContentChildren(MovableDirective) movables: QueryList<MovableDirective>;
private boundaries: Boundaries;
private subscriptions: Subscription[] = [];
constructor(private element: ElementRef) {}
ngAfterContentInit(): void {
this.movables.changes.subscribe(() => {
this.subscriptions.forEach(s => s.unsubscribe());
this.movables.forEach(movable => {
this.subscriptions.push(movable.dragStart.subscribe(() =>
this.measureBoundaries(movable)));
this.subscriptions.push(movable.dragMove.subscribe(() =>
this.maintainBoundaries(movable)));
});
});
this.movables.notifyOnChanges();
}
private measureBoundaries(movable: MovableDirective) {
const viewRect: ClientRect =
this.element.nativeElement.getBoundingClientRect();
const movableClientRect: ClientRect =
movable.element.nativeElement.getBoundingClientRect();
this.boundaries = {
minX: viewRect.left - movableClientRect.left + movable.position.x,
maxX: viewRect.right - movableClientRect.right + movable.position.x,
minY: viewRect.top - movableClientRect.top + movable.position.y,
maxY: viewRect.bottom - movableClientRect.bottom + movable.position.y
};
}
private maintainBoundaries(movable: MovableDirective) {
movable.position.x = Math.max(this.boundaries.minX, movable.position.x);
movable.position.x = Math.min(this.boundaries.maxX, movable.position.x);
movable.position.y = Math.max(this.boundaries.minY, movable.position.y);
movable.position.y = Math.min(this.boundaries.maxY, movable.position.y);
}
}
dropzone.directive
import { Directive, HostListener } from '@angular/core';
import { DroppableService } from '../_services/droppable.service';
@Directive({
selector: '[appDroppable]'
})
export class DroppableDirective {
constructor(private droppableService: DroppableService) { }
@HostListener('dragStart', ['$event'])
onDragStart(event: PointerEvent): void {
this.droppableService.onDragStart(event);
}
@HostListener('dragMove', ['$event'])
onDragMove(event: PointerEvent): void {
this.droppableService.onDragMove(event);
}
@HostListener('dragEnd', ['$event'])
onDragEnd(event: PointerEvent): void {
this.droppableService.onDragEnd(event);
}
}
import { Directive, ElementRef, EventEmitter, HostBinding, HostListener,
OnInit, Output, SkipSelf } from '@angular/core';
import { DroppableService } from '../_services/droppable.service';
@Directive({
selector: '[appDropzone]',
providers: [DroppableService]
})
export class DropzoneDirective implements OnInit {
@HostBinding('class.dropzone-activated') activated = false;
@HostBinding('class.dropzone-entered') entered = false;
@Output() drop = new EventEmitter<PointerEvent>();
@Output() remove = new EventEmitter<PointerEvent>();
private clientRect: ClientRect;
constructor(@SkipSelf() private allDroppableService: DroppableService,
private innerDroppableService: DroppableService,
private element: ElementRef) { }
ngOnInit(): void {
this.allDroppableService.dragStart$.subscribe(() => this.onDragStart());
this.allDroppableService.dragEnd$.subscribe(event =>
this.onDragEnd(event));
this.allDroppableService.dragMove$.subscribe(event => {
if (this.isEventInside(event)) {
this.onPointerEnter();
} else {
this.onPointerLeave();
}
});
this.innerDroppableService.dragStart$.subscribe(() =>
this.onInnerDragStart());
this.innerDroppableService.dragEnd$.subscribe(event =>
this.onInnerDragEnd(event));
}
private onPointerEnter(): void {
if (!this.activated) {
return;
}
this.entered = true;
}
private onPointerLeave(): void {
if (!this.activated) {
return;
}
this.entered = false;
}
private onDragStart(): void {
this.clientRect = this.element.nativeElement.getBoundingClientRect();
this.activated = true;
}
private onDragEnd(event: PointerEvent): void {
if (!this.activated) {
return;
}
if (this.entered) {
this.drop.emit(event);
}
this.activated = false;
this.entered = false;
}
private onInnerDragStart() {
this.activated = true;
this.entered = true;
}
private onInnerDragEnd(event: PointerEvent) {
if (!this.entered) {
this.remove.emit(event);
}
this.activated = false;
this.entered = false;
}
private isEventInside(event: PointerEvent) {
return event.clientX >= this.clientRect.left &&
event.clientX <= this.clientRect.right &&
event.clientY >= this.clientRect.top &&
event.clientY <= this.clientRect.bottom;
}
}
import { AfterContentInit, ContentChildren, Directive, ElementRef, QueryList
} from '@angular/core';
import { MovableDirective } from './movable.directive';
import { Subscription } from 'rxjs';
interface Boundaries {
minX: number;
maxX: number;
minY: number;
maxY: number;
}
@Directive({
selector: '[appMovableArea]'
})
export class MovableAreaDirective implements AfterContentInit {
@ContentChildren(MovableDirective) movables: QueryList<MovableDirective>;
private boundaries: Boundaries;
private subscriptions: Subscription[] = [];
constructor(private element: ElementRef) {}
ngAfterContentInit(): void {
this.movables.changes.subscribe(() => {
this.subscriptions.forEach(s => s.unsubscribe());
this.movables.forEach(movable => {
this.subscriptions.push(movable.dragStart.subscribe(() =>
this.measureBoundaries(movable)));
this.subscriptions.push(movable.dragMove.subscribe(() =>
this.maintainBoundaries(movable)));
});
});
this.movables.notifyOnChanges();
}
private measureBoundaries(movable: MovableDirective) {
const viewRect: ClientRect =
this.element.nativeElement.getBoundingClientRect();
const movableClientRect: ClientRect =
movable.element.nativeElement.getBoundingClientRect();
this.boundaries = {
minX: viewRect.left - movableClientRect.left + movable.position.x,
maxX: viewRect.right - movableClientRect.right + movable.position.x,
minY: viewRect.top - movableClientRect.top + movable.position.y,
maxY: viewRect.bottom - movableClientRect.bottom + movable.position.y
};
}
private maintainBoundaries(movable: MovableDirective) {
movable.position.x = Math.max(this.boundaries.minX, movable.position.x);
movable.position.x = Math.min(this.boundaries.maxX, movable.position.x);
movable.position.y = Math.max(this.boundaries.minY, movable.position.y);
movable.position.y = Math.min(this.boundaries.maxY, movable.position.y);
}
}
如果这种方法是错误的,那么请建议正确的方法使其工作
用于将blob转换为图像并将其作为blob上载的代码
我得到的数据的引用
"<div xmlns="http://www.w3.org/1999/xhtml" _ngcontent-c18="" appdropzone=""
appmovablearea="" class="dropzone image-area"
id="toget" ng-reflect-ng-style="[object Object]" style="width: 100%;
background-image:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALoAA
AC6CAMAAAAu0KfDAAAAwFBMVEX//XkFi/hkn/9ySZhLa0CgAAAAABJRU5ErkJggg==");
background-repeat: no-repeat; background-position: center center; back
ground-size: 100% 100%;"><!--bindings={
"ng-reflect-ng-for-of": ""
}--><div _ngcontent-c18="" appdroppable="" appmovable=""
class="box draggable movable ng-star-inserted" touch-action="none"
style="transform: translateX(136.8px) translateY(112.8px);"> vav18 </div>
</div>"
downloadImageFromBlob('abc', (err, data) => {
if (data) {
this.url = data.split('url("')[1].split('"); background-
repeat: no-repeat;')[0];
data = data.replace(/"/g,'')
this.myHtmlString = data;
}
}
<div id="existing" *ngIf="!abc" class="image-area"
[innerHTML]="myHtmlString | safeHtml"></div>
uploadImage(): void {
var svgString = new
XMLSerializer().serializeToString(document.getElementById('toget'));
var svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8"
});
let file = this.fileUploadService.convertToFile(svgBlob, "floorPlan.svg");
}
“vav18
"
下载ImageFromBlob('abc',(错误,数据)=>{
如果(数据){
this.url=data.split('url('')[1]。split('');背景-
重复:不重复;')[0];
数据=数据。替换(/“/g”“)
this.myHtmlString=数据;
}
}
uploadImage():void{
var svgString=new
XMLSerializer().serializeToString(document.getElementById('toget');
var svgBlob=newblob([svgString],{type:“image/svg+xml;charset=utf-8”
});
让file=this.fileUploadService.convertToFile(svgBlob,“floorPlan.svg”);
}
我推荐一种稍微不同的解决方案:您可以将对象添加到SVG中,而不是将其作为SVG上的精灵进行管理
粗略的程序大纲:
g
element)。确保它位于现有SVG元素之上(在之后绘制)。这是您希望在指令中保留句柄的内容rect
元素添加到新组中。您已经获得了定位逻辑,但需要对其进行转换,以了解SVG的缩放和viewporting- 尝试一个支持NG的SVG操作库。我还没有检查,但肯定有一个。这可以节省您编写指令包装器的时间
- 研究一个映射解决方案。也许可以尝试使用来自的NG包装器提示。除了实际绘制地图之外,管理带有其他精灵的基本矢量图像正是映射解决方案所做的。无需重新发明轮子。只需重定向从某个世界地图提供商读取的地图即可获取SVG
- 我做了一个评论来尝试,很多人都用它来注释地图。从他们的图库中已经完成了你的部分工作。我无法想象D3没有一个可用的NG包装器
- 把一切都放在一个H中