Fabric.js实作: 拼贴图片
2018-11-28 12:50:55
1267次阅读
2个评论
今天来实作一个图片编辑常用的功能: 拼贴。
顾名思义就是能把自己图片拼到已经设定好的框框中,而图片可以在框框中调整要显示的部分,也就是固定位置的裁切功能。
配合之前练习的拖拉图片进入 canvas 来做到让使用者自行上传图片,再将图片拖曳进去 canvas 拼贴。
拖曳部分相关可参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
这边就不在重复解释了
建立区域让使用者知道哪边可以匯入图片
我的作法是想要直接让之后设定的 clipPath 直接依据一开始所设定好的 Layout 做裁切。
首先先建出虚线矩形区块让使用者填入,并且将 selectable 设定為 false,只是要让使用者观看框框的范围,所以就不需要让使用者移动。
自订 isClipFrame 属性之后用配合 drop 事件,判断使用者拖曳到的是不是我们设定的虚线框。
拼贴动作函数
拖拉 Drap & drop 请参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
这边要做的动作分几个步骤
判断拖曳到的 target 是否為矩形虚线框
新增一张照片到举行框内,并且设定裁切范围同等於目标框 target。
判断长宽是否為满版来做调整并锁定移动 X 或 Y。
absolutePositioned 属性
这边可以做到这个功能,主要是靠 absolutePositioned 这个属性,只要将裁切遮罩中的这属性设成 true,此物件这时候 left、top 属性和一般裁切不同的地方在於此物件起始会回到 (0,0),而不是被裁切物件中心。
你可以想像成在 canvas 上挖洞固定在某个位置,而只有那个位置能够显示被裁切的物件。
clone 复製物件
这边因為要做出裁切效果,之后為了更好扩充我们不直接写死,改成复製一份目标框物件,再将复製出来的 absolutePositioned 属性设定成 true。
参考 fabricjs - copy & parse
判断长宽并锁定移动方向
这边做的事情是比对原始图片和框的大小是否适合,做出相对应的大小调整动作。
最后固定一轴的移动 X or Y,让使用者对齐自行调整。
完整函数拼贴动作函数
最后再配合档案上传,让使用者能够上传自己想要拼贴的图片
档案上传部分相关可参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
结果
更多形状填入
因為我们是直接写成复製虚线框物件来做裁切,这样一来,我们就能够更方便的拼贴图片,只要我们先将预设的虚线框建出来就可以了!
任何形状都能裁切!
接下来将预设好的 Layout 储存起来,包成函数让使用者可以透过按钮来切换预设 Layout 。
使用 SVG
也能够直接使用 SVG 来当作裁切的框,这样一来可以做的变化就更多了!
svg form Wikimedia Commons
今日小结
利用设定 absolutePositioned 固定画布上的裁切位置。
并且基於这个方式实作出简易拼贴图片功能。
利用 SVG 做出更丰富的裁切框。
顾名思义就是能把自己图片拼到已经设定好的框框中,而图片可以在框框中调整要显示的部分,也就是固定位置的裁切功能。
配合之前练习的拖拉图片进入 canvas 来做到让使用者自行上传图片,再将图片拖曳进去 canvas 拼贴。
拖曳部分相关可参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
这边就不在重复解释了
建立区域让使用者知道哪边可以匯入图片
我的作法是想要直接让之后设定的 clipPath 直接依据一开始所设定好的 Layout 做裁切。
首先先建出虚线矩形区块让使用者填入,并且将 selectable 设定為 false,只是要让使用者观看框框的范围,所以就不需要让使用者移动。
自订 isClipFrame 属性之后用配合 drop 事件,判断使用者拖曳到的是不是我们设定的虚线框。
let clipPathTop = new fabric.Rect({
// ...略
fill: 'transparent',
selectable: false,
isClipFrame: true
})
let clipPathBottom = new fabric.Rect({
width: 490,
height:240,
left: 5,
top: 255,
stroke: 'red',
strokeWidth: 1,
strokeDashArray: [5, 5],
fill: 'transparent',
selectable: false,
isClipFrame: true
})
canvas.add(clipPathTop)
canvas.add(clipPathBottom)
拼贴动作函数
拖拉 Drap & drop 请参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
这边要做的动作分几个步骤
判断拖曳到的 target 是否為矩形虚线框
新增一张照片到举行框内,并且设定裁切范围同等於目标框 target。
判断长宽是否為满版来做调整并锁定移动 X 或 Y。
absolutePositioned 属性
这边可以做到这个功能,主要是靠 absolutePositioned 这个属性,只要将裁切遮罩中的这属性设成 true,此物件这时候 left、top 属性和一般裁切不同的地方在於此物件起始会回到 (0,0),而不是被裁切物件中心。
你可以想像成在 canvas 上挖洞固定在某个位置,而只有那个位置能够显示被裁切的物件。
clone 复製物件
这边因為要做出裁切效果,之后為了更好扩充我们不直接写死,改成复製一份目标框物件,再将复製出来的 absolutePositioned 属性设定成 true。
参考 fabricjs - copy & parse
target.clone(cloned => clipPath = cloned)
clipPath.absolutePositioned = true
判断长宽并锁定移动方向
这边做的事情是比对原始图片和框的大小是否适合,做出相对应的大小调整动作。
最后固定一轴的移动 X or Y,让使用者对齐自行调整。
// 判断长宽是否為满版来做调整并锁定 X Y
image.scaleToWidth(target.width)
const isFullHeight = image.getScaledHeight() < target.height
if (isFullHeight) image.scaleToHeight(target.height)
image.lockMovementY = isFullHeight
image.lockMovementX = !isFullHeight
完整函数拼贴动作函数
function dropImg (e) {
let target = e.target
if (!target.isClipFrame) return
// 设定匯入图块
target.clone(cloned => clipPath = cloned)
clipPath.absolutePositioned = true
const image = new fabric.Image(movingImage, {
width: movingImage.naturalWidth,
height: movingImage.naturalHeight,
left: target.left,
top: target.top,
clipPath,
})
// 判断长宽是否為满版来做调整并锁定 X Y
image.scaleToWidth(target.width)
const isFullHeight = image.getScaledHeight() < target.height
if (isFullHeight) image.scaleToHeight(target.height)
image.lockMovementY = isFullHeight
image.lockMovementX = !isFullHeight
image.clipPath = clipPath
canvas.add(image)
}
最后再配合档案上传,让使用者能够上传自己想要拼贴的图片
档案上传部分相关可参考 Day 18 - Fabricjs 实作: 图片上传并透过拖曳进入 canvas
结果
更多形状填入
因為我们是直接写成复製虚线框物件来做裁切,这样一来,我们就能够更方便的拼贴图片,只要我们先将预设的虚线框建出来就可以了!
任何形状都能裁切!
接下来将预设好的 Layout 储存起来,包成函数让使用者可以透过按钮来切换预设 Layout 。
使用 SVG
也能够直接使用 SVG 来当作裁切的框,这样一来可以做的变化就更多了!
function setLayoutStyle3 () {
canvas.clear()
const URL = 'https://upload.wikimedia.org/wikipedia/commons/4/42/Love_Heart_SVG.svg'
fabric.loadSVGFromURL(URL, (objects, options) => {
console.log(options)
let svgClip = fabric.util.groupSVGElements(objects, options)
svgClip.scaleToWidth(300)
svgClip.set({
left: 100,
top: 100,
stroke: 'red',
strokeWidth: 1,
strokeDashArray: [5, 5],
fill: 'transparent',
selectable: false,
isClipFrame: true,
})
canvas.add(new fabric.Rect({
...
}))
canvas.add(new fabric.Rect({
...
}))
canvas.add(svgClip).renderAll()
})
}
svg form Wikimedia Commons
今日小结
利用设定 absolutePositioned 固定画布上的裁切位置。
并且基於这个方式实作出简易拼贴图片功能。
利用 SVG 做出更丰富的裁切框。
11