gpt4 book ai didi

javascript - Paper.js背景栅格化故障

转载 作者:行者123 更新时间:2023-11-29 21:39:16 24 4
gpt4 key购买 nike

我们正在使用Paper.js构建各种图像编辑器。我们在Paper.js画布的一侧有一个队列,可以在图像之间进行切换。每次在图像之间切换时,我们都希望将所有注释平整化(光栅化)到刚编辑的图像上。

每次切换图像时,都会调用此方法,该方法会将当前图像和注释光栅化为数据URL。 (如果我们重新访问该图像,将显示该数据URL中的栅格。)

var flattenToDataUrl = function() {
layerAsRaster = paper.project.layers[0].rasterize(); // Layer to Paper.js Raster object
layerAsRaster.visible = false; // Attempt to set not visible
var dataString = layerAsRaster.toDataURL();
return dataString;
};


然后,我们最终调用此方法,该方法将更改正在编辑的图像:

var setCanvasImage = function(imageObject) {
if(imageObject != null)
{
imageHeight = imageObject.height;
var imageWidth = imageObject.width;

// Set up HTMLImage
var imageElement = new Image(imageObject.width, imageObject.height);
if(_.has(imageObject, 'imageData')) { // Came as 64 bit data
imageElement.src = 'data:image/png;base64,' + imageObject.imageData;
} else if(_.has(imageObject, 'imageUrl')) { // Came as URL
imageElement.src = imageObject.imageUrl;
}

// Add image to Paper.js canvas
imageElement.onload = function(event) {

// Initialize Paper.js on the canvas
paper.setup(canvas);

raster = new paper.Raster(imageElement, new paper.Point(canvas.width / 2, canvas.height / 2));

setUpNotes();

selectedItems = new paper.Group(); // Since Paper.js has been setup we can now initialize this Group
registerCanvasEvents(); // Panning, zooming, moving selected items, deselecting all selected items

fitToPage();
};
}
};


因此,这会改变图像,但是当我在队列中选择其他图像后将鼠标移到画布中时,它会向刚刚显示的图像(带有注释)移动,直到执行平移,缩放等操作为止然后,我看到了我选择的图像并且正在使用它。

删除 flattenToDataUrl()功能可使队列无缝工作。因此在我看来那里有些可疑。我们正在通过该方法生成一个Paper.js Raster对象。栅格似乎会自动添加自己。我试图通过致电来遏制

layerAsRaster.visible = false;


但无济于事。

是什么原因导致这种故障现象,我该如何预防?

更新资料

为了清晰(希望如此)和完整性,我决定发布整个与React一起使用的PaperFunctions类,该类托管了我们的 <canvas>元素。这里有很多代码,还有很多清理工作,尤其是在 registerCanvasEvents()中。忍受这个学习初学者。而且它有几百行,因此将其粘贴到您喜欢的编辑器中可能会有所帮助。入口点包括 setCanvas(在带有 componentDidMount元素的React类的 <canvas>中调用)和 canvasSetImage(从队列中调用)。我同意bmacnaughton的回答,每次加载新图像时都调用 paper.setup(canvas)很奇怪。我目前正在研究正确的解决方案,正确的放置位置。 setCanvas似乎合乎逻辑,但是当我拖动图像以在该设置中移动图像时,它会留下一丝图像痕迹。无论如何,这是PaperFunctions.js:

var JQueryMousewheel = require('jquery-mousewheel')($);

var SimplePanAndZoom = require('./SimplePanAndZoom.js');
var panAndZoom = new SimplePanAndZoom();

var selectedItems;

