Я думаю, что вы попали в проблему XY. В комментарии объясняется, что вам нужно, и вы спрашиваете, как сделать что-то, что, по вашему мнению, является способом обойти это.
Вы настраиваете конкретное приложение, которое клонирует холст в состоянии c представление на другом холсте, при каждом событии after: render.
Теперь свободный рисунок bru sh не вызывает событие after: render, и даже если это произошло, bru sh не отображается на вашем холст перед мышью: событие up.
Таким образом, чтобы решить вашу проблему, вы должны поместить bru sh на нижний холст, чтобы существующий код нашел его.
Это очень трудно сделать, потому что это значит возиться с внутренним логикой c библиотеки. Почему вы можете просто копировать верхний холст каждый раз, когда добавляется новый сегмент bru sh? это, очевидно, позволит вам достичь цели.
Мой ответ и фрагмент не идеальны и не учитывают прозрачные кисти, которые много раз просто копируют себя.
Другое решение будет иметь второй холст stati c поверх первого, для обработки этих средних этапов.
var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");
var ctx1 = c1.getContext("2d");
var ctx2 = c2.getContext("2d");
var canvas = this.__canvas = new fabric.Canvas(c1, {
isDrawingMode: true,
renderOnAddRemove: false
});
canvas.add(new fabric.Rect({ top: 100, left: 100, width: 50, height: 50, fill: '#f55' }),
new fabric.Circle({ top: 140, left: 130, radius: 75, fill: 'green' }),
new fabric.Triangle({ top: 100, left: 110, width: 100, height: 100, fill: 'blue' }))
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
},
{
crossOrigin: "Annoymous"
}
);
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom += delta / 500;
if (zoom > 10) zoom = 10;
if (zoom < 0.5) zoom = 0.5;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
this.requestRenderAll();
opt.e.preventDefault();
opt.e.stopPropagation();
});
fabric.StaticCanvas.prototype.drawCopyOnCanvas = function(canvasEl) {
// save values
var scaledWidth = this.width,
scaledHeight = this.height,
vp = this.viewportTransform,
originalInteractive = this.interactive,
newVp = [1, 0, 0, 1, 0, 0],
originalRetina = this.enableRetinaScaling,
originalContextTop = this.contextTop;
// reset
this.contextTop = null;
this.enableRetinaScaling = false;
this.interactive = false;
this.viewportTransform = newVp;
this.calcViewportBoundaries();
// draw on copy
this.renderCanvas(canvasEl.getContext('2d'), this._objects);
// restore values
this.viewportTransform = vp;
this.calcViewportBoundaries();
this.interactive = originalInteractive;
this.enableRetinaScaling = originalRetina;
this.contextTop = originalContextTop;
}
function afterRender() {
// remove 'after:render' listener as canvas.toCanvasElement()
// calls renderCanvas(), which results in an infinite recursion
canvas.off('after:render', afterRender);
// draw c1 contents on c2
canvas.drawCopyOnCanvas(c2);
setTimeout(() => {
// re-attach the listener in the next event loop
canvas.on('after:render', afterRender);
});
}
function copyThePencil() {
if (this._isCurrentlyDrawing) {
ctx2.save();
var m = fabric.util.invertTransform(this.viewportTransform);
ctx2.transform.apply(ctx2, m);
ctx2.drawImage(this.upperCanvasEl, 0, 0, this.upperCanvasEl.width / this.getRetinaScaling(), this.upperCanvasEl.height / this.getRetinaScaling())
ctx2.restore();
}
}
canvas.on('after:render', afterRender);
canvas.on('mouse:move', copyThePencil);
var $ = function(id){return document.getElementById(id)};
fabric.Object.prototype.transparentCorners = false;
var drawingModeEl = $('drawing-mode'),
drawingOptionsEl = $('drawing-mode-options'),
drawingColorEl = $('drawing-color'),
drawingShadowColorEl = $('drawing-shadow-color'),
drawingLineWidthEl = $('drawing-line-width'),
drawingShadowWidth = $('drawing-shadow-width'),
drawingShadowOffset = $('drawing-shadow-offset'),
clearEl = $('clear-canvas');
clearEl.onclick = function() { canvas.clear() };
drawingModeEl.onclick = function() {
canvas.isDrawingMode = !canvas.isDrawingMode;
if (canvas.isDrawingMode) {
drawingModeEl.innerHTML = 'Cancel drawing mode';
drawingOptionsEl.style.display = '';
}
else {
drawingModeEl.innerHTML = 'Enter drawing mode';
drawingOptionsEl.style.display = 'none';
}
};
if (fabric.PatternBrush) {
var vLinePatternBrush = new fabric.PatternBrush(canvas);
vLinePatternBrush.getPatternSrc = function() {
var patternCanvas = fabric.document.createElement('canvas');
patternCanvas.width = patternCanvas.height = 10;
var ctx = patternCanvas.getContext('2d');
ctx.strokeStyle = this.color;
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(0, 5);
ctx.lineTo(10, 5);
ctx.closePath();
ctx.stroke();
return patternCanvas;
};
var hLinePatternBrush = new fabric.PatternBrush(canvas);
hLinePatternBrush.getPatternSrc = function() {
var patternCanvas = fabric.document.createElement('canvas');
patternCanvas.width = patternCanvas.height = 10;
var ctx = patternCanvas.getContext('2d');
ctx.strokeStyle = this.color;
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(5, 10);
ctx.closePath();
ctx.stroke();
return patternCanvas;
};
var squarePatternBrush = new fabric.PatternBrush(canvas);
squarePatternBrush.getPatternSrc = function() {
var squareWidth = 10, squareDistance = 2;
var patternCanvas = fabric.document.createElement('canvas');
patternCanvas.width = patternCanvas.height = squareWidth + squareDistance;
var ctx = patternCanvas.getContext('2d');
ctx.fillStyle = this.color;
ctx.fillRect(0, 0, squareWidth, squareWidth);
return patternCanvas;
};
var diamondPatternBrush = new fabric.PatternBrush(canvas);
diamondPatternBrush.getPatternSrc = function() {
var squareWidth = 10, squareDistance = 5;
var patternCanvas = fabric.document.createElement('canvas');
var rect = new fabric.Rect({
width: squareWidth,
height: squareWidth,
angle: 45,
fill: this.color
});
var canvasWidth = rect.getBoundingRect().width;
patternCanvas.width = patternCanvas.height = canvasWidth + squareDistance;
rect.set({ left: canvasWidth / 2, top: canvasWidth / 2 });
var ctx = patternCanvas.getContext('2d');
rect.render(ctx);
return patternCanvas;
};
var img = new Image();
img.src = 'https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg';
var texturePatternBrush = new fabric.PatternBrush(canvas);
texturePatternBrush.source = img;
}
$('drawing-mode-selector').onchange = function() {
if (this.value === 'hline') {
canvas.freeDrawingBrush = vLinePatternBrush;
}
else if (this.value === 'vline') {
canvas.freeDrawingBrush = hLinePatternBrush;
}
else if (this.value === 'square') {
canvas.freeDrawingBrush = squarePatternBrush;
}
else if (this.value === 'diamond') {
canvas.freeDrawingBrush = diamondPatternBrush;
}
else if (this.value === 'texture') {
canvas.freeDrawingBrush = texturePatternBrush;
}
else {
canvas.freeDrawingBrush = new fabric[this.value + 'Brush'](canvas);
}
if (canvas.freeDrawingBrush) {
canvas.freeDrawingBrush.color = drawingColorEl.value;
canvas.freeDrawingBrush.width = parseInt(drawingLineWidthEl.value, 10) || 1;
canvas.freeDrawingBrush.shadow = new fabric.Shadow({
blur: parseInt(drawingShadowWidth.value, 10) || 0,
offsetX: 0,
offsetY: 0,
affectStroke: true,
color: drawingShadowColorEl.value,
});
}
};
drawingColorEl.onchange = function() {
canvas.freeDrawingBrush.color = this.value;
};
drawingShadowColorEl.onchange = function() {
canvas.freeDrawingBrush.shadow.color = this.value;
};
drawingLineWidthEl.onchange = function() {
canvas.freeDrawingBrush.width = parseInt(this.value, 10) || 1;
this.previousSibling.innerHTML = this.value;
};
drawingShadowWidth.onchange = function() {
canvas.freeDrawingBrush.shadow.blur = parseInt(this.value, 10) || 0;
this.previousSibling.innerHTML = this.value;
};
drawingShadowOffset.onchange = function() {
canvas.freeDrawingBrush.shadow.offsetX = parseInt(this.value, 10) || 0;
canvas.freeDrawingBrush.shadow.offsetY = parseInt(this.value, 10) || 0;
this.previousSibling.innerHTML = this.value;
};
if (canvas.freeDrawingBrush) {
canvas.freeDrawingBrush.color = drawingColorEl.value;
canvas.freeDrawingBrush.width = parseInt(drawingLineWidthEl.value, 10) || 1;
canvas.freeDrawingBrush.shadow = new fabric.Shadow({
blur: parseInt(drawingShadowWidth.value, 10) || 0,
offsetX: 0,
offsetY: 0,
affectStroke: true,
color: drawingShadowColorEl.value,
});
}
canvas {
border: 1px solid black;
}
#static {
position: relative;
top: -300px;
left: 330px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.js"></script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static" width="300" height="300"></canvas>
<div style="display: inline-block; margin: 0px 0px 0px 210px">
<button id="drawing-mode" class="btn btn-info">Cancel drawing mode</button><br>
<button id="clear-canvas" class="btn btn-info">Clear</button><br>
<div id="drawing-mode-options">
<label for="drawing-mode-selector">Mode:</label>
<select id="drawing-mode-selector">
<option>Pencil</option>
<option>Circle</option>
<option>Spray</option>
<option>Pattern</option>
<option>hline</option>
<option>vline</option>
<option>square</option>
<option>diamond</option>
<option>texture</option>
</select><br>
<label for="drawing-line-width">Line width:</label>
<span class="info">30</span><input type="range" value="30" min="0" max="150" id="drawing-line-width"><br>
<label for="drawing-color">Line color:</label>
<input type="color" value="#005E7A" id="drawing-color"><br>
<label for="drawing-shadow-color">Shadow color:</label>
<input type="color" value="#005E7A" id="drawing-shadow-color"><br>
<label for="drawing-shadow-width">Shadow width:</label>
<span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-width"><br>
<label for="drawing-shadow-offset">Shadow offset:</label>
<span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-offset"><br>
</div>
</div>