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.

599 lines
19 KiB

/**
* 数据字典绘制方法集
* 作者刘广文
* 邮箱liugw@imut.edu.cn
* 版本20230819
* 功能基于canvas实现数据字典的绘制
*/
var tool = 1;
var current = -1;
var flag=false;
var mouseX= 0;
var mouseY= 0;
var mouseX1= 0;
var mouseY1= 0;
var aryValue = [];
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;
const aryTitle = ["数据存储名称", "属性名称", "数据类型", "描述"]
//加载工具
function loadTools(target){
target.innerHTML = "<div id=\"single\" onclick=\"clickTool(this, 1);\" title=\"绘制方框式数据字典\">方框</div>"
+ "<div id=\"table\" onclick=\"clickTool(this, 2);\" title=\"绘制表格式数据字典\">表格</div>"
+ "<div id=\"myTable\" hidden></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(){
if (tool == 1)
pushTool(tool, x, y, x + w, y + h, myText.value, color.value, bcolor.value, size.value);
if (tool == 2)
{
aryValue = [];
for(var i = 1; i < myText.children[0].children[0].children.length; i ++){
var row = myText.children[0].children[0].children[i];
for(var j = 0; j < aryTitle.length; j ++)
aryValue.push(row.cells[j].children[0].value);
}
pushTool(tool, x, y, x + w, y + h, "", color.value, bcolor.value, size.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 (!drawn)
{
//pushTool(tool, mouseX, mouseY, mouseX1, mouseY1, text.value, color.value, bcolor.value, size.value);
drawn = true;
if (tool == 1)
{
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();
}
if (tool == 2)
{
if (myText == null)
{
myText = document.getElementById("myTable");
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;
var rowcount = parseInt(text.value);
if (rowcount > 0){
var ww = w / 4 - 10, hh = 25;
var s = "<table width=\"100%\"><tr>";
var i = 0;
while(i < aryTitle.length)
{
s += "<td>" + aryTitle[i] + "</td>";
i ++;
}
s += "</tr>";
var j = 0;
while(j < rowcount){
s += "<tr>";
i = 0;
while(i < aryTitle.length)
{
s += ("<td><textarea style=\"width:" + ww + "px;\"></textarea></td>");
i ++;
}
s += "</tr>";
j ++;
}
s += "</table>";
myText.innerHTML = s;
}
myText.focus();
}
}
updateTools(cxt);
}
//鼠标移动响应动作
function myMouseMove(e, page){
mouseX1= e.pageX-page.offsetLeft;
mouseY1= e.pageY-page.offsetTop;
if(flag){
updateTools(cxt);
if (!drawn)
drawTool(cxt, tool * 10, mouseX, mouseY, mouseX1, mouseY1, color.value, bcolor.value, 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 = 'flowchart.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)
{
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 (current < aryObject.length - 1)
{
if (current < 0)
{
if (aryObject.length > 1)
current = 1;
else current = 0;
}
else
{
if (current + 2 < aryObject.length) current += 2;
else current = aryObject.length - 1;
}
while(current < aryObject.length)
{
var 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;
if (tag == 2)
{
text.hidden = false;
}
}
//绘制所有工具
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];
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], color);
yy += getFontHeight(cxt, ary[2]);
}
else break;
i ++;
}
}
else if(type == 2){
i ++;
var ww = Math.abs(x2 - x1) / aryTitle.length;
var hh = getFontHeight(cxt, aryTitle[0]);
var j = 0;
while(j < aryTitle.length)
{
drawTool(cxt, type, x1 + j * ww, y1, x1 + (j + 1) * ww, y1 + hh, color, bcolor, size);
drawText(cxt, type, x1 + j * ww, y1, x1 + (j + 1) * ww, y1 + hh, aryTitle[j], color);
j ++;
}
var rr = 0, cc = 0, rCount = 0, rMax = 0;
var aryText = [];
var yy = y1 + hh;
while(i <= current){
ary = aryObject[i].split('|');
type = parseInt(ary[0]);
if (type > 2)
{
ary1 = ary[1].split(',');
var r = parseInt(ary1[0]), c = parseInt(ary1[1]);
if (rr != r)
{
j = 0;
while(j < aryTitle.length)
{
drawTool(cxt, 2, x1 + j * ww, yy, x1 + (j + 1) * ww, yy + hh * rMax, color, bcolor, size);
var jj = 0;
for(var k = 0; k < aryText.length; k ++)
{
if (aryText[k].startsWith(j + "|"))
{
ary1 = aryText[k].split('|');
drawText(cxt, 2, x1 + j * ww, yy + hh * jj, x1 + (j + 1) * ww, yy + hh * (jj + 1), ary1[1], color);
jj ++;
}
}
j ++;
}
yy += hh * rMax
rMax = 0;
rCount = 0;
aryText = [];
}
aryText.push(c + "|" + ary[2]);
if (c != cc)
{
if (rMax < rCount)
rMax = rCount;
rCount = 0;
}
cc = c;
rr = r;
rCount ++;
}
else break;
i ++;
}
if (rCount > 0)
{
j = 0;
while(j < aryTitle.length)
{
drawTool(cxt, 2, x1 + j * ww, yy, x1 + (j + 1) * ww, yy + hh * rMax, color, bcolor, size);
var jj = 0;
for(var k = 0; k < aryText.length; k ++)
{
if (aryText[k].startsWith(j + "|"))
{
ary1 = aryText[k].split('|');
drawText(cxt, 2, x1 + j * ww, yy + hh * jj, x1 + (j + 1) * ww, yy + hh * (jj + 1), ary1[1], color);
jj ++;
}
}
j ++;
}
}
}
//i ++;
}
}
//保存当前的绘制
function pushTool(type, x1, y1, x2, y2, text, color, bcolor, size){
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;
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;
aryObject.push(s);
current ++;
var j = 0, r = 0, c = 0;
while(j < aryValue.length){
ary = aryValue[j].split('\n');
if (c == aryTitle.length)
{
c = 0;
r ++;
}
i = 0;
while(i < ary.length)
{
s = type + "0|" + r + "," + c + "|" + ary[i];
aryObject.push(s);
current++;
i ++;
}
j ++;
c ++;
}
}
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:
case 10:
case 2:
case 20:{
//绘制矩形框
//计算宽高
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 == 20)
{
text.value = Math.trunc(h / getFontHeight(context, aryTitle[0]));
}
break;
}
case 21:{
//绘制矩形框
//计算宽高
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;
}
var rSize = 25, cSize = w / 4;
context.strokeStyle = color;
context.lineWidth = size;
//context.beginPath();
var yy = t;
var rr = 0;
while(yy <= t + h){
context.moveTo(l, yy);
context.lineTo(l + w, yy);
yy += rSize;
rr ++;
}
text.value = rr;
var xx = l;
while(xx <= l + w){
context.moveTo(xx, t);
context.lineTo(xx, t + h);
xx += cSize;
}
//context.closePath();
//context.fillStyle = bcolor;
//context.fill();
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) {
const metrics = context.measureText(txt);
const fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
//所有字在这个字体下的高度
//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;
}