// We use selection here in two distinct ways.
// An item may be Paper.js selected but not in the selection group.
// This is because we want to show it is selectable.
// A blue bounding box indicates it is selectable.
// A green bounding box indicates it has actually been selected and added to selectedItems.
// Only things in selectedItems are actually operated on.
// So the event handlers in this method basically set up whether or not the item is in selectedItems (and therefore will be operated on for moving, resizing, deleting, etc.).
// That is, the event handlers here are concerned with displaying to the user the status of selection for the item - whether or not it will be operated on when events actually happen on the selectedItems Group.
var registerItemEvents = function(item) {
// Boolean flag for mouseup to know if was drag or click
var dragged;

// For tracking if dragging or clicking is happening
item.on('mousedown', function(e) {
dragged = false;
});

// On click toggle selection
item.on('mouseup', function(event) {
event.stopPropagation(); // Only for item applied to
event.preventDefault();

if(!dragged) {
var justAdded = addIfNotInSelectedItems(item);
if(!justAdded) { // Item was in selection group, remove it
item.remove();
paper.project.activeLayer.addChild(item);

this.selectedColor = paper.project.activeLayer.selectedColor;
//item.selected = false;
}
}
});

// Show as selectable even after has been deselected
item.on('mousemove', function(event) {
this.selected = true;
})

// If not selected, on mouse enter show that it is selectable
item.on('mouseenter', function(event) {
if(!this.selected) {
this.selected = true;
}
});

// If not selected, on mouse leave remove indicator that is selectable
item.on('mouseleave', function(event) {
var isInSelectedItems = selectedItems.getItem(item);
if(this.selected && isInSelectedItems == null) {
this.selected = false;
}
});

// On drag, move item
item.on('mousedrag', function(event) {
dragged = true;

// If user starts dragging automatically select the item
addIfNotInSelectedItems(item);
});
}

var addIfNotInSelectedItems = function(item) {
var isInSelectedItems = selectedItems.getItem(item);
if(isInSelectedItems == null) { // Item not currently in selection group, add it
selectedItems.addChild(item);
item.selectedColor = 'green';
item.selected = true;
return true; // Was added, return true
} else {
return false; // Already in, return false
}
}

