# 实现思路

1. 首先创建一个足够大的画布
4. 在周围画上四个矩形盖住（也可以画一个大矩形，把中间的挖掉，由于各种需求和测试问题没有采用这种方式）
5. 每次添加新的元素在上面的时候都保持周边四个区域在最上面

#### 其他思路

1. 使用clipPath，画一个通道给中间区域。

# 代码

// 获取中间画布的四个点的位置
function setXY(state, obj = {}) {
// 最外边整个画布的宽 高
const w = obj.currentWidth || state.currentWidth
const h = obj.currentHeight || state.currentHeight
// 内部工作台画布的宽pannelW 高pannelH
if (
state.currentWidth / state.currentHeight >
state.pannelW / state.pannelH
) {
const height = h - state.padding
// 缩放画布，因为pannelW为实际宽度，比如一张A4纸显示在屏幕上，需要缩放一下，zoom后获取到屏幕的宽度
state.zoom = height / state.pannelH
this.commit('zoomCanvas')
const x2 = 0
const y2 = 0

const y0 = state.padding / state.zoom / 2 + y2
const y1 = state.pannelH + y0
const x0 = w / state.zoom / 2 - state.pannelW / 2 + x2
const x1 = state.pannelW + x0
state.arrX = [x0, x1, x2, w / state.zoom + x2]
state.arrY = [y0, y1, y2, h / state.zoom + y2]
} else {
const width = w - state.padding
state.zoom = width / state.pannelW
this.commit('zoomCanvas')
const x2 = 0
const y2 = 0

const x0 = state.padding / state.zoom / 2 + x2
const x1 = state.pannelW + x0
const y0 = h / state.zoom / 2 - state.pannelH / 2 + y2
const y1 = state.pannelH + y0
state.arrX = [x0, x1, x2, w / state.zoom]
state.arrY = [y0, y1, y2, h / state.zoom]
}
}

2.创建四周的遮罩，给中间的区域，画个背景

function createMask(state) {

const arrX = state.arrX
const arrY = state.arrY

const pathOption = {
selectable: false,
fill: '#ebeced',
hoverCursor: 'default',
evented: false,
excludeFromExport: true,
hasControls: false,
perPixelTargetFind: false,
strokeWidth: 0,
stroke: null
}

const rect1 = new fabric.Rect({
width: arrX[0] - arrX[2],
height: arrY[3] - arrY[2]
})
const rect2 = new fabric.Rect({
width: arrX[3] - arrX[0] + 2,
height: arrY[0] - arrY[2]
})
const rect3 = new fabric.Rect({
width: arrX[3] - arrX[1],
height: arrY[1] - arrY[0] + 2
})
const rect4 = new fabric.Rect({
width: arrX[3] - arrX[0],
height: arrY[3] - arrY[1]
})
rect1.set({
left: arrX[2],
top: arrY[2],
...pathOption
})
rect2.set({
left: arrX[0] - 1,
top: arrY[2],
...pathOption
})
rect3.set({
left: arrX[1],
top: arrY[0] - 1,
...pathOption
})
rect4.set({
left: arrX[0],
top: arrY[1],
...pathOption
})

state.maskPath = new fabric.Group([rect1, rect2, rect3, rect4], {
selectable: false,
excludeFromExport: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
lockUniScaling: true,
hoverCursor: 'auto',
name: 'grid',
left: arrX[2],
top: arrY[2],
evented: false
})
// 创建中间画布的背景
state.backgroundPanel = new fabric.Rect({
left: arrX[0],
top: arrY[0],
selectable: false,
evented: false,
width: state.pannelW,
height: state.pannelH,
strokeWidth: 0,
fill: !state.activePage ? '#ffffff' : 'rgba(0, 0, 0, 0)',
objectCaching: false,
hoverCursor: 'default',
excludeFromExport: true,
hasControls: false,
type: 'sBg',
perPixelTargetFind: false
})
state.canvas.remove(...state.canvas.getObjects('sBg'))
state.canvas.sendToBack(state.backgroundPanel)

state.canvas.renderAll()
}

3.刷新画布，或者加载数据的时候

 jsonDemo.objects.forEach((item) => {
item.left += state.arrX[0]
item.top += state.arrY[0]
})

4.保存json

function saveJson(state) {

// state.toJSONProperties 为要保存的额外属性
const jsonStr = JSON.stringify(state.canvas.toJSON(state.toJSONProperties))
const jsonObj = JSON.parse(jsonStr)

jsonObj.objects.forEach((v) => {
v.left = v.left - state.arrX[0]
v.top = v.top - state.arrY[0]
})

}