- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个工作堆栈闪电战: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 |
| |_______| _______ |
| | | |
| | | |
| |_______| |
|____________________________________________________________|
.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);
}
}
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);
}
}
"<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");
}
最佳答案
我推荐一个稍微不同的解决方案:您可以将对象添加到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 rectangle和transform scaling来响应事件(滚动和缩放)。
使用这个,父div
中的所有内容都应该平移或缩放。当然,那你就回到你原来的问题了。
关于html - 保持对背景图像的响应以及完整的拖放元素并响应背景图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57165744/
我正在尝试检查 Entry 中是否存在重复项,并使用内联消息提醒用户该数字存在。 $(document).ready(function(){ $("#con1").blur(function(
我有一个基于类的 View 。我在引导模式上使用 Ajax。为了避免页面刷新,我想使用此类基于 View 返回 JSON 响应而不是 HTTP 响应,但我只看到了如何为基于函数的 View 返回 JS
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我有一个大型内部企业基于 Web 的应用程序在 IIS6 上运行 ASP.NET 3.5,生成 401 个“未经授权”响应,然后是 200 个“Ok”响应(如 Fiddler 所述)。我知道为什么会发
感谢您研究我的问题。 我有一个node/express服务器,配置了一个server.js文件,它调用urls.js,而urls.js又调用 Controller 来处理http请求,所有这些都配置相
当我使用以下命令时,我得到正确的 JSON 响应: $ curl --data "regno=&dob=&mobile=" https://vitacademics-rel.herokuapp.co
我有一个非常简单的 RESTful 服务,它通过 POST 接收一些表单数据,其目的是在云存储(Amazon S3、Azure Blob 存储等)中简单地保留文本主体(具有唯一 ID)作为一个文件..
UDP 不发送任何 ack,但它会发送任何响应吗? 我已经设置了客户端服务器UDP程序。如果我让客户端向不存在的服务器发送数据,那么客户端会收到任何响应吗? 我的假设是; 客户端 --> 广播服务器地
我有一个电梯项目,其中 有一个扩展 RestHelper 的类,看起来像这样 serve{ "api" / "mystuff" prefix { case a
我们正在寻求覆盖 Kong 错误响应结构并编写自定义消息(即用我们的自定义消息替换“超出 API 速率限制”、“无效的身份验证凭据”等)。 我们要找的错误响应结构(代码是自定义的内部错误代码,与HTT
我正在尝试监听 EKEventStoreChangedNotification 以检查当我的应用程序处于后台时日历是否已更改。 我在 View Controller 的 initWithNibMeth
我了解 javascript,并且正在学习 ASP.NET C# 我想要做什么(完成的是javascript): document.getElementById('divID-1'
是否可以过滤所有 har 对象并仅获取 POST 请求/响应?也许在初始化 BrowserMobProxyServer 期间是这样做的方法?我需要将 har 对象保存到文件中并上传到 har 查看器。
我正在尝试向 Oauth 的 API 发送响应。遗憾的是,Symfony2 文档在解释 $response->headers->set(...); 的所有不同部分方面做得很差。 这是我的 OauthC
我正在尝试测试用例来模拟 api 调用,并使用 python 响应来模拟 api 调用。 下面是我的模拟, with responses.RequestsMock() as rsps: url
在尝试在 Haskell 中进行一些领域驱动设计时,我发现自己遇到了这个问题: data FetchAccessories = FetchAccessories data AccessoriesRes
我正在与 ANT+ USB 棒连接,并用项目 react 器替换我自己天真的“MessageBus”,因为它看起来非常合适。 USB接口(interface)本质上是异步的(单独的输入/输出管道),我
我正在将项目迁移到AFNetworking 2.0。使用AFNetworking 1.0时,我编写了代码来记录控制台中的每个请求/响应。这是代码: -(AFHTTPRequestOperation *
我有以下代码段。 ajaxRequest.onreadystatechange = function(){ if(ajaxRequest.readyState == 4){
我有问题......我在 php 中有一个监听器脚本可以执行以下操作: if ($count != 1) {echo 'no';} else { echo "yes";} 因此它会回显"is"或“
我是一名优秀的程序员,十分优秀!