var registerCanvasEvents = function() {
if(paper.view != null && canvas != null) {
// Zoom on mousewheel
$(canvas).mousewheel(function(event) {
event.preventDefault();
var mousePosition = new paper.Point(event.offsetX, event.offsetY);
var viewPosition = paper.view.viewToProject(mousePosition);
var returnedValues = panAndZoom.changeZoom(paper.view.zoom, (event.deltaY * -1), paper.view.center, viewPosition, 1.1);
var newZoom = returnedValues[0];
var offset = returnedValues[1];
paper.view.zoom = newZoom;
paper.view.center = paper.view.center.add(offset);
});

// For tracking if dragging or clicking is happening
var dragged;
paper.project.layers[0].on('mousedown', function(e) { // TODO should be layer 0 in long run?
dragged = false;
});


// Pan on mouse drag
/*paper.project.layers[0].on('mousedrag', function(event) { // TODO should be layer 0 in long run?
if(!event.event.ctrlKey && !event.event.altKey && !event.event.shiftKey) { // No keys (that we use) can be pushed
dragged = true; // We're panning, we don't wish to deselect all items as we would do with a click
paper.view.center = panAndZoom.changeCenter(paper.view.center, event.delta.x, event.delta.y, 0.7);
//event.preventDefault();
}
});*/

// Move selected items on mouse drag
selectedItems.on('mousedrag', function(event) {
event.stopPropagation(); // Don't propogate up or it will register as a pan event
event.preventDefault();

dragged = true; // We're panning, we don't wish to deselect all items as we would do with a click

this.translate(new paper.Point(event.delta.x, event.delta.y));
});

// If was a click and not a drag, deselect selected items
paper.project.layers[0].on('mouseup', function(event) {
if(!dragged) {
var removedItems = selectedItems.removeChildren(); // Remove from selection group, which also removes from display
paper.project.activeLayer.addChildren(removedItems); // Return to display

// Reset selection colors for showing selectable
for(var i =0; i < removedItems.length; i++) {
removedItems[i].selectedColor = paper.project.activeLayer.selectedColor;
removedItems[i].selected = false;
}
}
});

// Initial path object, will be reset for new paths after Alt is released
var path = newPath();
var paths = [];
paths.push(path);

// On mousedown add point to start from
paper.project.layers[0].on('mousedown', function(event) {
if(event.event.altKey && !event.event.ctrlKey) { // Alt key to add a path, but disallow attempting to add text at the same time
if(paths[paths.length-1].lastSegment == null) {
//path.add(event.point, event.point);
paths[paths.length-1].add(event.point, event.point);
} else {
//path.add(path.lastSegment.point, path.lastSegment.point);
paths[paths.length-1].add(paths[paths.length-1].lastSegment.point, paths[paths.length-1].lastSegment.point);
}
}
});

// On mousedrag add points to path
paper.project.layers[0].on('mousedrag', function(event) {
if(event.event.altKey && !event.event.ctrlKey) { // Alt key to add a path, but disallow attempting to add text at the same time
if(event.event.shiftKey) { // Use shift key for freeform
//path.add(event.point);
paths[paths.length-1].add(event.point);
} else { // Default of straight line added to path
//path.lastSegment.point = event.point;
paths[paths.length-1].lastSegment.point = event.point;
}
}
}.bind(this));

var tool = new paper.Tool();

var startDragPoint;

// Capture start of drag selection
paper.tool.onMouseDown = function(event) {
if((event.event.ctrlKey && event.event.shiftKey) || (event.event.ctrlKey && event.event.altKey)) {
startDragPoint = new paper.Point(event.point);
}
};

paper.tool.onMouseDrag = function(event) {
// Panning
if(!event.event.ctrlKey && !event.event.altKey && !event.event.shiftKey) { // No keys (that we use) can be pushed
dragged = true; // We're panning, we don't wish to deselect all items as we would do with a click
paper.view.center = panAndZoom.changeCenter(paper.view.center, event.delta.x, event.delta.y, 0.7);
//event.preventDefault();
}

// Show box indicating the area that has been selected
// For moving area and whiting out area
if((event.event.ctrlKey && event.event.shiftKey) || (event.event.ctrlKey && event.event.altKey)) {
dragged = true;
var showSelection = new paper.Path.Rectangle({
from: startDragPoint,
to: event.point,
strokeColor: 'red',
strokeWidth: 1
});

// Stop showing the selected area on drag (new one is created) and up because we're done
showSelection.removeOn({
drag: true,
up: true
});
}
};

// Capture start of drag selection
paper.tool.onMouseUp = function(event) {
if((event.event.ctrlKey && event.event.shiftKey) || (event.event.ctrlKey && event.event.altKey)) {
var endDragPoint = new paper.Point(event.point);
if(event.event.ctrlKey && event.event.shiftKey) { // Whiteout area
whiteoutArea(startDragPoint, endDragPoint);
} else if(event.event.ctrlKey && event.event.altKey) { // Move selected area
selectArea(startDragPoint, endDragPoint);
}
}
};

// Key events
paper.tool.onKeyUp = function(event) {
// Delete selected items on delete key
if(event.key == 'delete') {
selectedItems.removeChildren();
} else if (event.key == 'option') {
registerItemEvents(paths[paths.length-1]);

// Start a new path
paths.push(newPath());
}
}
}
}

// These variables are scoped so that all methods in PaperFunctions can access them
var canvas; // Set by setCanvas
var imageHeight; // Set by setCanvasImage

var raster;

var toolsSetup = false;

var setCanvas = function(canvasElement) {
canvas = canvasElement;
paper.setup(canvas);
};

var setCanvasImage = function(imageObject) {
if(imageObject != null)
{
imageHeight = imageObject.height;
var imageWidth = imageObject.width;

// Set up HTMLImage
var imageElement = new Image(imageObject.width, imageObject.height);
if(_.has(imageObject, 'imageData')) { // Came as 64 bit data
imageElement.src = 'data:image/png;base64,' + imageObject.imageData;
} else if(_.has(imageObject, 'imageUrl')) { // Came as URL
imageElement.src = imageObject.imageUrl;
}

// Add image to Paper.js canvas
imageElement.onload = function(event) {
//canvas.height = $(document).height()-3; // Set canvas height. Why do this here and not in the React component? Because we set the width here too, so we're keeping those together. Perhaps in the future this will be changed when we are responsive to window resizing.
//scalingFactor = canvas.height / imageObject.height; // Determine the ratio
//canvas.width = imageElement.width * scalingFactor; // Scale width based on height; canvas height has been set to the height of the document

// Initialize Paper.js on the canvas
paper.setup(canvas);

raster = new paper.Raster(imageElement, new paper.Point(canvas.width / 2, canvas.height / 2));

//setUpLineAndFreeFormDrawing(); // TODO once we cycle through images will we need to reset this for each new image or can we do this just once?

setUpNotes(); // TODO once we cycle through images will we need to reset this for each new image or can we do this just once?

selectedItems = new paper.Group(); // Since Paper.js has been setup we can now initialize this Group
registerCanvasEvents(); // Panning, zooming, moving selected items, deselecting all selected items

fitToPage();
};
}
};

