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

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.

/**
* 数据字典绘制方法集
* 作者:刘广文
* 邮箱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;
}