@web-map-service/map2d-app
Version:
基于openlayer的2D地图应用
293 lines (262 loc) • 8.43 kB
text/typescript
import { App, Plugin } from '../types'
import { elements } from '@web-map-service/map2d-app'
import { setElementsData, Element } from '../elements'
import { util } from '../shared'
function getElementExtreme(type: RankType, element: Element) {
const sElement = element.getSElement()
let elementExtreme;
if (sElement.type === 'circle') {
// 圆形
// 间距
const distance = (sElement as elements.SElement<'circle'>)['data'].radius
// 是否使用当前元素的极限值替换最终极限值
if (type === 'left') {
elementExtreme = (sElement as elements.SElement<'circle'>)['data'].center[0] - distance;
}
if (type === 'right') {
elementExtreme = (sElement as elements.SElement<'circle'>)['data'].center[0] + distance;
}
if (type === 'top') {
elementExtreme = (sElement as elements.SElement<'circle'>)['data'].center[1] + distance;
}
if (type === 'bottom') {
elementExtreme = (sElement as elements.SElement<'circle'>)['data'].center[1] - distance;
}
} else {
// 多边形、线段
for (const coord of sElement['data']) {
// 是否使用当前元素的极限值替换最终极限值
if (type === 'left' || type === 'right') {
if (util.isUnDef(elementExtreme)) {
elementExtreme = coord[0];
continue
}
if (type === 'left') {
elementExtreme = elementExtreme < coord[0] ? elementExtreme : coord[0];
continue
}
if (type === 'right') {
elementExtreme = elementExtreme > coord[0] ? elementExtreme : coord[0];
continue
}
}
if (type === 'top' || type === 'bottom') {
if (util.isUnDef(elementExtreme)) {
elementExtreme = coord[1];
continue
}
if (type === 'top') {
elementExtreme = elementExtreme > coord[1] ? elementExtreme : coord[1];
continue
}
if (type === 'bottom') {
elementExtreme = elementExtreme < coord[1] ? elementExtreme : coord[1];
continue
}
}
}
}
return elementExtreme
}
function getExtreme(type: RankType, elements: Element[]) {
// 找出极限值
let extreme: number | undefined = undefined
for (const element of elements) {
let useSElementExtreme = false
const elementExtreme = getElementExtreme(type, element)
// extreme 不存在直接赋值
if (util.isUnDef(extreme)) {
extreme = elementExtreme
continue
}
if (type === 'left') {
useSElementExtreme = extreme > elementExtreme
}
if (type === 'right') {
useSElementExtreme = extreme < elementExtreme
}
if (type === 'top') {
useSElementExtreme = extreme < elementExtreme
}
if (type === 'bottom') {
useSElementExtreme = extreme > elementExtreme
}
if (!useSElementExtreme) continue
extreme = elementExtreme
}
return extreme!
}
function syncElements(type: RankType, app: App, extreme: number, elements: Element[]) {
// 所有元素极限排列
const elementsSetDataItems: Parameters<typeof setElementsData>['0'] = []
for (const element of elements) {
const sElement = element.getSElement()
const elementExtreme = getElementExtreme(type, element)
// 计算需要移动的大小
const distance = extreme - elementExtreme
let data: Element['data'] = []
if (sElement.type === 'circle') {
// 圆形
let x: number | undefined = undefined
let y: number | undefined = undefined
if (type === 'left' || type === 'right') {
x = sElement.data.center[0] + distance
y = sElement.data.center[1]
}
if (type === 'top' || type === 'bottom') {
x = sElement.data.center[0]
y = sElement.data.center[1] + distance
}
if (type === 'centerX') {
x = extreme
y = sElement.data.center[1]
}
if (type === 'centerY') {
x = sElement.data.center[0]
y = extreme
}
data = {
radius: sElement.data.radius,
center: [x!, y!]
}
} else {
// 多边形、线段
data = []
if (type === 'left' || type === 'right') {
for (const coord of sElement.data) {
data.push([coord[0] + distance, coord[1]])
}
}
if (type === 'top' || type === 'bottom') {
for (const coord of sElement.data) {
data.push([coord[0], coord[1] + distance])
}
}
if (type === 'centerX') {
const leftElementExtreme = getElementExtreme('left', element)
const rightElementExtreme = getElementExtreme('right', element)
const distance = (rightElementExtreme + leftElementExtreme) / 2 - extreme
for (const coord of sElement.data) {
data.push([coord[0] - distance, coord[1]])
}
}
if (type === 'centerY') {
const topElementExtreme = getElementExtreme('top', element)
const bottomElementExtreme = getElementExtreme('bottom', element)
const distance = (topElementExtreme + bottomElementExtreme) / 2 - extreme
for (const coord of sElement.data) {
data.push([coord[0], coord[1] - distance])
}
}
}
elementsSetDataItems.push({
element,
data: {
data
}
})
}
setElementsData(elementsSetDataItems, app.emitter)
app.emitter.emit('rank', {
elements,
type,
extreme
})
}
function leftAlign(app: App, elements: Element[]) {
const extreme: number = getExtreme('left', elements)
syncElements('left', app, extreme, elements)
}
function rightAlign(app: App, elements: Element[]) {
const extreme: number = getExtreme('right', elements)
syncElements('right', app, extreme, elements)
}
function topAligin(app: App, elements: Element[]) {
const extreme: number = getExtreme('top', elements)
syncElements('top', app, extreme, elements)
}
function bottomAligin(app: App, elements: Element[]) {
const extreme: number = getExtreme('bottom', elements)
syncElements('bottom', app, extreme, elements)
}
function centerAliginX(app: App, elements: Element[]) {
const leftExtreme: number = getExtreme('left', elements)
const rightExtreme: number = getExtreme('right', elements)
const extreme = (leftExtreme + rightExtreme) / 2
syncElements('centerX', app, extreme, elements)
}
function centerAliginY(app: App, elements: Element[]) {
const topExtreme: number = getExtreme('top', elements)
const bottomExtreme: number = getExtreme('bottom', elements)
const extreme = (topExtreme + bottomExtreme) / 2
syncElements('centerY', app, extreme, elements)
}
type RankType = 'left' | 'right' | 'top' | 'bottom' | 'centerX' | 'centerY'
function makeTool(app: App) {
const select = app.tools.select;
const tool = {
enabled: false,
enable() {
if (tool.enabled) return
tool.enabled = true
},
use(type: RankType) {
if (!tool.enabled) return
const elements = select.getSelected()
// 小于2个元素不进行排列
if (elements.length < 2) return
if (type === 'left') {
leftAlign(app, elements)
return
}
if (type === 'right') {
rightAlign(app, elements)
return
}
if (type === 'centerX') {
centerAliginX(app, elements)
return
}
if (type === 'centerY') {
centerAliginY(app, elements)
return
}
if (type === 'top') {
topAligin(app, elements)
return
}
if (type === 'bottom') {
bottomAligin(app, elements)
return
}
},
close() {
if (!tool.enabled) return
tool.enabled = false
}
}
return tool
}
export function createPlugin() {
let app: App
const plugin: Plugin = {
type: 'rank',
depend: ['select'],
install(_app: App) {
app = _app
app.tools.rank = makeTool(app)
return app
},
}
return plugin
}
declare module './tool' {
interface Tools {
rank: ReturnType<typeof makeTool>
}
}
declare module '../types' {
interface AppEmitterEvent {
rank: any
}
}