var fitToPage = function() {
if(paper.view != null && canvas != null) {
// Fit image to page so whole thing is displayed
var scalingFactor = canvas.height / imageHeight; // Constant representation of the ratio of the canvas size to the image size
var zoomFactor = scalingFactor / paper.view.zoom; // Dynamic representation of the zoom needed to return to viewing the whole image in the canvas

// Reset the center point to the center of the canvas
var canvasCenter = new paper.Point(canvas.width/2, canvas.height/2);
paper.view.center = canvasCenter;

// Zoom to fit the whole image in the canvas
var returnedValues = panAndZoom.changeZoom(paper.view.zoom, -1, canvasCenter, canvasCenter, zoomFactor); // Always pass -1 as the delta, not entirely sure why
var newZoom = returnedValues[0];
var offset = returnedValues[1];
paper.view.zoom = newZoom;
paper.view.center = paper.view.center.add(offset);
}
};

var addImage = function(imageDataUrl) {
if(paper.view != null) {
var img = document.createElement("img");
img.src = imageDataUrl;
var presentMomentForId = new Date().getTime() + "-image"; // For purposes of having unique IDs
img.id = presentMomentForId;
img.hidden = true;
document.body.appendChild(img);

var raster = new paper.Raster(presentMomentForId);

registerItemEvents(raster);
}
};

var setUpLineAndFreeFormDrawing = function() {
if(paper.project != null) {
// Initial path object, will be reset for new paths after Alt is released
var path = newPath();
var paths = [];
paths.push(path);

// On mousedown add point to start from
paper.project.layers[0].on('mousedown', function(event) {
if(event.event.altKey && !event.event.ctrlKey) { // Alt key to add a path, but disallow attempting to add text at the same time
if(paths[paths.length-1].lastSegment == null) {
//path.add(event.point, event.point);
paths[paths.length-1].add(event.point, event.point);
} else {
//path.add(path.lastSegment.point, path.lastSegment.point);
paths[paths.length-1].add(paths[paths.length-1].lastSegment.point, paths[paths.length-1].lastSegment.point);
}
}
});

// On mousedrag add points to path
paper.project.layers[0].on('mousedrag', function(event) {
if(event.event.altKey && !event.event.ctrlKey) { // Alt key to add a path, but disallow attempting to add text at the same time
if(event.event.shiftKey) { // Use shift key for freeform
//path.add(event.point);
paths[paths.length-1].add(event.point);
} else { // Default of straight line added to path
//path.lastSegment.point = event.point;
paths[paths.length-1].lastSegment.point = event.point;
}
}
}.bind(this));

// Each time Alt comes up, start a new path
paper.tool.onKeyUp = function(event) {
if(event.key == "option") {
registerItemEvents(paths[paths.length-1]);

// Start a new path
paths.push(newPath());
}
};
}
};

// Establishes default line style
var newPath = function() {
var path = new paper.Path();
path.strokeColor = 'black';
path.strokeWidth = 10;
return path;
};

var note = "";
var setNote = function(newNote) {
note = newNote;
};

var setUpNotes = function() {
if(paper.project != null) {
paper.project.layers[0].on('mousedown', function(event) { // TODO should be layer 0 in long run?
if(event.event.ctrlKey && !event.event.altKey && !event.event.shiftKey) { // Only Ctrl key to add text

// Add text box
var textBox = new paper.PointText(event.point);
textBox.justification = 'left';
textBox.fillColor = 'black';
textBox.fontSize = 60;
textBox.content = note;

registerItemEvents(textBox);
}
});
}
};

