feat:add watermark
This commit is contained in:
@@ -145,6 +145,15 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-item__watermark">
|
||||||
|
<i></i>
|
||||||
|
<div class="options">
|
||||||
|
<ul>
|
||||||
|
<li data-menu="add">添加水印</li>
|
||||||
|
<li data-menu="delete">删除水印</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-divider"></div>
|
<div class="menu-divider"></div>
|
||||||
<div class="menu-item">
|
<div class="menu-item">
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><rect stroke="#3D4757" x="2.5" y="1.5" width="11" height="13" rx="1"/><path d="M4 7h8v1H4V7zm0-2h8v1H4V5zm0 6h8v1H4v-1zm0-2h8v1H4V9z" fill="#909AA9" fill-rule="nonzero"/><path d="M6 5.623c.36-.354.936-.638 2-.604 1.785.057 2-.008 2 1.894v4.098H8.984v-.993c1.046.662.885.993-.484.993-1.792 0-2.5-1.068-2.5-2 0-1.427.447-2 2.5-2h.484c0-1-.006-1.007-.984-1-.978.008-1.419.437-2 .437v-.825zm2.5 2.389c-.899 0-1.5-.232-1.5 1 0 1.31.438 1 1.5 1 .617 0 .484-.665.484-1.848v-.152H8.5z" fill="#3D4757"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 602 B |
@@ -55,6 +55,7 @@
|
|||||||
height: 30px;
|
height: 30px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-option__item span {
|
.dialog-option__item span {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IElement } from "../.."
|
import { IElement } from "../.."
|
||||||
import { RowFlex } from "../../dataset/enum/Row"
|
import { RowFlex } from "../../dataset/enum/Row"
|
||||||
import { IDrawImagePayload } from "../../interface/Draw"
|
import { IDrawImagePayload } from "../../interface/Draw"
|
||||||
|
import { IWatermark } from "../../interface/Watermark"
|
||||||
import { CommandAdapt } from "./CommandAdapt"
|
import { CommandAdapt } from "./CommandAdapt"
|
||||||
|
|
||||||
export class Command {
|
export class Command {
|
||||||
@@ -41,6 +42,8 @@ export class Command {
|
|||||||
private static image: Function
|
private static image: Function
|
||||||
private static hyperlink: Function
|
private static hyperlink: Function
|
||||||
private static separator: Function
|
private static separator: Function
|
||||||
|
private static addWatermark: Function
|
||||||
|
private static deleteWatermark: Function
|
||||||
private static search: Function
|
private static search: Function
|
||||||
private static print: Function
|
private static print: Function
|
||||||
private static pageScaleRecovery: Function
|
private static pageScaleRecovery: Function
|
||||||
@@ -84,6 +87,8 @@ export class Command {
|
|||||||
Command.image = adapt.image.bind(adapt)
|
Command.image = adapt.image.bind(adapt)
|
||||||
Command.hyperlink = adapt.hyperlink.bind(adapt)
|
Command.hyperlink = adapt.hyperlink.bind(adapt)
|
||||||
Command.separator = adapt.separator.bind(adapt)
|
Command.separator = adapt.separator.bind(adapt)
|
||||||
|
Command.addWatermark = adapt.addWatermark.bind(adapt)
|
||||||
|
Command.deleteWatermark = adapt.deleteWatermark.bind(adapt)
|
||||||
Command.search = adapt.search.bind(adapt)
|
Command.search = adapt.search.bind(adapt)
|
||||||
Command.print = adapt.print.bind(adapt)
|
Command.print = adapt.print.bind(adapt)
|
||||||
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
|
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
|
||||||
@@ -239,6 +244,14 @@ export class Command {
|
|||||||
return Command.separator(payload)
|
return Command.separator(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public executeAddWatermark(payload: IWatermark) {
|
||||||
|
return Command.addWatermark(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
public executeDeleteWatermark() {
|
||||||
|
return Command.deleteWatermark()
|
||||||
|
}
|
||||||
|
|
||||||
public executeSearch(payload: string | null) {
|
public executeSearch(payload: string | null) {
|
||||||
return Command.search(payload)
|
return Command.search(payload)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ZERO } from "../../dataset/constant/Common"
|
import { ZERO } from "../../dataset/constant/Common"
|
||||||
import { EDITOR_ELEMENT_STYLE_ATTR, TEXTLIKE_ELEMENT_TYPE } from "../../dataset/constant/Element"
|
import { EDITOR_ELEMENT_STYLE_ATTR, TEXTLIKE_ELEMENT_TYPE } from "../../dataset/constant/Element"
|
||||||
|
import { defaultWatermarkOption } from "../../dataset/constant/Watermark"
|
||||||
import { EditorContext } from "../../dataset/enum/Editor"
|
import { EditorContext } from "../../dataset/enum/Editor"
|
||||||
import { ElementType } from "../../dataset/enum/Element"
|
import { ElementType } from "../../dataset/enum/Element"
|
||||||
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
||||||
@@ -11,6 +12,7 @@ import { ISearchResult, ISearchResultRestArgs } from "../../interface/Search"
|
|||||||
import { IColgroup } from "../../interface/table/Colgroup"
|
import { IColgroup } from "../../interface/table/Colgroup"
|
||||||
import { ITd } from "../../interface/table/Td"
|
import { ITd } from "../../interface/table/Td"
|
||||||
import { ITr } from "../../interface/table/Tr"
|
import { ITr } from "../../interface/table/Tr"
|
||||||
|
import { IWatermark } from "../../interface/Watermark"
|
||||||
import { getUUID } from "../../utils"
|
import { getUUID } from "../../utils"
|
||||||
import { formatElementList } from "../../utils/element"
|
import { formatElementList } from "../../utils/element"
|
||||||
import { printImageBase64 } from "../../utils/print"
|
import { printImageBase64 } from "../../utils/print"
|
||||||
@@ -920,6 +922,31 @@ export class CommandAdapt {
|
|||||||
this.draw.render({ curIndex })
|
this.draw.render({ curIndex })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addWatermark(payload: IWatermark) {
|
||||||
|
const options = this.draw.getOptions()
|
||||||
|
const { color, size, opacity, font } = defaultWatermarkOption
|
||||||
|
options.watermark.data = payload.data
|
||||||
|
options.watermark.color = payload.color || color
|
||||||
|
options.watermark.size = payload.size || size
|
||||||
|
options.watermark.opacity = payload.opacity || opacity
|
||||||
|
options.watermark.font = payload.font || font
|
||||||
|
this.draw.render({
|
||||||
|
isSetCursor: false,
|
||||||
|
isSubmitHistory: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteWatermark() {
|
||||||
|
const options = this.draw.getOptions()
|
||||||
|
if (options.watermark && options.watermark.data) {
|
||||||
|
options.watermark = { ...defaultWatermarkOption }
|
||||||
|
this.draw.render({
|
||||||
|
isSetCursor: false,
|
||||||
|
isSubmitHistory: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public image(payload: IDrawImagePayload) {
|
public image(payload: IDrawImagePayload) {
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
const { startIndex, endIndex } = this.range.getRange()
|
||||||
if (!~startIndex && !~endIndex) return
|
if (!~startIndex && !~endIndex) return
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ export class CanvasEvent {
|
|||||||
|
|
||||||
public save(): IEditorResult {
|
public save(): IEditorResult {
|
||||||
// 配置
|
// 配置
|
||||||
const { width, height, margins } = this.draw.getOptions()
|
const { width, height, margins, watermark } = this.draw.getOptions()
|
||||||
// 数据
|
// 数据
|
||||||
const elementList = this.draw.getOriginalElementList()
|
const elementList = this.draw.getOriginalElementList()
|
||||||
const data = zipElementList(elementList)
|
const data = zipElementList(elementList)
|
||||||
@@ -471,6 +471,7 @@ export class CanvasEvent {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
margins,
|
margins,
|
||||||
|
watermark: watermark.data ? watermark : undefined,
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { IHeader } from "../../interface/Header"
|
||||||
|
|
||||||
|
export const defaultHeaderOption: Readonly<Required<IHeader>> = {
|
||||||
|
data: '',
|
||||||
|
color: '#AAAAAA',
|
||||||
|
size: 14,
|
||||||
|
font: 'Yahei'
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { IWatermark } from "../../interface/Watermark"
|
||||||
|
|
||||||
|
export const defaultWatermarkOption: Readonly<Required<IWatermark>> = {
|
||||||
|
data: '',
|
||||||
|
color: '#AEB5C0',
|
||||||
|
opacity: 0.3,
|
||||||
|
size: 200,
|
||||||
|
font: 'Yahei'
|
||||||
|
}
|
||||||
+4
-9
@@ -17,6 +17,8 @@ import { EditorComponent } from './dataset/enum/Editor'
|
|||||||
import { EDITOR_COMPONENT } from './dataset/constant/Editor'
|
import { EDITOR_COMPONENT } from './dataset/constant/Editor'
|
||||||
import { IHeader } from './interface/Header'
|
import { IHeader } from './interface/Header'
|
||||||
import { IWatermark } from './interface/Watermark'
|
import { IWatermark } from './interface/Watermark'
|
||||||
|
import { defaultHeaderOption } from './dataset/constant/Header'
|
||||||
|
import { defaultWatermarkOption } from './dataset/constant/Watermark'
|
||||||
|
|
||||||
export default class Editor {
|
export default class Editor {
|
||||||
|
|
||||||
@@ -26,18 +28,11 @@ export default class Editor {
|
|||||||
|
|
||||||
constructor(container: HTMLDivElement, elementList: IElement[], options: IEditorOption = {}) {
|
constructor(container: HTMLDivElement, elementList: IElement[], options: IEditorOption = {}) {
|
||||||
const headerOptions: Required<IHeader> = {
|
const headerOptions: Required<IHeader> = {
|
||||||
data: '',
|
...defaultHeaderOption,
|
||||||
color: '#AAAAAA',
|
|
||||||
size: 14,
|
|
||||||
font: 'Yahei',
|
|
||||||
...options.header
|
...options.header
|
||||||
}
|
}
|
||||||
const waterMarkOptions: Required<IWatermark> = {
|
const waterMarkOptions: Required<IWatermark> = {
|
||||||
data: '',
|
...defaultWatermarkOption,
|
||||||
color: '#AEB5C0',
|
|
||||||
opacity: 0.3,
|
|
||||||
size: 200,
|
|
||||||
font: 'Yahei',
|
|
||||||
...options.watermark
|
...options.watermark
|
||||||
}
|
}
|
||||||
const editorOptions: Required<IEditorOption> = {
|
const editorOptions: Required<IEditorOption> = {
|
||||||
|
|||||||
@@ -41,5 +41,6 @@ export interface IEditorResult {
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
margins: [top: number, right: number, bottom: number, left: number];
|
margins: [top: number, right: number, bottom: number, left: number];
|
||||||
|
watermark?: IWatermark;
|
||||||
data: IElement[];
|
data: IElement[];
|
||||||
}
|
}
|
||||||
+49
-1
@@ -213,7 +213,8 @@ window.onload = function () {
|
|||||||
data: '人民医院门诊'
|
data: '人民医院门诊'
|
||||||
},
|
},
|
||||||
watermark: {
|
watermark: {
|
||||||
data: '严禁复制'
|
data: 'CANVAS-EDITOR',
|
||||||
|
size: 120
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log('实例: ', instance)
|
console.log('实例: ', instance)
|
||||||
@@ -485,6 +486,53 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
instance.command.executeSeparator(payload)
|
instance.command.executeSeparator(payload)
|
||||||
}
|
}
|
||||||
|
const watermarkDom = document.querySelector<HTMLDivElement>('.menu-item__watermark')!
|
||||||
|
const watermarkOptionDom = watermarkDom.querySelector<HTMLDivElement>('.options')!
|
||||||
|
watermarkDom.onclick = function () {
|
||||||
|
console.log('watermark')
|
||||||
|
watermarkOptionDom.classList.toggle('visible')
|
||||||
|
}
|
||||||
|
watermarkOptionDom.onmousedown = function (evt) {
|
||||||
|
const li = evt.target as HTMLLIElement
|
||||||
|
const menu = li.dataset.menu!
|
||||||
|
watermarkOptionDom.classList.toggle('visible')
|
||||||
|
if (menu === 'add') {
|
||||||
|
new Dialog({
|
||||||
|
title: '水印',
|
||||||
|
data: [{
|
||||||
|
type: 'text',
|
||||||
|
label: '内容',
|
||||||
|
name: 'data',
|
||||||
|
placeholder: '请输入内容'
|
||||||
|
}, {
|
||||||
|
type: 'color',
|
||||||
|
label: '颜色',
|
||||||
|
name: 'color',
|
||||||
|
value: '#AEB5C0'
|
||||||
|
}, {
|
||||||
|
type: 'number',
|
||||||
|
label: '字体大小',
|
||||||
|
name: 'size',
|
||||||
|
value: '120'
|
||||||
|
}],
|
||||||
|
onConfirm: (payload) => {
|
||||||
|
const nullableIndex = payload.findIndex(p => !p.value)
|
||||||
|
if (~nullableIndex) return
|
||||||
|
const watermark = payload.reduce((pre, cur) => {
|
||||||
|
pre[cur.name] = cur.value
|
||||||
|
return pre
|
||||||
|
}, <any>{})
|
||||||
|
instance.command.executeAddWatermark({
|
||||||
|
data: watermark.data,
|
||||||
|
color: watermark.color,
|
||||||
|
size: Number(watermark.size)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
instance.command.executeDeleteWatermark()
|
||||||
|
}
|
||||||
|
}
|
||||||
const searchCollapseDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
const searchCollapseDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
||||||
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
||||||
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
||||||
|
|||||||
@@ -413,6 +413,14 @@ ul {
|
|||||||
background-image: url('./assets/images/line-dash-dot-dot.svg');
|
background-image: url('./assets/images/line-dash-dot-dot.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-item__watermark>i {
|
||||||
|
background-image: url('./assets/images/watermark.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item__watermark {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item__search {
|
.menu-item__search {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user