属性修改
字号:
文本框:
线颜色:
<template>
<div class="edit-line">
<!-- 所有按钮 -->
<div class="btn-list">
</div>
<div class="content">
<div class="left" id="left">
<!-- <textarea name="" class="text" cols="30" rows="10"></textarea> -->
<canvas id="edit_polygon" 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="size" @change="updateSize" :min="1" :max="50"></el-input-number>
</div>
<div class="always-item">
<span>文本框:</span>
<el-input
v-model="text"
@change="handleChangeText"
type="textarea"
:autosize="{ minRows: 1, maxRows: 1}"
placeholder="请输入内容"
style="width:200px;"
></el-input>
</div>
<div class="always-item">
<span>线颜色:</span>
<el-color-picker v-model="color" @change="changeColor" show-alpha></el-color-picker>
</div>
</el-card>
</div>
</div>
</div>
</template>
<script>
import {
SGraphScene,
SGraphView,
SGraphPropertyCommand,
SGraphMoveCommand
} from "@persagy-web/graph/";
import { SUndoStack } from "@persagy-web/base/lib";
import { SFont } from "@persagy-web/draw/lib";
import { SPoint, SColor } from "@persagy-web/draw/";
//注: 开发者引入 SImageItem 包为: import {SImageItem} from "@persagy-web/edit/";
import { EditText } from "./../../../../../guides/edit/items/src/EditText";
import { hexify } from "./../../../../public/until/rgbaUtil";
class SScene extends SGraphScene {
undoStack = new SUndoStack();
textItem = new EditText(null);
constructor() {
super();
this.textItem.moveable = true;
this.textItem.x = 100;
this.textItem.y = 100;
this.addItem(this.textItem);
this.textItem.connect("onMove", this, this.onItemMove.bind(this));
}
updateText(str) {
if (this.textItem.text !== str) {
let old = this.textItem.text;
this.textItem.text = str;
this.undoStack.push(
new SGraphPropertyCommand(this, this.textItem, "text", old, str)
);
}
}
updateColor(color) {
if (this.textItem.color !== color) {
let old = this.textItem.color;
this.textItem.color = color;
this.undoStack.push(
new SGraphPropertyCommand(this, this.textItem, "color", old, color)
);
}
}
updateSize(size) {
if (this.textItem.font.size !== size) {
let old = new SFont(this.textItem.font);
let font = new SFont(this.textItem.font);
font.size = size;
this.textItem.font = font;
this.undoStack.push(
new SGraphPropertyCommand(this, this.textItem, "font", old, font)
);
}
}
onItemMove(item, ...arg) {
this.undoStack.push(
new SGraphMoveCommand(this, item, arg[0][0], arg[0][1])
);
}
}
class TestView extends SGraphView {
constructor() {
super("edit_polygon");
}
}
export default {
name: "edittext",
data() {
return {
scene: new SScene(),
text: "测试文本",
size: 20,
color: "#333333"
};
},
mounted() {
let view = new TestView();
this.scene.updateText(this.text);
this.scene.updateColor(this.color);
this.scene.updateSize(this.size);
view.scene = this.scene;
// this.scene.onMouseUp = this.onMouseUp;
},
methods: {
handleChangeText(text) {
this.scene.updateText(text);
},
handleChangeColor(color) {
this.scene.updateColor(color);
},
updateSize(size) {
this.scene.updateSize(size);
},
undo() {
this.scene.undoStack.undo();
},
redo() {
this.scene.undoStack.redo();
},
reset() {
this.text = "测试文本";
this.size = 20;
this.color = "#333333";
this.scene.updateText(this.text);
this.scene.updateColor(this.color);
this.scene.updateSize(this.size);
},
// 改变颜色
changeColor(val) {
this.scene.updateColor(hexify(val));
},
///////////////////////////////////
//// 以下为测试代码,请忽略
// 设置tooltip位置
/**
* raduis 灵敏范围
* e 鼠标事件对象
* tipDom 浮动得dom
* boxDom 最外层盒子
* offset 偏移量
*/
toolTipPosition(radius, e, tipDom, offset = 0) {
// 滚动高度
const screenTop =
document.documentElement.scrollTop || document.body.scrollTop;
const screenLeft =
document.documentElement.scrollLeft || document.body.scrollLeft;
radius = radius + offset;
const mapBox = document.getElementById("edit_polygon");
// 测试边界mousePosition = 1(右下) 2 (右上)3 (左上) 4 (左下)
const mousePosition = this.Boxboundary(radius, e, mapBox);
const absPosition = this.offsetTL(mapBox);
const absPositionLeft = absPosition.left;
const absPositionTop = absPosition.top;
const mClientY = e.clientY + screenTop;
const mClientX = e.clientX + screenLeft;
const fuzzy_model_width = tipDom.offsetWidth;
const fuzzy_model_height = tipDom.offsetHeight;
// let offsetTL
if (mousePosition == 2) {
tipDom.style.left = `${mClientX - absPositionLeft + offset}px`;
tipDom.style.top = `${mClientY -
fuzzy_model_height -
absPositionTop -
offset}px`;
} else if (mousePosition == 3) {
tipDom.style.left = `${mClientX -
fuzzy_model_width -
absPositionLeft -
offset}px`;
tipDom.style.top = `${mClientY -
fuzzy_model_height -
absPositionTop -
offset}px`;
} else if (mousePosition == 4) {
tipDom.style.left = `${mClientX -
fuzzy_model_width -
absPositionLeft -
offset}px`;
tipDom.style.top = `${mClientY - absPositionTop + offset}px`;
} else {
tipDom.style.left = `${mClientX - absPositionLeft + offset}px`;
tipDom.style.top = `${mClientY - absPositionTop + offset}px`;
}
},
Boxboundary(radius, event, box) {
const screenTop =
document.documentElement.scrollTop || document.body.scrollTop;
const boxWidth = Number(box.style.width.slice(0, -2));
const boxHeight = Number(box.style.height.slice(0, -2));
const absPosition = this.offsetTL(box);
const boxClientX = absPosition.left;
const boxClientY = absPosition.top;
const mouseX = event.clientX;
const mouseY = event.clientY + screenTop;
if (mouseY >= boxClientY + boxHeight - radius) {
if (mouseX <= radius + boxClientX) {
return 2;
} else if (mouseX >= boxClientX + boxWidth - radius) {
return 3;
} else {
return 2;
}
} else if (mouseX >= boxClientX + boxWidth - radius) {
return 4;
} else {
return 1;
}
},
offsetTL(obj) {
//获取到body的offsetTop和offsetLeft
var t = 0,
l = 0;
while (obj) {
t = t + obj.offsetTop;
l = l + obj.offsetLeft;
obj = obj.offsetParent;
}
return {
top: t,
left: l
};
},
onMouseUp(event) {
const dom = "<textarea autofocus ref='textarea' class='text'></textarea>";
let parentDom = document.getElementById("left");
parentDom.innerHTML = parentDom.innerHTML + dom;
const textareaDom = this.$refs.textarea;
// console.log('textareaDom',parentDom.children[0])
this.toolTipPosition(1, event, textareaDom, 0);
}
},
watch: {
// cmdStatus(val) {
// this.scene.cmdStatus = val;
// }
}
};
</script>
<style scoped lang="less">
.text {
overflow: auto;
word-break: break-all;
outline: none;
// background: #409eff;
position: absolute;
left: 0;
top: 0;
}
.edit-line {
width: 100%;
height: 500px;
position: relative;
.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();