var selectArea = function(startDragPoint, endDragPoint) {
var rasterTopLeftCorner = new paper.Point(raster.bounds.topLeft);
var adjustedStartDragPoint = new paper.Point(startDragPoint.x - rasterTopLeftCorner.x, startDragPoint.y - rasterTopLeftCorner.y);
var adjustedEndDragPoint = new paper.Point(endDragPoint.x - rasterTopLeftCorner.x, endDragPoint.y - rasterTopLeftCorner.y);
var boundingRectangleRasterCoordinates = new paper.Rectangle(adjustedStartDragPoint, adjustedEndDragPoint);
var boundingRectangleCanvasCoordinates = new paper.Rectangle(startDragPoint, endDragPoint);

var selectedArea = raster.getSubRaster(boundingRectangleRasterCoordinates);

var whitedOutSelection = new paper.Shape.Rectangle(boundingRectangleCanvasCoordinates);
whitedOutSelection.fillColor = 'white';
whitedOutSelection.insertAbove(raster); // Whiteout just above the image we're working with

registerItemEvents(selectedArea);
}

var whiteoutArea = function(startDragPoint, endDragPoint) {
var whitedOutSelection = new paper.Shape.Rectangle(startDragPoint, endDragPoint);
whitedOutSelection.fillColor = 'white';
whitedOutSelection.insertAbove(raster); // Whiteout just above the image we're working with
}

var flattenToDataUrl = function() {
layerAsRaster = paper.project.layers[0].rasterize(); // TODO should be layer 0 in long run? // Layer to Paper.js Raster object
layerAsRaster.visible = false;
var dataString = layerAsRaster.toDataURL();
return dataString;
};

module.exports = {
setCanvas: setCanvas,
setCanvasImage: setCanvasImage,
fitToPage: fitToPage,
addImage: addImage,
setNote: setNote,
flattenToDataUrl: flattenToDataUrl
};


另外,为清晰起见,这是SimplePanAndZoom.js文件。它使用最少的Paper函数,主要是进行计算:

// Based on http://matthiasberth.com/articles/stable-zoom-and-pan-in-paperjs/

var SimplePanAndZoom = (function() {
function SimplePanAndZoom() { }

SimplePanAndZoom.prototype.changeZoom = function(oldZoom, delta, centerPoint, offsetPoint, zoomFactor) {
var newZoom = oldZoom;
if (delta < 0) {
newZoom = oldZoom * zoomFactor;
}
if (delta > 0) {
newZoom = oldZoom / zoomFactor;
}

// Zoom towards offsetPoint, not centerPoint (unless they're the same)
var a = null;
if(!centerPoint.equals(offsetPoint)) {
var scalingFactor = oldZoom / newZoom;
var difference = offsetPoint.subtract(centerPoint);
a = offsetPoint.subtract(difference.multiply(scalingFactor)).subtract(centerPoint);
}

return [newZoom, a];
};

SimplePanAndZoom.prototype.changeCenter = function(oldCenter, deltaX, deltaY, factor) {
var offset;
offset = new paper.Point(-deltaX, -deltaY);
offset = offset.multiply(factor);
return oldCenter.add(offset);
};

return SimplePanAndZoom;

})();

module.exports = SimplePanAndZoom;


谢谢。

最佳答案

我在这里进行一些猜测,但是我将解决代码中的一些问题,这些问题有望解决您所看到的行为。

首先,我假设paper.project.layers[0]paper.project.activeLayer。一旦将其栅格化1)将栅格添加到图层,并且设置visible = false确实会导致它在更新完成后消失。

其次,当您在paper.setup(canvas)中调用imageElement.onload时,将创建一个新的纸张项目。该项目从活动项目开始,使先前的项目“消失”。因此,当您使用raster = new paper.Raster(...)创建栅格时,它将进入新项目,而不是旧项目。

因此,现在在旧项目中有一个隐藏(.visible = false)栅格(我们将其称为project1),在project2中有一个新版本。

