Отображение элемента который генерируется внутри canvas за его пределами fabricjs
Сейчас при наведении на пересечение линий отображается черная квадратная точка. Внутри канваса все хорошо, она отображается полностью, но если навести на край блока где так же есть пересечение, отображение квадратной точки происходит строго по границам канваса. Есть ли какой то способ отобразить черную квадратную точку при наведении за пределами канваса с любой из сторон.
const canvasSize = { width: 500, height: 500 }
const cellDimensions = { width: 50, height: 50 }
const borderStrokeWidth = 3
const objectTypes = {
frame: 'frame',
gridPoint: 'point',
gridLine: 'line',
}
let drawingCanvas
initCanvas()
function initCanvas(id = 'canvas') {
drawingCanvas = new fabric.Canvas(id, {
height: canvasSize.height + borderStrokeWidth,
width: canvasSize.width + borderStrokeWidth,
hoverCursor: 'default',
backgroundColor: 'gray',
selection: false,
})
drawingCanvas.on('mouse:over', (e) => {
if (e.target?.type === objectTypes.gridPoint) {
drawingCanvas.bringToFront(e.target)
e.target.set('opacity', 1)
drawingCanvas.renderAll()
}
})
drawingCanvas.on('mouse:out', (e) => {
if (e.target?.type === objectTypes.gridPoint) {
e.target.set('opacity', 0)
drawingCanvas.renderAll()
}
})
drawingCanvas.on('object:modified', (e) => {
const obj = e.target
const { y: top, x: left } = obj.getPointByOrigin('left', 'top')
obj.set({ top, left, originX: 'left', originY: 'top' })
drawingCanvas.renderAll()
})
drawGrid()
}
function drawGrid() {
const { width: colSize, height: rowSize } = cellDimensions
const makePoint = (x, y) => {
const r = 8
const point = new fabric.Rect({
top: y - r,
left: x - r,
width: r * 2,
height: r * 2,
rx: 1,
ry: 1,
fill: 'black',
hasControls: false,
hasBorders: false,
selectable: false,
opacity: 0,
type: objectTypes.gridPoint,
hoverCursor: 'pointer',
})
drawingCanvas.add(point)
}
const drawLine = (params) => {
const line = new fabric.Line(params, {
stroke: 'yellow',
strokeWidth: borderStrokeWidth,
selectable: false,
evented: false,
type: objectTypes.gridLine,
})
drawingCanvas.add(line)
}
const makeRows = () => {
const rowsCount = canvasSize.height / rowSize
for (let i = 0; i <= rowsCount; i++) {
const y = i * rowSize
drawLine([0, y, canvasSize.width, y])
}
}
const makeCols = () => {
const colsCount = canvasSize.width / colSize
for (let i = 0; i <= colsCount; i++) {
const x = i * colSize
drawLine([x, 0, x, canvasSize.height])
}
}
const makePoints = () => {
const rowsCount = canvasSize.height / rowSize
const colsCount = canvasSize.width / colSize
for (let i = 0; i <= colsCount; i++) {
const x = i * colSize
for (let j = 0; j <= rowsCount; j++) {
const y = j * rowSize
makePoint(x, y)
}
}
}
makeRows()
makeCols()
makePoints()
}
<canvas id="canvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.4.0/fabric.min.js"></script>
Ответы (1 шт):
Самое очевидное решение - это увеличить холст по высоте и ширине на диаметр точки. При этом сместить отрисовку остальных элементов на радиус точки.
const r = 8;
const canvasSize = {
width: 500 + r * 2,
height: 500 + r * 2
};
const cellDimensions = {
width: 50,
height: 50
};
const borderStrokeWidth = 3;
const objectTypes = {
frame: 'frame',
gridPoint: 'point',
gridLine: 'line'
};
let drawingCanvas;
initCanvas();
function initCanvas(id = 'canvas') {
drawingCanvas = new fabric.Canvas(id, {
height: canvasSize.height + borderStrokeWidth,
width: canvasSize.width + borderStrokeWidth,
hoverCursor: 'default',
backgroundColor: 'transparent',
selection: false
})
drawingCanvas.on('mouse:over', (e) => {
if (e.target?.type === objectTypes.gridPoint) {
drawingCanvas.bringToFront(e.target);
e.target.set('opacity', 1);
drawingCanvas.renderAll();
}
})
drawingCanvas.on('mouse:out', (e) => {
if (e.target?.type === objectTypes.gridPoint) {
e.target.set('opacity', 0);
drawingCanvas.renderAll();
}
})
drawingCanvas.on('object:modified', (e) => {
const obj = e.target;
const {y: top, x: left} = obj.getPointByOrigin('left', 'top');
obj.set({
top,
left,
originX: 'left',
originY: 'top'
});
drawingCanvas.renderAll();
})
drawGrid()
}
function drawGrid() {
const {
width: colSize,
height: rowSize
} = cellDimensions;
/* Добавление фона фигурой вместо backgroundColor у всего холста */
const drawBack = () => {
const rect = new fabric.Rect({
left: r,
top: r,
fill: 'grey',
width: canvasSize.width - r * 2,
height: canvasSize.height - r * 2
});
drawingCanvas.add(rect);
}
const makePoint = (x, y) => {
// const r = 18; Перенесено в глобальную область
const point = new fabric.Rect({
top: y - r,
left: x - r,
width: r * 2,
height: r * 2,
rx: 1,
ry: 1,
fill: 'black',
hasControls: false,
hasBorders: false,
selectable: false,
opacity: 0,
type: objectTypes.gridPoint,
hoverCursor: 'pointer'
})
drawingCanvas.add(point);
}
const drawLine = (params) => {
const line = new fabric.Line(params, {
stroke: 'yellow',
strokeWidth: borderStrokeWidth,
selectable: false,
evented: false,
type: objectTypes.gridLine,
})
drawingCanvas.add(line);
}
const makeRows = () => {
const rowsCount = (canvasSize.height - r * 2) / rowSize;
for (let i = 0; i <= rowsCount; i++) {
const y = i * rowSize;
drawLine([0 + r, y + r, canvasSize.width - r, y + r]);
}
}
const makeCols = () => {
const colsCount = (canvasSize.width - r * 2) / colSize;
for (let i = 0; i <= colsCount; i++) {
const x = i * colSize;
drawLine([x + r, 0 + r, x + r, canvasSize.height - r]);
}
}
const makePoints = () => {
const rowsCount = canvasSize.height / rowSize;
const colsCount = canvasSize.width / colSize;
for (let i = 0; i <= colsCount; i++) {
const x = i * colSize;
for (let j = 0; j <= rowsCount; j++) {
const y = j * rowSize;
makePoint(x + r, y + r);
}
}
}
drawBack();
makeRows();
makeCols();
makePoints();
}
<canvas id="canvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.4.0/fabric.min.js"></script>
Вынес константу r (радиус точки) за пределы функций, чтобы она была видна во всех расчётах. А также заменил фоновый цвет холста на прозрачный, подложив под сетку прямоугольник нужного цвета.

