feat:add separator

pr675
黄云飞 4 years ago
parent c1cb37c56e
commit f7a677409b

@ -122,6 +122,28 @@
</div>
<div class="menu-item__separator">
<i></i>
<div class="options">
<ul>
<li data-separator='0,0'>
<i></i>
</li>
<li data-separator="1,1">
<i></i>
</li>
<li data-separator="3,1">
<i></i>
</li>
<li data-separator="4,4">
<i></i>
</li>
<li data-separator="7,3,3,3">
<i></i>
</li>
<li data-separator="6,2,2,2,2,2">
<i></i>
</li>
</ul>
</div>
</div>
</div>
<div class="menu-divider"></div>

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h5v1H4zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 390 B

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h6v1H4zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 294 B

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M5 10h4v1H5zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 282 B

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h4v1H4zm5 0h4v1H9zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h3v1h-3z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 389 B

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h1v1H4zm12 0h1v1h-1zM6 10h1v1H6zm12 0h1v1h-1zM8 10h1v1H8zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 885 B

@ -0,0 +1 @@
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h118v1H4z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 116 B

@ -235,8 +235,8 @@ export class Command {
return Command.image(payload)
}
public executeSeparator() {
return Command.separator()
public executeSeparator(payload: number[]) {
return Command.separator(payload)
}
public executeSearch(payload: string | null) {

@ -890,18 +890,32 @@ export class CommandAdapt {
this.draw.render({ curIndex })
}
public separator() {
public separator(payload: number[]) {
const { startIndex, endIndex } = this.range.getRange()
if (!~startIndex && !~endIndex) return
const elementList = this.draw.getElementList()
// 光标后是否存在分割线
if (elementList[endIndex]?.type === ElementType.SEPARATOR) return
const element: IElement = {
value: '\n',
type: ElementType.SEPARATOR
let curIndex = -1
// 光标存在分割线,则判断为修改线段逻辑
const endElement = elementList[endIndex + 1]
if (endElement && endElement.type === ElementType.SEPARATOR) {
if (endElement.dashArray && endElement.dashArray.join() === payload.join()) return
curIndex = endIndex
endElement.dashArray = payload
} else {
const newElement: IElement = {
value: '\n',
type: ElementType.SEPARATOR,
dashArray: payload
}
// 从行头增加分割线
if (startIndex !== 0 && elementList[startIndex].value === ZERO) {
elementList.splice(startIndex, 1, newElement)
curIndex = startIndex - 1
} else {
elementList.splice(startIndex + 1, 0, newElement)
curIndex = startIndex
}
}
const curIndex = startIndex + 1
elementList.splice(curIndex, 0, element)
this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
}

@ -104,7 +104,7 @@ export class Draw {
this.pageNumber = new PageNumber(this)
this.header = new Header(this)
this.hyperlinkParticle = new HyperlinkParticle(this)
this.separatorParticle = new SeparatorParticle(this)
this.separatorParticle = new SeparatorParticle()
this.superscriptParticle = new SuperscriptParticle()
this.subscriptParticle = new SubscriptParticle()
@ -447,6 +447,7 @@ export class Draw {
metrics.boundingBoxDescent = elementHeight
metrics.boundingBoxAscent = 0
} else if (element.type === ElementType.SEPARATOR) {
element.width = innerWidth
metrics.width = innerWidth
metrics.height = this.options.defaultSize
metrics.boundingBoxAscent = -rowMargin

@ -1,24 +1,18 @@
import { IRowElement } from "../../../interface/Row"
import { Draw } from "../Draw"
export class SeparatorParticle {
private draw: Draw
constructor(draw: Draw) {
this.draw = draw
}
public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) {
const innerWidth = this.draw.getInnerWidth()
ctx.save()
if (element.color) {
ctx.strokeStyle = element.color
}
ctx.translate(0.5, 0.5)
if (element.dashArray && element.dashArray.length) {
ctx.setLineDash(element.dashArray)
}
ctx.translate(0, 0.5) // 从1处渲染避免线宽度等于3
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineTo(x + innerWidth, y)
ctx.lineTo(x + element.width!, y)
ctx.stroke()
ctx.restore()
}

@ -78,6 +78,7 @@ export class RangeManager {
const highlight = curElement.highlight || null
const rowFlex = curElement.rowFlex || null
const rowMargin = curElement.rowMargin || this.options.defaultRowMargin
const dashArray = curElement.dashArray || []
// 菜单
const painter = !!this.draw.getPainterStyle()
const undo = this.historyManager.isCanUndo()
@ -95,7 +96,8 @@ export class RangeManager {
color,
highlight,
rowFlex,
rowMargin
rowMargin,
dashArray
})
}
@ -119,7 +121,8 @@ export class RangeManager {
color: null,
highlight: null,
rowFlex: null,
rowMargin
rowMargin,
dashArray: []
})
}

@ -47,7 +47,16 @@ export interface ISuperscriptSubscript {
actualSize?: number;
}
export type IElement = IElementBasic & IElementStyle & ITable & IHyperlinkElement & ISuperscriptSubscript
export interface ISeparator {
dashArray?: number[];
}
export type IElement = IElementBasic
& IElementStyle
& ITable
& IHyperlinkElement
& ISuperscriptSubscript
& ISeparator
export interface IElementMetrics {
width: number;

@ -16,6 +16,7 @@ export interface IRangeStyle {
highlight: string | null;
rowFlex: RowFlex | null;
rowMargin: number;
dashArray: number[];
}
export type IRangeStyleChange = (payload: IRangeStyle) => void

@ -465,9 +465,22 @@ window.onload = function () {
})
}
const separatorDom = document.querySelector<HTMLDivElement>('.menu-item__separator')!
const separatorOptionDom = separatorDom.querySelector<HTMLDivElement>('.options')!
separatorDom.onclick = function () {
console.log('separator')
instance.command.executeSeparator()
separatorOptionDom.classList.toggle('visible')
}
separatorOptionDom.onmousedown = function (evt) {
let payload: number[] = []
const li = evt.target as HTMLLIElement
const separatorDash = li.dataset.separator?.split(',').map(Number)
if (separatorDash) {
const isSingleLine = separatorDash.every(d => d === 0)
if (!isSingleLine) {
payload = separatorDash
}
}
instance.command.executeSeparator(payload)
}
const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
@ -510,11 +523,22 @@ window.onload = function () {
// 控件类型
payload.type === ElementType.SUBSCRIPT ? subscriptDom.classList.add('active') : subscriptDom.classList.remove('active')
payload.type === ElementType.SUPERSCRIPT ? superscriptDom.classList.add('active') : superscriptDom.classList.remove('active')
payload.type === ElementType.SEPARATOR ? separatorDom.classList.add('active') : separatorDom.classList.remove('active')
separatorOptionDom.querySelectorAll('li').forEach(li => li.classList.remove('active'))
if (payload.type === ElementType.SEPARATOR) {
const separator = payload.dashArray.join(',') || '0,0'
const curSeparatorDom = separatorOptionDom.querySelector<HTMLLIElement>(`[data-separator='${separator}']`)!
if (curSeparatorDom) {
curSeparatorDom.classList.add('active')
}
}
// 富文本
const curFontDom = fontOptionDom.querySelector<HTMLLIElement>(`[data-family=${payload.font}]`)!
fontSelectDom.innerText = curFontDom.innerText
fontOptionDom.querySelectorAll<HTMLLIElement>('li').forEach(li => li.classList.remove('active'))
curFontDom.classList.add('active')
const curFontDom = fontOptionDom.querySelector<HTMLLIElement>(`[data-family=${payload.font}]`)
if (curFontDom) {
fontSelectDom.innerText = curFontDom.innerText
curFontDom.classList.add('active')
}
payload.bold ? boldDom.classList.add('active') : boldDom.classList.remove('active')
payload.italic ? italicDom.classList.add('active') : italicDom.classList.remove('active')
payload.underline ? underlineDom.classList.add('active') : underlineDom.classList.remove('active')

@ -369,10 +369,50 @@ ul {
background-image: url('./assets/images/hyperlink.svg');
}
.menu-item__separator i {
.menu-item__separator {
position: relative;
}
.menu-item__separator>i {
background-image: url('./assets/images/separator.svg');
}
.menu-item .menu-item__separator .options {
width: 128px;
}
.menu-item .menu-item__separator li {
padding: 1px 5px;
}
.menu-item__separator li i {
pointer-events: none;
}
.menu-item__separator li[data-separator="0,0"] {
background-image: url('./assets/images/line-single.svg');
}
.menu-item__separator li[data-separator="1,1"] {
background-image: url('./assets/images/line-dot.svg');
}
.menu-item__separator li[data-separator="3,1"] {
background-image: url('./assets/images/line-dash-small-gap.svg');
}
.menu-item__separator li[data-separator="4,4"] {
background-image: url('./assets/images/line-dash-large-gap.svg');
}
.menu-item__separator li[data-separator="7,3,3,3"] {
background-image: url('./assets/images/line-dash-dot.svg');
}
.menu-item__separator li[data-separator="6,2,2,2,2,2"] {
background-image: url('./assets/images/line-dash-dot-dot.svg');
}
.menu-item__search {
position: relative;
}

Loading…
Cancel
Save