接入画布
This commit is contained in:
532
src/component/Canvas/CanvasEditor/utils/helperLine.js
Normal file
532
src/component/Canvas/CanvasEditor/utils/helperLine.js
Normal file
@@ -0,0 +1,532 @@
|
||||
/**
|
||||
* Should objects be aligned by a bounding box?
|
||||
* [Bug] Scaled objects sometimes can not be aligned by edges
|
||||
*
|
||||
*/
|
||||
function initAligningGuidelines(canvas) {
|
||||
var ctx = canvas.getSelectionContext(),
|
||||
aligningLineOffset = 5,
|
||||
aligningLineMargin = 4,
|
||||
aligningLineWidth = 1,
|
||||
aligningLineColor = "rgb(0,255,0)",
|
||||
viewportTransform,
|
||||
zoom = 1;
|
||||
|
||||
function drawVerticalLine(coords) {
|
||||
drawLine(
|
||||
coords.x + 0.5,
|
||||
coords.y1 > coords.y2 ? coords.y2 : coords.y1,
|
||||
coords.x + 0.5,
|
||||
coords.y2 > coords.y1 ? coords.y2 : coords.y1
|
||||
);
|
||||
}
|
||||
|
||||
function drawHorizontalLine(coords) {
|
||||
drawLine(
|
||||
coords.x1 > coords.x2 ? coords.x2 : coords.x1,
|
||||
coords.y + 0.5,
|
||||
coords.x2 > coords.x1 ? coords.x2 : coords.x1,
|
||||
coords.y + 0.5
|
||||
);
|
||||
}
|
||||
|
||||
function drawLine(x1, y1, x2, y2) {
|
||||
ctx.save();
|
||||
ctx.lineWidth = aligningLineWidth;
|
||||
ctx.strokeStyle = aligningLineColor;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(
|
||||
x1 * zoom + viewportTransform[4],
|
||||
y1 * zoom + viewportTransform[5]
|
||||
);
|
||||
ctx.lineTo(
|
||||
x2 * zoom + viewportTransform[4],
|
||||
y2 * zoom + viewportTransform[5]
|
||||
);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function isInRange(value1, value2) {
|
||||
value1 = Math.round(value1);
|
||||
value2 = Math.round(value2);
|
||||
for (
|
||||
var i = value1 - aligningLineMargin, len = value1 + aligningLineMargin;
|
||||
i <= len;
|
||||
i++
|
||||
) {
|
||||
if (i === value2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var verticalLines = [],
|
||||
horizontalLines = [];
|
||||
|
||||
canvas.on("mouse:down", function () {
|
||||
viewportTransform = canvas.viewportTransform;
|
||||
zoom = canvas.getZoom();
|
||||
});
|
||||
|
||||
canvas.on("object:moving", function (e) {
|
||||
var activeObject = e.target,
|
||||
canvasObjects = canvas.getObjects(),
|
||||
activeObjectCenter = activeObject.getCenterPoint(),
|
||||
activeObjectLeft = activeObjectCenter.x,
|
||||
activeObjectTop = activeObjectCenter.y,
|
||||
activeObjectBoundingRect = activeObject.getBoundingRect(),
|
||||
activeObjectHeight =
|
||||
activeObjectBoundingRect.height / viewportTransform[3],
|
||||
activeObjectWidth = activeObjectBoundingRect.width / viewportTransform[0],
|
||||
horizontalInTheRange = false,
|
||||
verticalInTheRange = false,
|
||||
transform = canvas._currentTransform;
|
||||
|
||||
if (!transform) return;
|
||||
|
||||
// It should be trivial to DRY this up by encapsulating (repeating) creation of x1, x2, y1, and y2 into functions,
|
||||
// but we're not doing it here for perf. reasons -- as this a function that's invoked on every mouse move
|
||||
|
||||
for (var i = canvasObjects.length; i--; ) {
|
||||
if (canvasObjects[i] === activeObject) continue;
|
||||
|
||||
var objectCenter = canvasObjects[i].getCenterPoint(),
|
||||
objectLeft = objectCenter.x,
|
||||
objectTop = objectCenter.y,
|
||||
objectBoundingRect = canvasObjects[i].getBoundingRect(),
|
||||
objectHeight = objectBoundingRect.height / viewportTransform[3],
|
||||
objectWidth = objectBoundingRect.width / viewportTransform[0];
|
||||
|
||||
// snaps if the right side of the active object touches the left side of the object
|
||||
if (
|
||||
isInRange(
|
||||
activeObjectLeft + activeObjectWidth / 2,
|
||||
objectLeft - objectWidth / 2
|
||||
)
|
||||
) {
|
||||
verticalInTheRange = true;
|
||||
verticalLines.push({
|
||||
x: objectLeft - objectWidth / 2,
|
||||
y1:
|
||||
objectTop < activeObjectTop
|
||||
? objectTop - objectHeight / 2 - aligningLineOffset
|
||||
: objectTop + objectHeight / 2 + aligningLineOffset,
|
||||
y2:
|
||||
activeObjectTop > objectTop
|
||||
? activeObjectTop + activeObjectHeight / 2 + aligningLineOffset
|
||||
: activeObjectTop - activeObjectHeight / 2 - aligningLineOffset,
|
||||
});
|
||||
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
objectLeft - objectWidth / 2 - activeObjectWidth / 2,
|
||||
activeObjectTop
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snaps if the left side of the active object touches the right side of the object
|
||||
if (
|
||||
isInRange(
|
||||
activeObjectLeft - activeObjectWidth / 2,
|
||||
objectLeft + objectWidth / 2
|
||||
)
|
||||
) {
|
||||
verticalInTheRange = true;
|
||||
verticalLines.push({
|
||||
x: objectLeft + objectWidth / 2,
|
||||
y1:
|
||||
objectTop < activeObjectTop
|
||||
? objectTop - objectHeight / 2 - aligningLineOffset
|
||||
: objectTop + objectHeight / 2 + aligningLineOffset,
|
||||
y2:
|
||||
activeObjectTop > objectTop
|
||||
? activeObjectTop + activeObjectHeight / 2 + aligningLineOffset
|
||||
: activeObjectTop - activeObjectHeight / 2 - aligningLineOffset,
|
||||
});
|
||||
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
objectLeft + objectWidth / 2 + activeObjectWidth / 2,
|
||||
activeObjectTop
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snaps if the bottom of the object touches the top of the active object
|
||||
if (
|
||||
isInRange(
|
||||
objectTop + objectHeight / 2,
|
||||
activeObjectTop - activeObjectHeight / 2
|
||||
)
|
||||
) {
|
||||
horizontalInTheRange = true;
|
||||
horizontalLines.push({
|
||||
y: objectTop + objectHeight / 2,
|
||||
x1:
|
||||
objectLeft < activeObjectLeft
|
||||
? objectLeft - objectWidth / 2 - aligningLineOffset
|
||||
: objectLeft + objectWidth / 2 + aligningLineOffset,
|
||||
x2:
|
||||
activeObjectLeft > objectLeft
|
||||
? activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset
|
||||
: activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset,
|
||||
});
|
||||
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
activeObjectLeft,
|
||||
objectTop + objectHeight / 2 + activeObjectHeight / 2
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snaps if the top of the object touches the bottom of the active object
|
||||
if (
|
||||
isInRange(
|
||||
objectTop - objectHeight / 2,
|
||||
activeObjectTop + activeObjectHeight / 2
|
||||
)
|
||||
) {
|
||||
horizontalInTheRange = true;
|
||||
horizontalLines.push({
|
||||
y: objectTop - objectHeight / 2,
|
||||
x1:
|
||||
objectLeft < activeObjectLeft
|
||||
? objectLeft - objectWidth / 2 - aligningLineOffset
|
||||
: objectLeft + objectWidth / 2 + aligningLineOffset,
|
||||
x2:
|
||||
activeObjectLeft > objectLeft
|
||||
? activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset
|
||||
: activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset,
|
||||
});
|
||||
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
activeObjectLeft,
|
||||
objectTop - objectHeight / 2 - activeObjectHeight / 2
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the horizontal center line
|
||||
if (isInRange(objectLeft, activeObjectLeft)) {
|
||||
verticalInTheRange = true;
|
||||
verticalLines.push({
|
||||
x: objectLeft,
|
||||
y1:
|
||||
objectTop < activeObjectTop
|
||||
? objectTop - objectHeight / 2 - aligningLineOffset
|
||||
: objectTop + objectHeight / 2 + aligningLineOffset,
|
||||
y2:
|
||||
activeObjectTop > objectTop
|
||||
? activeObjectTop + activeObjectHeight / 2 + aligningLineOffset
|
||||
: activeObjectTop - activeObjectHeight / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(objectLeft, activeObjectTop),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the left edge
|
||||
if (
|
||||
isInRange(
|
||||
objectLeft - objectWidth / 2,
|
||||
activeObjectLeft - activeObjectWidth / 2
|
||||
)
|
||||
) {
|
||||
verticalInTheRange = true;
|
||||
verticalLines.push({
|
||||
x: objectLeft - objectWidth / 2,
|
||||
y1:
|
||||
objectTop < activeObjectTop
|
||||
? objectTop - objectHeight / 2 - aligningLineOffset
|
||||
: objectTop + objectHeight / 2 + aligningLineOffset,
|
||||
y2:
|
||||
activeObjectTop > objectTop
|
||||
? activeObjectTop + activeObjectHeight / 2 + aligningLineOffset
|
||||
: activeObjectTop - activeObjectHeight / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
objectLeft - objectWidth / 2 + activeObjectWidth / 2,
|
||||
activeObjectTop
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the right edge
|
||||
if (
|
||||
isInRange(
|
||||
objectLeft + objectWidth / 2,
|
||||
activeObjectLeft + activeObjectWidth / 2
|
||||
)
|
||||
) {
|
||||
verticalInTheRange = true;
|
||||
verticalLines.push({
|
||||
x: objectLeft + objectWidth / 2,
|
||||
y1:
|
||||
objectTop < activeObjectTop
|
||||
? objectTop - objectHeight / 2 - aligningLineOffset
|
||||
: objectTop + objectHeight / 2 + aligningLineOffset,
|
||||
y2:
|
||||
activeObjectTop > objectTop
|
||||
? activeObjectTop + activeObjectHeight / 2 + aligningLineOffset
|
||||
: activeObjectTop - activeObjectHeight / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
objectLeft + objectWidth / 2 - activeObjectWidth / 2,
|
||||
activeObjectTop
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the vertical center line
|
||||
if (isInRange(objectTop, activeObjectTop)) {
|
||||
horizontalInTheRange = true;
|
||||
horizontalLines.push({
|
||||
y: objectTop,
|
||||
x1:
|
||||
objectLeft < activeObjectLeft
|
||||
? objectLeft - objectWidth / 2 - aligningLineOffset
|
||||
: objectLeft + objectWidth / 2 + aligningLineOffset,
|
||||
x2:
|
||||
activeObjectLeft > objectLeft
|
||||
? activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset
|
||||
: activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(activeObjectLeft, objectTop),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the top edge
|
||||
if (
|
||||
isInRange(
|
||||
objectTop - objectHeight / 2,
|
||||
activeObjectTop - activeObjectHeight / 2
|
||||
)
|
||||
) {
|
||||
horizontalInTheRange = true;
|
||||
horizontalLines.push({
|
||||
y: objectTop - objectHeight / 2,
|
||||
x1:
|
||||
objectLeft < activeObjectLeft
|
||||
? objectLeft - objectWidth / 2 - aligningLineOffset
|
||||
: objectLeft + objectWidth / 2 + aligningLineOffset,
|
||||
x2:
|
||||
activeObjectLeft > objectLeft
|
||||
? activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset
|
||||
: activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
activeObjectLeft,
|
||||
objectTop - objectHeight / 2 + activeObjectHeight / 2
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
|
||||
// snap by the bottom edge
|
||||
if (
|
||||
isInRange(
|
||||
objectTop + objectHeight / 2,
|
||||
activeObjectTop + activeObjectHeight / 2
|
||||
)
|
||||
) {
|
||||
horizontalInTheRange = true;
|
||||
horizontalLines.push({
|
||||
y: objectTop + objectHeight / 2,
|
||||
x1:
|
||||
objectLeft < activeObjectLeft
|
||||
? objectLeft - objectWidth / 2 - aligningLineOffset
|
||||
: objectLeft + objectWidth / 2 + aligningLineOffset,
|
||||
x2:
|
||||
activeObjectLeft > objectLeft
|
||||
? activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset
|
||||
: activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset,
|
||||
});
|
||||
activeObject.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
activeObjectLeft,
|
||||
objectTop + objectHeight / 2 - activeObjectHeight / 2
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!horizontalInTheRange) {
|
||||
horizontalLines.length = 0;
|
||||
}
|
||||
|
||||
if (!verticalInTheRange) {
|
||||
verticalLines.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("before:render", function () {
|
||||
if (canvas.contextTop) {
|
||||
canvas.clearContext(canvas.contextTop);
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("after:render", function () {
|
||||
for (var i = verticalLines.length; i--; ) {
|
||||
drawVerticalLine(verticalLines[i]);
|
||||
}
|
||||
for (var i = horizontalLines.length; i--; ) {
|
||||
drawHorizontalLine(horizontalLines[i]);
|
||||
}
|
||||
|
||||
verticalLines.length = horizontalLines.length = 0;
|
||||
});
|
||||
|
||||
canvas.on("mouse:up", function () {
|
||||
verticalLines.length = horizontalLines.length = 0;
|
||||
canvas.renderAll();
|
||||
});
|
||||
}
|
||||
|
||||
export default initAligningGuidelines;
|
||||
|
||||
/**
|
||||
* Augments canvas by assigning to `onObjectMove` and `onAfterRender`.
|
||||
* This kind of sucks because other code using those methods will stop functioning.
|
||||
* Need to fix it by replacing callbacks with pub/sub kind of subscription model.
|
||||
* (or maybe use existing fabric.util.fire/observe (if it won't be too slow))
|
||||
*/
|
||||
|
||||
export function initCenteringGuidelines(canvas) {
|
||||
var canvasWidth = canvas.getWidth(),
|
||||
canvasHeight = canvas.getHeight(),
|
||||
canvasWidthCenter = canvasWidth / 2,
|
||||
canvasHeightCenter = canvasHeight / 2,
|
||||
canvasWidthCenterMap = {},
|
||||
canvasHeightCenterMap = {},
|
||||
centerLineMargin = 4,
|
||||
centerLineColor = "rgba(255,0,241,0.5)",
|
||||
centerLineWidth = 1,
|
||||
ctx = canvas.getSelectionContext(),
|
||||
viewportTransform;
|
||||
|
||||
for (
|
||||
var i = canvasWidthCenter - centerLineMargin,
|
||||
len = canvasWidthCenter + centerLineMargin;
|
||||
i <= len;
|
||||
i++
|
||||
) {
|
||||
canvasWidthCenterMap[Math.round(i)] = true;
|
||||
}
|
||||
for (
|
||||
var i = canvasHeightCenter - centerLineMargin,
|
||||
len = canvasHeightCenter + centerLineMargin;
|
||||
i <= len;
|
||||
i++
|
||||
) {
|
||||
canvasHeightCenterMap[Math.round(i)] = true;
|
||||
}
|
||||
|
||||
function showVerticalCenterLine() {
|
||||
showCenterLine(
|
||||
canvasWidthCenter + 0.5,
|
||||
0,
|
||||
canvasWidthCenter + 0.5,
|
||||
canvasHeight
|
||||
);
|
||||
}
|
||||
|
||||
function showHorizontalCenterLine() {
|
||||
showCenterLine(
|
||||
0,
|
||||
canvasHeightCenter + 0.5,
|
||||
canvasWidth,
|
||||
canvasHeightCenter + 0.5
|
||||
);
|
||||
}
|
||||
|
||||
function showCenterLine(x1, y1, x2, y2) {
|
||||
ctx.save();
|
||||
ctx.strokeStyle = centerLineColor;
|
||||
ctx.lineWidth = centerLineWidth;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1 * viewportTransform[0], y1 * viewportTransform[3]);
|
||||
ctx.lineTo(x2 * viewportTransform[0], y2 * viewportTransform[3]);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
var afterRenderActions = [],
|
||||
isInVerticalCenter,
|
||||
isInHorizontalCenter;
|
||||
|
||||
canvas.on("mouse:down", function () {
|
||||
viewportTransform = canvas.viewportTransform;
|
||||
});
|
||||
|
||||
canvas.on("object:moving", function (e) {
|
||||
var object = e.target,
|
||||
objectCenter = object.getCenterPoint(),
|
||||
transform = canvas._currentTransform;
|
||||
|
||||
if (!transform) return;
|
||||
|
||||
(isInVerticalCenter = Math.round(objectCenter.x) in canvasWidthCenterMap),
|
||||
(isInHorizontalCenter =
|
||||
Math.round(objectCenter.y) in canvasHeightCenterMap);
|
||||
|
||||
if (isInHorizontalCenter || isInVerticalCenter) {
|
||||
object.setPositionByOrigin(
|
||||
new fabric.Point(
|
||||
isInVerticalCenter ? canvasWidthCenter : objectCenter.x,
|
||||
isInHorizontalCenter ? canvasHeightCenter : objectCenter.y
|
||||
),
|
||||
"center",
|
||||
"center"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("before:render", function () {
|
||||
if (canvas.contextTop) {
|
||||
canvas.clearContext(canvas.contextTop);
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("after:render", function () {
|
||||
if (isInVerticalCenter) {
|
||||
showVerticalCenterLine();
|
||||
}
|
||||
if (isInHorizontalCenter) {
|
||||
showHorizontalCenterLine();
|
||||
}
|
||||
});
|
||||
|
||||
canvas.on("mouse:up", function () {
|
||||
// clear these values, to stop drawing guidelines once mouse is up
|
||||
isInVerticalCenter = isInHorizontalCenter = null;
|
||||
canvas.renderAll();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user