深度画布粘贴图片
This commit is contained in:
@@ -85,6 +85,7 @@
|
|||||||
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
|
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
|
||||||
import DepthInput from '../tools/depth-input.vue'
|
import DepthInput from '../tools/depth-input.vue'
|
||||||
import DepthSelect from '../tools/depth-select.vue'
|
import DepthSelect from '../tools/depth-select.vue'
|
||||||
|
import { BlendMode } from '../../tools/layerHelper'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const objectManager = inject('objectManager') as any
|
const objectManager = inject('objectManager') as any
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
height: 0,
|
height: 0,
|
||||||
scaleX: 1,
|
scaleX: 1,
|
||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
globalCompositeOperation: 'source-over'
|
globalCompositeOperation: BlendMode.NORMAL
|
||||||
})
|
})
|
||||||
const updateData = async () => {
|
const updateData = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
@@ -139,87 +140,91 @@
|
|||||||
|
|
||||||
const layerCompositeOptions = ref([
|
const layerCompositeOptions = ref([
|
||||||
{
|
{
|
||||||
value: 'source-over',
|
value: BlendMode.NORMAL,
|
||||||
label: t('DepthCanvas.compositeNormal'),
|
label: t('DepthCanvas.compositeNormal'),
|
||||||
tip: t('DepthCanvas.compositeNormalTip')
|
tip: t('DepthCanvas.compositeNormalTip')
|
||||||
}, // 正常
|
}, // 正常
|
||||||
{
|
{
|
||||||
value: 'darken',
|
value: BlendMode.DARKEN,
|
||||||
label: t('DepthCanvas.compositeDarken'),
|
label: t('DepthCanvas.compositeDarken'),
|
||||||
tip: t('DepthCanvas.compositeDarkenTip')
|
tip: t('DepthCanvas.compositeDarkenTip')
|
||||||
}, // 变暗
|
}, // 变暗
|
||||||
{
|
{
|
||||||
value: 'multiply',
|
value: BlendMode.MULTIPLY,
|
||||||
label: t('DepthCanvas.compositeMultiply'),
|
label: t('DepthCanvas.compositeMultiply'),
|
||||||
tip: t('DepthCanvas.compositeMultiplyTip')
|
tip: t('DepthCanvas.compositeMultiplyTip')
|
||||||
}, // 正片叠底
|
}, // 正片叠底
|
||||||
{
|
{
|
||||||
value: 'color-burn',
|
value: BlendMode.COLOR_BURN,
|
||||||
label: t('DepthCanvas.compositeColorBurn'),
|
label: t('DepthCanvas.compositeColorBurn'),
|
||||||
tip: t('DepthCanvas.compositeColorBurnTip')
|
tip: t('DepthCanvas.compositeColorBurnTip')
|
||||||
}, // 颜色加深
|
}, // 颜色加深
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'lighten',
|
value: BlendMode.LIGHTEN,
|
||||||
label: t('DepthCanvas.compositeLighten'),
|
label: t('DepthCanvas.compositeLighten'),
|
||||||
tip: t('DepthCanvas.compositeLightenTip')
|
tip: t('DepthCanvas.compositeLightenTip')
|
||||||
}, // 颜色减淡
|
}, // 变亮
|
||||||
{
|
{
|
||||||
value: 'screen',
|
value: BlendMode.SCREEN,
|
||||||
label: t('DepthCanvas.compositeScreen'),
|
label: t('DepthCanvas.compositeScreen'),
|
||||||
tip: t('DepthCanvas.compositeScreenTip')
|
tip: t('DepthCanvas.compositeScreenTip')
|
||||||
}, // 滤色
|
}, // 滤色
|
||||||
{
|
{
|
||||||
value: 'color-dodge',
|
value: BlendMode.COLOR_DODGE,
|
||||||
label: t('DepthCanvas.compositeColorDodge'),
|
label: t('DepthCanvas.compositeColorDodge'),
|
||||||
tip: t('DepthCanvas.compositeColorDodgeTip')
|
tip: t('DepthCanvas.compositeColorDodgeTip')
|
||||||
}, // 颜色减淡
|
}, // 颜色减淡
|
||||||
{
|
{
|
||||||
value: 'lighter',
|
value: BlendMode.LIGHTER,
|
||||||
label: t('DepthCanvas.compositeLighter'),
|
label: t('DepthCanvas.compositeLighter'),
|
||||||
tip: t('DepthCanvas.compositeLighterTip')
|
tip: t('DepthCanvas.compositeLighterTip')
|
||||||
}, // 颜色减淡
|
}, // 颜色减淡(添加)
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'overlay',
|
value: BlendMode.OVERLAY,
|
||||||
label: t('DepthCanvas.compositeOverlay'),
|
label: t('DepthCanvas.compositeOverlay'),
|
||||||
tip: t('DepthCanvas.compositeOverlayTip')
|
tip: t('DepthCanvas.compositeOverlayTip')
|
||||||
}, // 叠加
|
}, // 叠加
|
||||||
{
|
{
|
||||||
value: 'soft-light',
|
value: BlendMode.SOFT_LIGHT,
|
||||||
label: t('DepthCanvas.compositeSoftLight'),
|
label: t('DepthCanvas.compositeSoftLight'),
|
||||||
tip: t('DepthCanvas.compositeSoftLightTip')
|
tip: t('DepthCanvas.compositeSoftLightTip')
|
||||||
}, // 柔光
|
}, // 柔光
|
||||||
{
|
{
|
||||||
value: 'hard-light',
|
value: BlendMode.HARD_LIGHT,
|
||||||
label: t('DepthCanvas.compositeHardLight'),
|
label: t('DepthCanvas.compositeHardLight'),
|
||||||
tip: t('DepthCanvas.compositeHardLightTip')
|
tip: t('DepthCanvas.compositeHardLightTip')
|
||||||
}, // 强光
|
}, // 强光
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'difference',
|
value: BlendMode.DIFFERENCE,
|
||||||
label: t('DepthCanvas.compositeDifference'),
|
label: t('DepthCanvas.compositeDifference'),
|
||||||
tip: t('DepthCanvas.compositeDifferenceTip')
|
tip: t('DepthCanvas.compositeDifferenceTip')
|
||||||
}, // 差值
|
}, // 差值
|
||||||
{
|
{
|
||||||
value: 'exclusion',
|
value: BlendMode.EXCLUSION,
|
||||||
label: t('DepthCanvas.compositeExclusion'),
|
label: t('DepthCanvas.compositeExclusion'),
|
||||||
tip: t('DepthCanvas.compositeExclusionTip')
|
tip: t('DepthCanvas.compositeExclusionTip')
|
||||||
}, // 排除
|
}, // 排除
|
||||||
|
|
||||||
{ value: 'hue', label: t('DepthCanvas.compositeHue'), tip: t('DepthCanvas.compositeHueTip') }, // 色相
|
|
||||||
{
|
{
|
||||||
value: 'saturation',
|
value: BlendMode.HUE,
|
||||||
|
label: t('DepthCanvas.compositeHue'),
|
||||||
|
tip: t('DepthCanvas.compositeHueTip')
|
||||||
|
}, // 色相
|
||||||
|
{
|
||||||
|
value: BlendMode.SATURATION,
|
||||||
label: t('DepthCanvas.compositeSaturation'),
|
label: t('DepthCanvas.compositeSaturation'),
|
||||||
tip: t('DepthCanvas.compositeSaturationTip')
|
tip: t('DepthCanvas.compositeSaturationTip')
|
||||||
}, // 饱和度
|
}, // 饱和度
|
||||||
{
|
{
|
||||||
value: 'color',
|
value: BlendMode.COLOR,
|
||||||
label: t('DepthCanvas.compositeColor'),
|
label: t('DepthCanvas.compositeColor'),
|
||||||
tip: t('DepthCanvas.compositeColorTip')
|
tip: t('DepthCanvas.compositeColorTip')
|
||||||
}, // 颜色
|
}, // 颜色
|
||||||
{
|
{
|
||||||
value: 'luminosity',
|
value: BlendMode.LUMINOSITY,
|
||||||
label: t('DepthCanvas.compositeLuminosity'),
|
label: t('DepthCanvas.compositeLuminosity'),
|
||||||
tip: t('DepthCanvas.compositeLuminosityTip')
|
tip: t('DepthCanvas.compositeLuminosityTip')
|
||||||
} // 亮度
|
} // 亮度
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
provide('toolManager', toolManager)
|
provide('toolManager', toolManager)
|
||||||
|
|
||||||
//键盘事件管理器
|
//键盘事件管理器
|
||||||
const keyEventManager = new KeyEventManager({ stateManager, onWorkbench })
|
const keyEventManager = new KeyEventManager({ stateManager, onWorkbench, layerManager })
|
||||||
stateManager.setManager({ keyEventManager })
|
stateManager.setManager({ keyEventManager })
|
||||||
provide('keyEventManager', keyEventManager)
|
provide('keyEventManager', keyEventManager)
|
||||||
|
|
||||||
@@ -163,15 +163,7 @@
|
|||||||
input.addEventListener('change', (e: any) => {
|
input.addEventListener('change', (e: any) => {
|
||||||
const file = e.target.files[0]
|
const file = e.target.files[0]
|
||||||
if (!file) return
|
if (!file) return
|
||||||
const reader = new FileReader()
|
layerManager.createFileImageLayer(file, isRecord).then((v) => resolve(v))
|
||||||
reader.readAsDataURL(file)
|
|
||||||
reader.onload = () => {
|
|
||||||
toolManager.setTool(OperationType.SELECT)
|
|
||||||
const url = reader.result as string
|
|
||||||
layerManager
|
|
||||||
.createImageLayer(url, { info: { name: file.name } }, isRecord)
|
|
||||||
.then((v) => resolve(v))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,6 +419,18 @@ export class LayerManager {
|
|||||||
if (isActive) this.setActiveID(imageObject.info.id)
|
if (isActive) this.setActiveID(imageObject.info.id)
|
||||||
return imageObject
|
return imageObject
|
||||||
}
|
}
|
||||||
|
createFileImageLayer(file: File, isRecord = true) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
reader.onload = () => {
|
||||||
|
this.stateManager.toolManager.setTool(OperationType.SELECT)
|
||||||
|
const url = reader.result as string
|
||||||
|
this.createImageLayer(url, { info: { name: file.name } }, isRecord)
|
||||||
|
.then((v) => resolve(v))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/** 合并图层 */
|
/** 合并图层 */
|
||||||
async imageMergeToLayer(targetLayer: fabric.Object, fabricImage: fabric.Object) {
|
async imageMergeToLayer(targetLayer: fabric.Object, fabricImage: fabric.Object) {
|
||||||
|
|||||||
@@ -1,24 +1,37 @@
|
|||||||
export class KeyEventManager {
|
export class KeyEventManager {
|
||||||
stateManager: any
|
stateManager: any
|
||||||
|
layerManager: any
|
||||||
onWorkbench: any
|
onWorkbench: any
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.stateManager = options.stateManager;
|
this.stateManager = options.stateManager;
|
||||||
|
this.layerManager = options.layerManager;
|
||||||
this.onWorkbench = options.onWorkbench;
|
this.onWorkbench = options.onWorkbench;
|
||||||
this._handleKeyDown = this.handleKeyDown.bind(this)
|
this._handleKeyDown = this.handleKeyDown.bind(this)
|
||||||
|
this._handlePaste = this.handlePaste.bind(this)
|
||||||
}
|
}
|
||||||
onMounted() { }
|
onMounted() { }
|
||||||
|
/** 注册事件 */
|
||||||
|
registerEvents() {
|
||||||
|
document.addEventListener('keydown', this._handleKeyDown)
|
||||||
|
document.addEventListener("paste", this._handlePaste);
|
||||||
|
}
|
||||||
|
/** 删除事件 */
|
||||||
|
removeEvents() {
|
||||||
|
document.removeEventListener('keydown', this._handleKeyDown)
|
||||||
|
document.removeEventListener("paste", this._handlePaste)
|
||||||
|
}
|
||||||
|
|
||||||
/** 处理键盘事件 */
|
/** 处理键盘事件 */
|
||||||
_handleKeyDown: any
|
_handleKeyDown: any
|
||||||
handleKeyDown(event: any) {
|
handleKeyDown(event: any) {
|
||||||
const activeID = this.stateManager.layerManager.activeID.value
|
const activeID = this.layerManager.activeID.value
|
||||||
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
const ctrl = event.ctrlKey ? 'ctrl-' : "";
|
||||||
const shift = event.shiftKey ? 'shift-' : "";
|
const shift = event.shiftKey ? 'shift-' : "";
|
||||||
const key = event.key;
|
const key = event.key;
|
||||||
const reg = new RegExp(`^${ctrl}${shift}${key}$`, 'i')
|
const reg = new RegExp(`^${ctrl}${shift}${key}$`, 'i')
|
||||||
const list = [
|
const list = [
|
||||||
{ key: "ctrl-c", handler: () => this.stateManager.layerManager.copyLayerById(activeID) },
|
{ key: "ctrl-c", handler: () => this.layerManager.copyLayerById(activeID) },
|
||||||
{ key: "delete", handler: () => this.stateManager.layerManager.deleteLayerById(activeID) },
|
{ key: "delete", handler: () => this.layerManager.deleteLayerById(activeID) },
|
||||||
{ key: "ctrl-z", handler: () => this.stateManager.undoState() },
|
{ key: "ctrl-z", handler: () => this.stateManager.undoState() },
|
||||||
{ key: "ctrl-s", handler: () => this.onWorkbench() },
|
{ key: "ctrl-s", handler: () => this.onWorkbench() },
|
||||||
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
|
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
|
||||||
@@ -28,14 +41,28 @@ export class KeyEventManager {
|
|||||||
if (reg.test(v.key)) v.handler(event)
|
if (reg.test(v.key)) v.handler(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/** 注册事件 */
|
/** 处理粘贴事件 */
|
||||||
registerEvents() {
|
_handlePaste: any
|
||||||
document.addEventListener('keydown', this._handleKeyDown)
|
handlePaste(event: any) {
|
||||||
}
|
event.preventDefault(); // 阻止默认粘贴行为
|
||||||
/** 删除事件 */
|
const text = event.clipboardData?.getData("text/plain") || "";
|
||||||
removeEvents() {
|
if (/^aida_copy_canvas_layer/.test(text)) return;
|
||||||
document.removeEventListener('keydown', this._handleKeyDown)
|
const items = event.clipboardData?.items || [];
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.type.indexOf("text/plain") !== -1) {
|
||||||
|
item.getAsString((text) => {
|
||||||
|
console.log('粘贴文本', text);
|
||||||
|
});
|
||||||
|
} else if (item.type.indexOf("image") !== -1) {
|
||||||
|
const file = item.getAsFile();
|
||||||
|
this.layerManager.createFileImageLayer(file, false).then(layer => {
|
||||||
|
const id = layer?.info?.id
|
||||||
|
this.stateManager.objectManager.setFillRepeat(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/** 销毁事件管理器 */
|
||||||
dispose() {
|
dispose() {
|
||||||
this.removeEvents()
|
this.removeEvents()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,21 +54,23 @@ export const OperationTypes = Object.values(OperationType);
|
|||||||
*/
|
*/
|
||||||
export const BlendMode = {
|
export const BlendMode = {
|
||||||
NORMAL: "source-over", // 正常模式
|
NORMAL: "source-over", // 正常模式
|
||||||
MULTIPLY: "multiply", // 正片叠底
|
|
||||||
SCREEN: "screen", // 滤色
|
|
||||||
OVERLAY: "overlay", // 叠加
|
|
||||||
DARKEN: "darken", // 变暗
|
DARKEN: "darken", // 变暗
|
||||||
LIGHTEN: "lighten", // 变亮
|
MULTIPLY: "multiply", // 正片叠底
|
||||||
COLOR_DODGE: "color-dodge", // 颜色减淡
|
|
||||||
COLOR_BURN: "color-burn", // 颜色加深
|
COLOR_BURN: "color-burn", // 颜色加深
|
||||||
HARD_LIGHT: "hard-light", // 强光
|
LIGHTEN: "lighten", // 变亮
|
||||||
|
SCREEN: "screen", // 滤色
|
||||||
|
COLOR_DODGE: "color-dodge", // 颜色减淡
|
||||||
|
LIGHTER: "lighter", // 颜色减淡(添加)
|
||||||
|
OVERLAY: "overlay", // 叠加
|
||||||
SOFT_LIGHT: "soft-light", // 柔光
|
SOFT_LIGHT: "soft-light", // 柔光
|
||||||
|
HARD_LIGHT: "hard-light", // 强光
|
||||||
DIFFERENCE: "difference", // 差值
|
DIFFERENCE: "difference", // 差值
|
||||||
EXCLUSION: "exclusion", // 排除
|
EXCLUSION: "exclusion", // 排除
|
||||||
HUE: "hue", // 色相
|
HUE: "hue", // 色相
|
||||||
SATURATION: "saturation", // 饱和度
|
SATURATION: "saturation", // 饱和度
|
||||||
COLOR: "color", // 颜色
|
COLOR: "color", // 颜色
|
||||||
LUMINOSITY: "luminosity", // 明度
|
LUMINOSITY: "luminosity", // 明度
|
||||||
|
|
||||||
DESTINATION_IN: "destination-in", // 目标内
|
DESTINATION_IN: "destination-in", // 目标内
|
||||||
DESTINATION_OUT: "destination-out", // 目标外
|
DESTINATION_OUT: "destination-out", // 目标外
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user