gpt4 book ai didi

html - 保持对背景图像的响应以及完整的拖放元素并响应背景图像

转载 作者:太空狗 更新时间:2023-10-29 18:00:12 37 4
gpt4 key购买 nike

我有一个工作堆栈闪电战:https://stackblitz.com/edit/dynamic-component-example-1rvd1p
我已经在DIV包含的背景图像中编写了角度和落下元素的自定义拖放事件。我的目标是使div元素响应,保持新的被丢弃元素的位置对背景图像的完整性,从而也与背景图像成比例地响应。
我试着给父容器和子容器指定位置,这样父div就会响应,但是子元素(丢弃的元素)不会与父背景图像保持完整,也不会成比例。
换言之,当图像将缩小或放大时,子元素(删除的元素)也应按比例增加和减少大小,以保持其位置与图像的完整性。
这是拖放工作参考
https://stackblitz.com/edit/draggable-part-6?file=app%2Fapp.component.ts

 <div class="dropzone" appDropzone appMovableArea (drop)="move(currentBox, 
dropzone1)" [ngStyle]="{'width':'100%','background-image':
'url('+url+')', 'background-repeat': 'no-repeat', 'background-position':
'center', 'background-size': '100% 100%'}">
<div *ngFor="let box of dropzone1" class="box"
appDroppable (dragStart)="currentBox = box" appMovable>
{{ box.dis }}
<!--<div class="box" *appDraggableHelper>{{ box }}</div>-->
</div>
</div>


_____________________________________________________________
| _______ background image |
| | | |
| | | => dropped elements |
| |_______| _______ |
| | | |
| | | |
| |_______| |
|____________________________________________________________|

CSS
.dropzone {
padding: 20px;
margin: 20px 0;
background: lightgray;
min-height: 200px;
border: 1px solid black;
&.dropzone-activated {
border: 1px solid red;
}

&.dropzone-entered {
background-color: #efefef;
}
}

指令
可拖放指令
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);
}

}

dropzone.指令
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);
}
}

组件
  dropzone1 = [];

currentBox?: string;

move(box: string, toList: string[]): void {

this.removeBox(box, this.rooms);
this.removeBox(box, this.dropzone1);

toList.push(box);
}

removeBox(item: string, list) {
if (list.indexOf(item) !== -1) {
list.splice(list.indexOf(item), 1);
}
}

如果这种方法是错误的,那么请建议正确的方法使其发挥作用。
将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(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALoAA
AC6CAMAAAAu0KfDAAAAwFBMVEX//XkFi/hkn/9ySZhLa0CgAAAAABJRU5ErkJggg==&quot;);
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(&quot;')[1].split('&quot;); background-
repeat: no-repeat;')[0];
data = data.replace(/&quot;/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");
}

最佳答案

我推荐一个稍微不同的解决方案:您可以将对象添加到svg中,而不是将它们作为svg上的精灵来管理。
粗略的程序纲要:
请确保使用svg基本文件的副本,因为您要修改它。我想你已经在做了。
使用您的ng服务添加组(g元素)。确保它位于上面的(绘制)现有SVG元素。这是您希望在指令中保留的句柄。
拖放时,将svgrect元素添加到新组中。您已经有了定位逻辑,但需要对其进行转换,以了解SVG缩放和视图移植。
使用svg的事件将事件冒泡到ng中。这应该能够被包装在一个NG指令很容易,因为SVG真的只是HTML,生活在您的文档。
此时,您应该能够将move和scale事件重定向到svg缩放和viewporting。也就是说,在重新缩放时,只需重新缩放svg。你掉下来的盒子将与其余的绘图一起重新缩放。
有几件事可以让你更容易做到:
尝试一个支持ng的svg操作库。我还没检查,但肯定有一个在外面。这可以节省编写指令包装器的时间。
研究映射解决方案。可以尝试使用Leaflet中的ng包装提示here。除了实际绘制地图之外,管理带有附加精灵的基向量图像正是映射解决方案所要做的。不需要重新发明轮子。只需重定向从某个世界地图提供者读取的地图即可获取SVG。
我发表了一条评论,试图尝试D3,很多人都用它来注释地图。This simple example他们的画廊已经做了你的一部分工作。我无法想象d3没有一个工作的ng包装器。
希望里面的东西能帮到你。
更新(回答的评论中的一些问题)
在D3或其他库上:添加另一个库会影响性能,特别是会减慢性能。当您添加更多运行的代码时,总是这样。
我认为更好的问题是,“如果我添加另一个库,我的性能是否会降低到可接受的水平以下?”这取决于库、库的一些细节(比如从何处加载以及如何使用库)以及可接受的性能级别。我不相信编写代码从一开始就是最终表现:编写可维护代码并优化特定的东西以满足特定的要求。这就是说,链接到一个图书馆是很愚蠢的,这个图书馆使用任何合理的标准,都会明显地破坏性能。
如果您的项目已经加载了d3,特别是如果您(个人)对它不太熟悉,请注意,编写代码可能需要一个非常好的库,并使它比必须做的事情做得更多。这会毁了你的表演。这种情况也最有可能成为图书馆的首次消费者。如果你的项目中有人知道d3,我建议你征集他们的帮助,至少在你完成代码评审后。
在纯html/css/js中执行此操作:当然这是可能的。您已经开始执行其中的一个。
有一个解决方案,需要更少的JS,涉及CSS剪辑和转换。它们的行为与svg视口和转换非常相似,但它们附带了更密集的代码列表。也就是说,您必须在一行css中完成可以分布在许多svg元素和属性上的工作。这将使调试和维护更加复杂。考虑到你原来的职位,你最大的问题就是调试。考虑到问题答案的数量和质量(截至本次编辑),似乎没有人真的想帮助您调试。如果我处在你的位置,我会专注于可维护性和调试能力,以便完成你的项目。
这就是说,总的想法是:
将所有内容放在一个htmldiv中。
把你的元素放在里面,从SVG开始,然后绿色盒子放在上面。你已经这样做了。如果您尚未操作z-order,则可能需要对其进行操作。
通过让js直接在父节点上更改cssclip rectangletransform scaling来响应事件(滚动和缩放)。
使用这个,父div中的所有内容都应该平移或缩放。当然,那你就回到你原来的问题了。

关于html - 保持对背景图像的响应以及完整的拖放元素并响应背景图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57165744/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com