属性修改
线宽:
线类型:
线颜色:
<template>
<div class="edit-line">
<div class="btn-list">
<el-button :class="[cmdStatus=='create' ? 'heightLight' : '']" size="small" @click="create">画线</el-button>
<el-tooltip class="item" effect="dark" content="双击 item 也可进入编辑状态" placement="top-start">
<el-button :class="[cmdStatus=='edit' ? 'heightLight' : '']" size="small" @click="edit">编辑</el-button>
</el-tooltip>
<el-button
:class="[cmdStatus=='deleteItem' ? 'heightLight' : '']"
size="small"
@click="deleteItem"
>删除</el-button>
<el-tooltip class="item" effect="dark" content="长按 Shoft 配合左键也可触发该功能" placement="top-start">
<el-button
:class="[cmdStatus=='eqDrawLine' ? 'heightLight' : '']"
size="small"
@click="eqDrawLine"
>垂直水平划线</el-button>
</el-tooltip>
</div>
<div class="content">
<div class="left">
<canvas id="edit_line" width="700" height="460" tabindex="0" />
</div>
<div class="line-property">
<el-card shadow="always">
<div slot="header" class="clearfix">
<span>属性修改</span>
</div>
<div class="always-item">
<span>线宽:</span>
<el-input-number
size="small"
v-model="lineWidth"
@change="changeLineWidth"
:min="1"
:max="50"
></el-input-number>
</div>
<div class="always-item">
<span>线类型:</span>
<el-select
style="width:130px"
size="small"
v-model="lineType"
@change="changeType"
placeholder="请选择"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
<div class="always-item">
<span>线颜色:</span>
<el-color-picker v-model="lineColor" @change="changeColor" show-alpha></el-color-picker>
</div>
</el-card>
</div>
</div>
</div>
</template>
<script>
import { SGraphScene, SGraphView, SLineStyle } from "@persagy-web/graph/";
import { SItemStatus } from "@persagy-web/big/lib/enums/SItemStatus";
import { SPoint } from "@persagy-web/draw/";
import { EditLineItem } from "./../../../../../guides/edit/items/src/EditLineItem";
import { hexify } from "./../../../../public/until/rgbaUtil";
//注: 开发者引入 SWallItem 包为: import {SWallItem} from "@persagy-web/edit/";
export default {
name: "editLine",
data() {
return {
scene: null,
view: null,
isCreated: false, //是否创建完成
cmdStatus: "", //选中状态
lineItem: null, //存放创建的Item
lineWidth: 1,
lineColor: "",
lineType: "",
options: [
{
value: "Solid",
label: "实线"
},
{
value: "Dashed",
label: "虚线"
},
{
value: "Dotted",
label: "点"
}
]
};
},
mounted() {
this.view = new SGraphView("edit_line");
this.scene = new SGraphScene();
this.view.scene = this.scene;
},
methods: {
create() {
this.cmdStatus = "create";
this.scene.root.children = [];
this.lineItem = new EditLineItem(null, []);
this.lineItem.status = SItemStatus.Create;
this.lineItem.connect("finishCreated", this, this.finishCreated);
this.scene.addItem(this.lineItem);
this.scene.grabItem = this.lineItem;
this.view.update();
},
deleteItem() {
this.cmdStatus = "";
this.scene.removeItem(this.lineItem);
this.lineItem = null;
this.view.update();
},
edit() {
if (this.lineItem) {
if (this.lineItem.status == SItemStatus.Normal) {
this.scene.grabItem = this.lineItem;
this.lineItem.status = SItemStatus.Edit;
this.cmdStatus = "edit";
} else {
this.lineItem.status = SItemStatus.Normal;
this.scene.grabItem = null;
this.cmdStatus = "";
}
}
},
eqDrawLine() {
this.cmdStatus = "eqDrawLine";
this.scene.root.children = [];
this.lineItem = new EditLineItem(null, []);
this.lineItem.verAndLeve = true;
this.lineItem.status = SItemStatus.Create;
this.lineItem.connect("finishCreated", this, this.finishCreated);
this.scene.addItem(this.lineItem);
this.scene.grabItem = this.lineItem;
this.view.update();
},
// 改变线宽属性
changeLineWidth(val) {
if (this.lineItem) {
this.lineWidth = val;
this.lineItem.lineWidth = val;
}
},
// 改变颜色
changeColor(val) {
if (this.lineItem) {
this.lineColor = hexify(val);
this.lineItem.strokeColor = this.lineColor;
}
},
//改变线得类型
changeType(val) {
if (this.lineItem) {
this.lineItem.lineStyle = SLineStyle[val];
}
},
// 完成创建后的回调
finishCreated() {
this.cmdStatus = "";
}
},
watch: {
lineItem(val) {
if (val) {
this.lineWidth = val.lineWidth; // 线宽
this.lineStyle = val.lineStyle; // 线条样式
this.lineColor = val.strokeColor.value; // 线条填充色
this.lineType = this.options[val.lineStyle].value;
} else {
this.lineWidth = 0;
}
}
}
};
</script>
<style scoped lang="less">
.edit-line {
width: 100%;
height: 500px;
.content {
display: flex;
justify-content: flex-start;
.left {
margin-right: 20px;
}
.line-property {
width: 300px;
margin-top: 20px;
.always{
width: 100%;
height: 100%;
}
.always-item {
display: flex;
margin-top: 10px;
justify-content: space-between;
}
}
}
.heightLight {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
</style>
import { SColor, SLine, SPainter, SPoint, SRect } from "@persagy-web/draw/";
import { SMouseButton, SMouseEvent, SUndoStack } from "@persagy-web/base";
import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";
import { SItemStatus } from "@persagy-web/big";
import {
SGraphItem,
SGraphPointListInsert,
SGraphPointListUpdate,
SLineStyle
} from "@persagy-web/graph/";
/**
* 编辑类直线 item
*
* @author 韩耀龙(han_yao_long@163.com)
* */
export class EditLineItem extends SGraphItem {
/** X坐标最小值 */
private minX = Number.MAX_SAFE_INTEGER;
/** X坐标最大值 */
private maxX = Number.MIN_SAFE_INTEGER;
/** Y坐标最小值 */
private minY = Number.MAX_SAFE_INTEGER;
/** Y坐标最大值 */
private maxY = Number.MIN_SAFE_INTEGER;
/** 线段 */
private _line: SPoint[] = [];
get line(): SPoint[] {
return this._line;
}
set line(arr: SPoint[]) {
this._line = arr;
this.update();
}
/** 是否垂直水平绘制 */
private _verAndLeve: Boolean= false;
get verAndLeve(): Boolean {
return this._verAndLeve;
}
set verAndLeve(bool: Boolean) {
this._verAndLeve = bool;
this.update();
}
/** 是否完成绘制 */
protected _status: SItemStatus = SItemStatus.Normal;
get status(): SItemStatus {
return this._status;
}
set status(v: SItemStatus) {
this._status = v;
this.undoStack.clear();
this.update();
}
/** 线条颜色 */
private _strokeColor: SColor = SColor.Black;
get strokeColor(): SColor {
return this._strokeColor;
}
set strokeColor(v: SColor) {
this._strokeColor = v;
this.update();
}
/** 线条样式 */
private _lineStyle: SLineStyle = SLineStyle.Solid;
get lineStyle(): SLineStyle {
return this._lineStyle;
}
set lineStyle(v: SLineStyle) {
this._lineStyle = v;
this.update();
}
/** 端点填充色 */
private _fillColor: SColor = SColor.White;
get fillColor(): SColor {
return this._fillColor;
}
set fillColor(v: SColor) {
this._fillColor = v;
this.update();
}
/** 选中端点填充色 */
private _activeFillColor: SColor = new SColor("#2196f3");
get activeFillColor(): SColor {
return this._activeFillColor;
}
set activeFillColor(v: SColor) {
this._activeFillColor = v;
this.update();
}
/** 线条宽度 */
private _lineWidth: number = 1;
get lineWidth(): number {
return this._lineWidth;
}
set lineWidth(v: number) {
this._lineWidth = v;
this.update();
}
/** 拖动灵敏度 */
dis: number = 5;
/** 拖动灵敏度 */
private sceneDis: number = 5;
/** 当前点索引 */
curIndex: number = -1;
/** 当前点坐标 */
private curPoint: SPoint | null = null;
/** undo/redo堆栈 */
private undoStack: SUndoStack = new SUndoStack();
/**
* 构造函数
*
* @param parent 父级
* */
constructor(parent: SGraphItem | null);
/**
* 构造函数
*
* @param parent 父级
* @param line 坐标集合
* */
constructor(parent: SGraphItem | null, line: SPoint[]);
/**
* 构造函数
*
* @param parent 父级
* @param point 第一个点坐标
* */
constructor(parent: SGraphItem | null, point: SPoint);
/**
* 构造函数
*
* @param parent 父级
* @param l 坐标集合|第一个点坐标
* */
constructor(parent: SGraphItem | null, l?: SPoint | SPoint[]) {
super(parent);
if (l) {
if (l instanceof SPoint) {
this.line.push(l);
} else {
this.line = l;
}
} else {
this.line = [];
}
}
/**
* 添加点至数组中
*
* @param p 添加的点
* */
private addPoint(p: SPoint): void {
if (this.line.length < 2) {
this.line.push(p);
this.recordAction(SGraphPointListInsert, [this.line, p]);
} else {
this.line[1] = p;
this.recordAction(SGraphPointListInsert, [this.line, p, 1]);
this.status = SItemStatus.Normal;
this.releaseItem();
this.$emit("finishCreated");
}
this.update();
} // Function addPoint()
/**
* 鼠标双击事件
*
* @param event 事件参数
* @return boolean
*/
onDoubleClick(event: SMouseEvent): boolean {
if (this.status == SItemStatus.Normal) {
this.status = SItemStatus.Edit;
this.grabItem(this);
} else if (this.status == SItemStatus.Edit) {
this.status = SItemStatus.Normal;
this.releaseItem();
}
this.update();
return true;
} // Function onDoubleClick()
/**
* 鼠标按下事件
*
* @param event 鼠标事件
* @return 是否处理事件
* */
onMouseDown(event: SMouseEvent): boolean {
this.curIndex = -1;
this.curPoint = null;
if (event.shiftKey || this._verAndLeve) {
event = this.compare(event);
}
if (event.buttons == SMouseButton.LeftButton) {
if (this.status == SItemStatus.Normal) {
return super.onMouseDown(event);
} else if (this.status == SItemStatus.Edit) {
// 判断是否点击到端点上(获取端点索引值)
this.findNearestPoint(new SPoint(event.x, event.y));
} else if (this.status == SItemStatus.Create) {
this.addPoint(new SPoint(event.x, event.y));
return true;
}
}
return true;
} // Function onMouseDown()
/**
* 鼠标抬起事件
*
* @param event 事件参数
* @return boolean
*/
onMouseUp(event: SMouseEvent): boolean {
if (this.status == SItemStatus.Edit) {
if (this.curIndex > -1) {
const p = new SPoint(
this.line[this.curIndex].x,
this.line[this.curIndex].y
);
this.recordAction(SGraphPointListUpdate, [
this.line,
this.curPoint,
p,
this.curIndex
]);
}
} else if (this.status == SItemStatus.Normal) {
this.moveToOrigin(this.x, this.y);
return super.onMouseUp(event);
}
this.curIndex = -1;
this.curPoint = null;
return true;
} // Function onMouseUp()
/**
* 鼠标移动事件
*
* @param event 鼠标事件
* @return 是否处理事件
* */
onMouseMove(event: SMouseEvent): boolean {
if (event.shiftKey || this._verAndLeve) {
event = this.compare(event);
}
if (this.status == SItemStatus.Create) {
if (this.line[0] instanceof SPoint) {
this.line[1] = new SPoint(event.x, event.y);
}
} else if (this.status == SItemStatus.Edit) {
if (-1 != this.curIndex) {
this.line[this.curIndex].x = event.x;
this.line[this.curIndex].y = event.y;
}
} else {
return super.onMouseMove(event);
}
this.update();
return true;
} // Function onMouseMove()
/**
* 获取点击点与Point[]中的点距离最近点
*
* @param p 鼠标点击点
* */
findNearestPoint(p: SPoint): void {
let len = this.sceneDis;
for (let i = 0; i < this.line.length; i++) {
let dis = SMathUtil.pointDistance(
p.x,
p.y,
this.line[i].x,
this.line[i].y
);
if (dis < len) {
len = dis;
this.curIndex = i;
this.curPoint = new SPoint(this.line[this.curIndex]);
}
}
} // Function findNearestPoint()
/**
* 记录相关动作并推入栈中
*
* @param SGraphCommand 相关命令类
* @param any 对应传入参数
*/
protected recordAction(SGraphCommand: any, any: any[]): void {
// 记录相关命令并推入堆栈中
const command = new SGraphCommand(this.scene, this, ...any);
this.undoStack.push(command);
} // Function recordAction()
/**
* 移动后处理所有坐标,并肩原点置为场景原点
*
* @param x x坐标
* @param y y坐标
* */
moveToOrigin(x: number, y: number): void {
super.moveToOrigin(x, y);
this.line = this.line.map(t => {
t.x = t.x + x;
t.y = t.y + y;
return t;
});
this.x = 0;
this.y = 0;
} // Function moveToOrigin()
/**
* shift垂直水平创建或编辑
*
* @param event 事件
* */
compare(event: SMouseEvent): SMouseEvent {
if (this.line.length) {
let last = new SPoint(event.x, event.y);
if (this.status == SItemStatus.Create) {
last = this.line[0];
} else if (this.status == SItemStatus.Edit) {
if (this.curIndex == 1) {
last = this.line[0];
} else if (this.curIndex == 0) {
last = this.line[1];
}
}
const dx = Math.abs(event.x - last.x);
const dy = Math.abs(event.y - last.y);
if (dy > dx) {
event.x = last.x;
} else {
event.y = last.y;
}
}
return event;
} // Function compare()
/**
* 判断点是否在区域内
*
* @param x
* @param y
* @return true-是
*/
contains(x: number, y: number): boolean {
if (this.line.length == 2) {
let p = new SPoint(x, y);
if (
SMathUtil.pointToLine(p, new SLine(this.line[0], this.line[1]))
.MinDis < this.dis
) {
return true;
}
}
return false;
} // Function contains()
/**
* 撤销操作
*
*/
undo(): void {
if (this.status != SItemStatus.Normal) {
this.undoStack.undo();
}
} // Function undo()
/**
* 重做操作
*
*/
redo(): void {
if (this.status != SItemStatus.Normal) {
this.undoStack.redo();
}
} // Function redo()
/**
* 取消操作item事件
*
* */
cancelOperate(): void {
if (this.status == SItemStatus.Create) {
this.parent = null;
this.releaseItem();
} else if (this.status == SItemStatus.Edit) {
this.status = SItemStatus.Normal;
this.releaseItem();
}
} // Function cancelOperate()
/**
* Item对象边界区域
*
* @return SRect
*/
boundingRect(): SRect {
if (this.line.length) {
this.minX = this.line[0].x;
this.maxX = this.line[0].x;
this.minY = this.line[0].y;
this.maxY = this.line[0].y;
this.line.forEach(it => {
let x = it.x,
y = it.y;
if (x < this.minX) {
this.minX = x;
}
if (y < this.minY) {
this.minY = y;
}
if (x > this.maxX) {
this.maxX = x;
}
if (y > this.maxY) {
this.maxY = y;
}
});
}
return new SRect(
this.minX,
this.minY,
this.maxX - this.minX,
this.maxY - this.minY
);
} // Function boundingRect()
/**
* Item绘制操作
*
* @param painter painter对象
*/
onDraw(painter: SPainter): void {
this.sceneDis = painter.toPx(this.dis);
painter.pen.lineWidth = painter.toPx(this.lineWidth);
painter.pen.color = this.strokeColor;
if (this.line.length == 2) {
// 绘制直线
painter.pen.color = new SColor(this.strokeColor);
if (this.lineStyle == SLineStyle.Dashed) {
painter.pen.lineDash = [
painter.toPx(this.lineWidth * 3),
painter.toPx(this.lineWidth * 7)
];
} else if (this.lineStyle == SLineStyle.Dotted) {
painter.pen.lineDash = [
painter.toPx(this.lineWidth),
painter.toPx(this.lineWidth)
];
}
if (this.selected && this.status == SItemStatus.Normal) {
painter.pen.lineWidth = painter.toPx(this.lineWidth * 2);
painter.shadow.shadowBlur = 10;
painter.shadow.shadowColor = new SColor(`#00000033`);
painter.shadow.shadowOffsetX = 5;
painter.shadow.shadowOffsetY = 5;
}
painter.drawLine(this.line[0], this.line[1]);
if (
this.status == SItemStatus.Edit ||
this.status == SItemStatus.Create
) {
// 绘制端点
this.line.forEach((p, i): void => {
painter.brush.color = this.fillColor;
if (i == this.curIndex) {
painter.brush.color = this.activeFillColor;
}
painter.drawCircle(p.x, p.y, painter.toPx(5));
});
}
} else if (this.line.length == 1) {
if (
this.status == SItemStatus.Edit ||
this.status == SItemStatus.Create
) {
// 绘制端点
painter.brush.color = this.fillColor;
painter.drawCircle(
this.line[0].x,
this.line[0].y,
painter.toPx(5)
);
}
}
} // Function onDraw()
} // Class SLineItem
// 编辑状态时的 LineItem
this.lineItem = new EditLineItem(null, []);
this.lineItem.status = SItemStatus.Create;
this.scene.grabItem = this.lineItem;
// 正常状态时的 LineItem
this.lineItem = new EditLineItem(null, []);
this.lineItem.status = SItemStatus.Normal;
this.scene.grabItem = null;
// 编辑状态时的 LineItem
this.lineItem = new EditLineItem(null, []);
this.lineItem.status = SItemStatus.Create;
this.lineItem.verAndLeve = true;
this.scene.grabItem = this.lineItem;
// 编辑状态时的 LineItem
this.lineItem = new EditLineItem(null, []);
this.lineItem.status = SItemStatus.Create;
this.view.update();