我不确定这是否是预期的行为,但是当您第二次调用paper.setup(canvas)时,纸张似乎注意到它们都引用相同的画布并且使project1和project2保持同步。因此,创建第二个项目将清除第一个项目的子数组。添加new paper.Raster(...)最终将栅格添加到project1和project2。

现在我无法说出下一个难题是什么。您需要添加一些信息,例如1)设置鼠标事件处理程序的位置以及它们的附加内容; 2)setUpNotes()的作用; 3)registerCanvasEvents()的作用; 4)fitToPage的作用。

创建了一些全局变量,imageHeightraster可能不是故意的。目前尚不清楚为什么需要使用new Image()-paper.Raster()接受URL,包括数据URL。

我很惊讶纸清除了第一个项目。很好奇

版本2:

让我刺破使用层来构造它。我建议您摆脱多个项目,因为将鼠标事件处理程序附加到共享同一画布的多个项目会增加太多的复杂性。

因此,在代码初始化中:paper.setup(canvas)。只能这样做一次。

在最初由纸张创建的单层中设置初始图像。

// this will be inserted into the current layer, project.activeLayer
var raster = new paper.Raster(imageURL, paper.view.bounds.center);


当队列中的图像更改时,请执行以下操作:

// make the existing image/layer invisible
paper.project.activeLayer.visible = false;

// add a new layer which is inserted in the project and activated
var layer = new paper.Layer();

// the new layer is activated, create a raster for the image
var raster = new paper.Raster(imageURL, paper.view.bounds.center);

// now do your normal logic for editing, zooming, etc.


确实比这复杂一点,因为您有一个图像队列,并且只想在第一次访问图像时创建一个图层。您可以在一开始就初始化所有栅格,例如:

var imageURLs = ["url to image1", "url to image2", "etc"];
imageURLs.forEach(function(url) {
new paper.Layer();
paper.project.activeLayer.visible = false;
new paper.Raster(url, paper.view.bounds.center);
});
// make the first layer visible and activate it
paper.project.layers[0].visible = true;
paper.project.layers[0].activate();


前面的代码为您提供了队列中图像的并行数组,因此切换图像非常简单-无需检查该图像是否已创建:

function setImage(index) {
paper.project.activeLayer.visible = false;
paper.project.layers[index].activate();
paper.project.layers[index].visible = true;
}


最后,我将确保鼠标操作不会引起问题。从您发布的新代码中,看起来每个项目都有一个全局工具来处理“ mousedown”,“ mousedrag”和“ mouseup”事件,为 activeLayer的另一组处理程序分别用于“ mousedown”,“ mousedrag”和“ mouseup”事件,并且 selectedItems也具有“ mousedrag”的处理程序。我无法跟踪所有不同的处理程序在项目中应该做什么。我猜这是您所看到的闪烁的根本原因。

我可能只将 paper.view.on用于'mousedown','mousedrag'和'mouseup'事件。当我得到一个事件时,我将使用以下命令检查该图层上是否有任何东西被击中:

paper.project.activeLayer.hitTest(event.point);


能够在视图上设置事件对于纸张来说是新事物,但非常有用。可能还需要进行一些其他调整,以突出显示未选中的项目。一种相对简单的处理方法是拥有一组选定项和一组未选定项:

unSelectedGroup.on('mouseenter', function() {
unSelectedGroup.selected = true;
});

unSelectedGroup.on('mouseleave', function() {
unSelectedGroup.selected = false;
});


当一次仅可见一层时,这些层在跨层上应该是安全的。设置图像时,我会设置这些组处理程序,无论是预先放置还是根据需要。另外,您也可以添加 paper.view.on('mousemove', ...)并使用 hitTest自己处理'mouseenter'和'mouseleave'事件,如上所示,但是任何一种方法都应该起作用。

我认为对图像使用基于图层的方法可以使事物保持同步。基于项目的方法和许多不同的鼠标事件处理程序存在足够的问题,无论如何您都会处于更稳定的状态。

关于javascript - Paper.js背景栅格化故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33682575/

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