You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

416 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* IPO图绘制方法集
* 作者:刘广文
* 邮箱liugw@imut.edu.cn
* 版本20230813
* 功能基于canvas实现IPO图的绘制
*/
var tool = 1;
var current = -1;
var flag=false;
var mouseX= 0;
var mouseY= 0;
var mouseX1= 0;
var mouseY1= 0;
var aryObject = [];
var drawn = false;
var myText = null, okButton = null, cancelButton = null;
var w = 0, h = 0, x = 0, y = 0, pLeft = 0, pTop = 0;
//加载工具
function loadTools(target){
target.innerHTML = "<div id=\"single\" onclick=\"clickTool(this, 1);\" title=\"绘制文字框\">文字框</div>"
+ "<div id=\"arrow1\" onclick=\"clickTool(this, 2);\" title=\"绘制箭头\">箭头</div>"
+ "<textarea id=\"myText\" hidden></textarea><input type=\"button\" id=\"okButton\" value=\"确定\" onclick=\"okTool();\" hidden/><input type=\"button\" id=\"cancelButton\" value=\"取消\" onclick=\"cancelTool();\" hidden/>";
}
//确定添加
function okTool(){
pushTool(tool, x, y, x + w, y + h, myText.value, color.value, bcolor.value, size.value, fcolor.value);
cancelTool();
updateTools(cxt, tool, x, y, x + w, y + h, color.value, bcolor.value, size.value);
}
//取消添加
function cancelTool(){
if (myText != null)
{
myText.hidden = true;
okButton.hidden = true;
cancelButton.hidden = true;
}
drawn = false;
}
//鼠标抬起响应动作
function myMouseUp(e, page){
flag=false;
if (tool == 1 && !drawn)
{
//
drawn = true;
if (myText == null)
{
myText = document.getElementById("myText");
okButton = document.getElementById("okButton");
cancelButton = document.getElementById("cancelButton");
}
myText.hidden = false;
okButton.hidden = false;
cancelButton.hidden = false;
x = mouseX;
y = mouseY;
if (mouseX1 < mouseX)
x = mouseX1;
if (mouseY1 < mouseY)
y = mouseY1;
w = Math.abs(mouseX - mouseX1);
h = Math.abs(mouseY - mouseY1);
var rect = canvas.getBoundingClientRect();
pLeft = rect.left;
pTop = rect.top;
myText.style.left = (x + pLeft) + "px";
myText.style.top = (y + pTop) + "px";
myText.style.width = w + "px";
myText.style.height = h + "px";
cancelButton.style.left = (x + pLeft + w - 50) + "px";
cancelButton.style.top = (y + pTop + h + 5) + "px";
okButton.style.left = (x + pLeft + w - 110) + "px";
okButton.style.top = (y + pTop + h + 5) + "px";
textWidth = w;
textHeight = h;
myText.addEventListener("mousemove", function(){
if(myText.clientWidth != w || myText.clientHeight != h){
w = myText.clientWidth;
h = myText.clientHeight;
cancelButton.style.left = (x + pLeft + w - 50) + "px";
cancelButton.style.top = (y + pTop + h + 5) + "px";
okButton.style.left = (x + pLeft + w - 110) + "px";
okButton.style.top = (y + pTop + h + 5) + "px";
}
});
myText.focus();
}
else if (tool == 2){
pushTool(tool, mouseX, mouseY, mouseX1, mouseY1, text.value, color.value, bcolor.value, size.value, fcolor.value);
}
updateTools(cxt);
}
//鼠标移动响应动作
function myMouseMove(e, page){
mouseX1= e.pageX-page.offsetLeft;
mouseY1= e.pageY-page.offsetTop;
if(flag){
updateTools(cxt);
if (tool == 2 || !drawn)
drawTool(cxt, tool, mouseX, mouseY, mouseX1, mouseY1, "#000000", "#FFFFFF", size.value);
}
}
//鼠标按下响应动作
function myMouseDown(e, page)
{
mouseX= e.pageX-page.offsetLeft;
mouseY= e.pageY-page.offsetTop;
flag=true;
}
//保存
function save(){
var ary = [];
var i = 0;
while(i <= current){
ary.push(aryObject[i]);
i ++;
}
aryObject = ary;
updateButton();
const fileName = 'ipograph.txt';
var str = '';
i = 0;
while(i < aryObject.length){
if (i == 0)
str = aryObject[i]
else{
str += "\r\n"
str += aryObject[i]
}
i ++;
}
const content = str
const blob = new Blob([content], {type: 'application/text'});
// 构造一个blob对象来处理数据
// 对于<a>标签,只有 Firefox 和 Chrome内核 支持 download 属性
// IE10以上支持blob但是依然不支持download
if ('download' in document.createElement('a'))
{
// 支持a标签download的浏览器
const link = document.createElement('a')
// 创建a标签
link.download = fileName
// a标签添加属性
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
document.body.appendChild(link)
link.click()
// 执行下载
URL.revokeObjectURL(link.href)
// 释放url
document.body.removeChild(link)
// 释放标签
} else {
// 其他浏览器
navigator.msSaveBlob(blob, fileName)
}
}
//撤销
function undo(){
if (current >= 0)
{
var ary = aryObject[current].split('|');
if (parseInt(ary[0]) == 2){
current --;
updateTools();
updateButton();
return;
}
while(current > 0)
{
var ary = aryObject[current].split('|');
if (parseInt(ary[0]) < 3)
break;
current --;
}
current --;
updateTools();
}
updateButton();
}
//刷新按钮状态
function updateButton(){
var undo = document.getElementById("undo");
var redo = document.getElementById("redo");
var save = document.getElementById("save");
if (current >= 0)
{
save.disabled = false;
undo.disabled = false;
}
else
{
undo.disabled = true;
save.disabled = true;
}
if (current < aryObject.length - 1)
{
redo.disabled = false;
}
else {
redo.disabled = true;
}
}
//重做
function redo(){
if (aryObject.length > 0 && current < aryObject.length - 1)
{
current ++;
var ary = aryObject[current].split('|');
if (parseInt(ary[0]) == 2 || current == aryObject.length - 1)
{
updateTools();
updateButton();
return;
}
current ++;
while(current < aryObject.length)
{
ary = aryObject[current].split('|');
if (parseInt(ary[0]) < 3)
{
current --;
break
}
if (current == aryObject.length - 1) break;
current ++;
}
updateTools();
}
updateButton();
}
//选择工具
function clickTool(o, tag){
cancelTool();
myText = null;
tool = tag;
for(var i = 0; i < tools.children.length; i ++){
tools.children[i].style.border = '1px solid black';
}
o.style.border = '2px solid red';
text.hidden = true;
}
//绘制所有工具
function updateTools(context){
canvas.width = canvas.width;
var i = 0;
while (i <= current){
var ary = aryObject[i].split('|');
var type = parseInt(ary[0]);
var ary1 = ary[1].split(',');
var x1 = parseFloat(ary1[0]);
var y1 = parseFloat (ary1[1]);
var x2 = parseFloat(ary1[2]);
var y2 = parseFloat(ary1[3]);
var size = parseFloat(ary[5]);
var color = ary[3];
var bcolor = ary[4];
var fcolor = ary[6];
if(type == 1){
drawTool(cxt, type, x1, y1, x2, y2, color, bcolor, size);
i ++;
var yy = y1;
while(i <= current){
ary = aryObject[i].split('|');
type = parseInt(ary[0]);
if (type > 2)
{
drawText(cxt, type, x1, yy, x2, y2, ary[2], fcolor);
yy += getFontHeight(cxt, ary[2]);
}
else break;
i ++;
}
}
else if(type == 2){
drawTool(cxt, type, x1, y1, x2, y2, color, bcolor, size);
i ++;
}
}
}
//保存当前的绘制
function pushTool(type, x1, y1, x2, y2, text, color, bcolor, size, fcolor){
var ary = [];
var i = 0;
while(i <= current){
ary.push(aryObject[i]);
i ++;
}
aryObject = ary;
if(type == 1)
{
var s = type + '|' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + '||' + color + '|' + bcolor + '|' + size + '|' + fcolor;
aryObject.push(s);
current ++;
ary = text.split("\n");
i = 0;
while(i < ary.length){
s = type + '0||' + ary[i];
aryObject.push(s);
i ++;
current++;
}
}
if(type == 2)
{
var s = type + '|' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + '||' + color + '|' + bcolor + '|' + size + '|' + fcolor;
aryObject.push(s);
current ++;
}
updateButton();
}
//绘制文本
function drawText(context, type, x1, y1, x2, y2, text, color){
if (text == "" || context == null) return;
context.fillStyle = color;
context.fillText(text, x1, y1 + 10);
}
//绘制当前工具
function drawTool(context, type, x1, y1, x2, y2, color, bcolor, size){
if (context == null || type < 1) return;
switch(type){
case 1:{
//绘制框型数据字典
//计算宽高
var l = x1, t = y1;
var w = x2 - x1, h = y2 - y1;
if (w < 0)
{
l = x2;
w = x1 - x2;
}
if (h < 0){
t = y2;
h = y1 - y2;
}
context.strokeStyle = color;
context.lineWidth = size;
context.beginPath();
context.moveTo(l, t);
context.lineTo(l + w, t);
context.lineTo(l + w, t + h);
context.lineTo(l, t + h);
context.lineTo(l, t);
context.closePath();
context.fillStyle = bcolor;
context.fill();
context.stroke();
if (type == 2)
text.value = Math.trunc(h / getFontHeight(aryTitle[0]));
break;
}
case 2:{
//绘制连接箭头
//计算箭头方向
var ll = 10, ss = 30;
var a = Math.atan2((y2 - y1), (x2 - x1));
var x3 = x2 - ll * Math.cos(a + ss * Math.PI/180);
var y3 = y2 - ll * Math.sin(a + ss * Math.PI/180);
var x4 = x2 - ll * Math.cos(a - ss * Math.PI/180);
var y4 = y2 - ll * Math.sin(a - ss * Math.PI/180);
context.strokeStyle = color;
context.lineWidth = size;
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.lineTo(x3, y3);
context.moveTo(x2, y2);
context.lineTo(x4, y4)
context.closePath();
context.stroke();
break;
}
}
}
//计算当前字体下的文本宽度
function getFontWidth(context, txt) {
const metrics = context.measureText(txt);
const actual = Math.abs(metrics.actualBoundingBoxLeft ?? 0) + Math.abs(metrics.actualBoundingBoxRight ?? 0);
const width = Math.max(metrics.width, actual);
return width;
}
//计算当前字体下的文本高度
function getFontHeight(context, txt) {
var fontHeight = 20;
try{
const metrics = context.measureText(txt);
fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
}
catch{
fontHeight = 20;
}
//所有字在这个字体下的高度
//const actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
return fontHeight;
}
//自动调整字体大小
function updateFont(context, w, h, text, size){
context.font = size + "pt SimSun";
w1 = getFontWidth(context, text) * 2;
h1 = getFontHeight(context, text) * 2;
var s = size;
while (w1 > w || h1 > h){
s = s - 1;
context.font = s + "pt SimSun";
w1 = getFontWidth(context, text) * 2;
h1 = getFontHeight(context, text) * 2;
}
return s;
}