|
|
/**
|
|
|
* 数据流图绘制方法集
|
|
|
* 作者:刘广文
|
|
|
* 邮箱:liugw@imut.edu.cn
|
|
|
* 版本:20230813
|
|
|
* 功能:基于canvas实现数据流图的绘制
|
|
|
*/
|
|
|
var tool = 1;
|
|
|
var current = -1;
|
|
|
var flag=false;
|
|
|
var mouseX= 0;
|
|
|
var mouseY= 0;
|
|
|
var mouseX1= 0;
|
|
|
var mouseY1= 0;
|
|
|
var aryPoint = [];
|
|
|
var aryObject = [];
|
|
|
|
|
|
//加载工具
|
|
|
function loadTools(target){
|
|
|
target.innerHTML = "<div id=\"object\" onclick=\"clickTool(this, 1);\" title=\"绘制外部实体\">源点/终点</div>"
|
|
|
+ "<div id=\"process\" onclick=\"clickTool(this, 2);\" title=\"绘制处理框\">处理</div>"
|
|
|
+ "<div id=\"arrow\" onclick=\"clickTool(this, 3);\" title=\"绘制数据流(1)\"></div>"
|
|
|
+ "<div id=\"arrow1\" onclick=\"clickTool(this, 4);\" title=\"绘制数据流(2)\"></div>"
|
|
|
+ "<div id=\"datasrc\" onclick=\"clickTool(this, 5);\" title=\"绘制数据存储\">数据存储</div>"
|
|
|
+ "<select id=\"arrowtype\" title=\"箭头方向\" hidden><option value=\"1\">单向</option><option value=\"2\">双向</option></select>";
|
|
|
}
|
|
|
//鼠标抬起响应动作
|
|
|
function myMouseUp(e, page){
|
|
|
flag=false;
|
|
|
//drawText(cxt, tool, mouseX, mouseY, mouseX1, mouseY1, text.value, color.value, getDataText(text.value, current));
|
|
|
pushTool(tool, mouseX, mouseY, mouseX1, mouseY1, text.value, color.value, bcolor.value, size.value, arrowtype.value);
|
|
|
updateTools(cxt);
|
|
|
}
|
|
|
//鼠标移动响应动作
|
|
|
function myMouseMove(e, page){
|
|
|
mouseX1= e.pageX-page.offsetLeft;
|
|
|
mouseY1= e.pageY-page.offsetTop;
|
|
|
if(flag){
|
|
|
var aryPoint1 = [];
|
|
|
var i = 0;
|
|
|
while(i < aryPoint.length){
|
|
|
aryPoint1.push(aryPoint[i]);
|
|
|
i ++;
|
|
|
}
|
|
|
updateTools(cxt);
|
|
|
aryPoint = [];
|
|
|
i = 0;
|
|
|
while(i < aryPoint1.length){
|
|
|
aryPoint.push(aryPoint1[i]);
|
|
|
i ++;
|
|
|
}
|
|
|
if (tool == 4){
|
|
|
var s = aryPoint[aryPoint.length - 1];
|
|
|
ary = s.split(",");
|
|
|
var x = parseFloat(ary[0]), y = parseFloat(ary[1]);
|
|
|
if (Math.abs(x - mouseX1) > 10 || Math.abs(y - mouseY1) > 10)
|
|
|
aryPoint.push(mouseX1 + "," + mouseY1);
|
|
|
}
|
|
|
var arrowtype = document.getElementById("arrowtype");
|
|
|
var atype = arrowtype.value;
|
|
|
drawTool(cxt, tool, mouseX, mouseY, mouseX1, mouseY1, color.value, bcolor.value, size.value, atype);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//鼠标按下响应动作
|
|
|
function myMouseDown(e, page)
|
|
|
{
|
|
|
mouseX= e.pageX-page.offsetLeft;
|
|
|
mouseY= e.pageY-page.offsetTop;
|
|
|
aryPoint = [];
|
|
|
aryPoint.push(mouseX + "," + mouseY);
|
|
|
flag = true;
|
|
|
}
|
|
|
//保存
|
|
|
function save(){
|
|
|
var ary = [];
|
|
|
var i = 0;
|
|
|
while(i <= current){
|
|
|
ary.push(aryObject[i]);
|
|
|
i ++;
|
|
|
}
|
|
|
aryObject = ary;
|
|
|
updateButton();
|
|
|
const fileName = 'dataflow.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)
|
|
|
{
|
|
|
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)
|
|
|
{
|
|
|
current ++;
|
|
|
updateTools();
|
|
|
}
|
|
|
updateButton();
|
|
|
}
|
|
|
//选择工具
|
|
|
function clickTool(o, tag){
|
|
|
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';
|
|
|
var arrowtype = document.getElementById("arrowtype");
|
|
|
arrowtype.hidden = true;
|
|
|
text.hidden = true;
|
|
|
text.value = "";
|
|
|
if (tag == 1)
|
|
|
{
|
|
|
text.hidden = false;
|
|
|
text.value = "名称";
|
|
|
}
|
|
|
if (tag == 2)
|
|
|
{
|
|
|
text.hidden = false;
|
|
|
text.value = "处理";
|
|
|
}
|
|
|
if (tag == 3 || tag == 4){
|
|
|
text.hidden = false;
|
|
|
text.value = "数据流";
|
|
|
arrowtype.hidden = false;
|
|
|
}
|
|
|
if (tag == 5)
|
|
|
{
|
|
|
text.hidden = false;
|
|
|
text.value = "数据存储";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//绘制所有工具
|
|
|
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 atype = parseInt(ary[6]);
|
|
|
var color = ary[3];
|
|
|
var bcolor = ary[4];
|
|
|
if(type == 4){
|
|
|
x2 = parseFloat(ary1[ary1.length - 2]);
|
|
|
y2 = parseFloat(ary1[ary1.length - 1]);
|
|
|
aryPoint = [];
|
|
|
var j = 0;
|
|
|
while(j < ary1.length){
|
|
|
var x = parseFloat(ary1[j]), y = parseFloat(ary1[j + 1]);
|
|
|
aryPoint.push(x + "," + y);
|
|
|
j += 2;
|
|
|
}
|
|
|
}
|
|
|
drawTool(cxt, type, x1, y1, x2, y2, color, bcolor, size, atype);
|
|
|
drawText(cxt, type, x1, y1, x2, y2, ary[2], color, getDataText(ary[2], current));
|
|
|
i ++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//通过计算得到当前数据存储的编号
|
|
|
function getDataText(name, count){
|
|
|
var i = 0, j = 0;
|
|
|
//统计包含的数据存储类别
|
|
|
var aryType = [];
|
|
|
while(i <= count){
|
|
|
var ary = aryObject[i].split('|');
|
|
|
var type = parseInt(ary[0]);
|
|
|
if (type == 5 && aryType.indexOf(ary[2]) < 0)
|
|
|
{
|
|
|
aryType.push(ary[2]);
|
|
|
j ++;
|
|
|
}
|
|
|
i ++;
|
|
|
}
|
|
|
if (j > 0){
|
|
|
var l = aryType.length, j = aryType.indexOf(name);
|
|
|
if (l > 1){
|
|
|
if (j < 0) return "D" + (l + 1);
|
|
|
else return "D" + (j + 1);
|
|
|
}
|
|
|
}
|
|
|
return '';
|
|
|
}
|
|
|
//保存当前的绘制
|
|
|
function pushTool(type, x1, y1, x2, y2, text, color, bcolor, size, arrowtype = 0){
|
|
|
var ary = [];
|
|
|
var i = 0;
|
|
|
while(i <= current){
|
|
|
ary.push(aryObject[i]);
|
|
|
i ++;
|
|
|
}
|
|
|
aryObject = ary;
|
|
|
var s = type + '|' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + '|' + text + '|' + color + '|' + bcolor + '|' + size + '|' + arrowtype;
|
|
|
if(type == 4){
|
|
|
s = type + '|';
|
|
|
i = 0;
|
|
|
while(i < aryPoint.length){
|
|
|
if (i > 0)
|
|
|
s += ",";
|
|
|
s += aryPoint[i];
|
|
|
i ++;
|
|
|
}
|
|
|
s = s + '|' + text + '|' + color + '|' + bcolor + '|' + size + '|' + arrowtype;
|
|
|
}
|
|
|
aryObject.push(s);
|
|
|
current ++;
|
|
|
updateButton();
|
|
|
}
|
|
|
//绘制文本
|
|
|
function drawText(context, type, x1, y1, x2, y2, text, color, dataText = ''){
|
|
|
if (text == "" || context == null || type < 1) return;
|
|
|
switch(type){
|
|
|
case 1:
|
|
|
case 2:
|
|
|
case 5:{
|
|
|
//绘制开始框
|
|
|
//计算宽高
|
|
|
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.font = "10pt SimSun";
|
|
|
//updateFont(context, w, h, text, 100);
|
|
|
var w1 = getFontWidth(context, text);
|
|
|
var h1 = getFontHeight(context, text);
|
|
|
context.fillStyle = color;
|
|
|
context.fillText(text, l + (w - w1) / 2, t + h1 / 4 + h / 2);
|
|
|
//如果是数据库,还需要输出标号
|
|
|
if (type == 5){
|
|
|
w1 = getFontWidth(context, dataText);
|
|
|
h1 = getFontHeight(context, dataText);
|
|
|
context.fillText(dataText, l + (w * 0.2 - w1) / 2, t + h1 / 4 + h / 2);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
case 3:{
|
|
|
//绘制箭头
|
|
|
//计算文字大小
|
|
|
context.font = "10pt SimSun";
|
|
|
var w = getFontWidth(context, text);
|
|
|
var h = getFontHeight(context, text);
|
|
|
//获得输出坐标
|
|
|
var x = (x2 + x1) / 2;
|
|
|
var y = (y2 + y1) / 2;
|
|
|
context.fillStyle = color;
|
|
|
context.fillText(text, x, y);
|
|
|
break;
|
|
|
}
|
|
|
case 4:{
|
|
|
//绘制箭头
|
|
|
//计算文字大小
|
|
|
context.font = "10pt SimSun";
|
|
|
var w = getFontWidth(context, text);
|
|
|
var h = getFontHeight(context, text);
|
|
|
//获得输出坐标
|
|
|
var px1 = x1, py1 = y1;
|
|
|
var i = 1;
|
|
|
var pp = 0;
|
|
|
while(i < aryPoint.length)
|
|
|
{
|
|
|
var ary = aryPoint[i].split(',');
|
|
|
var px = parseFloat(ary[0]), py = parseFloat(ary[1]);
|
|
|
var pp1 = 2;
|
|
|
if (Math.abs(px - px1) > Math.abs(py - py1)) pp1 = 1;
|
|
|
if (pp != 0 && pp1 != pp) break;
|
|
|
pp = pp1;
|
|
|
px1 = px;
|
|
|
py1 = py;
|
|
|
i ++;
|
|
|
}
|
|
|
var x = (px1 + x1) / 2;
|
|
|
var y = (py1 + y1) / 2;
|
|
|
context.fillStyle = color;
|
|
|
context.fillText(text, x, y);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
//绘制当前工具
|
|
|
function drawTool(context, type, x1, y1, x2, y2, color, bcolor, size, atype = 0){
|
|
|
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();
|
|
|
break;
|
|
|
}
|
|
|
case 2:{
|
|
|
//绘制处理框
|
|
|
//计算宽高
|
|
|
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;
|
|
|
var r = w * 0.2;
|
|
|
if (h < w)
|
|
|
r = h * 0.2;
|
|
|
context.beginPath();
|
|
|
context.moveTo(l + r, t);
|
|
|
context.arcTo(l + w, t, l + w, t + h, r);
|
|
|
context.arcTo(l + w, t + h, l, t + h, r);
|
|
|
context.arcTo(l, t + h, l, t, r);
|
|
|
context.arcTo(l, t, l + w, t, r);
|
|
|
context.closePath();
|
|
|
context.fillStyle = bcolor;
|
|
|
context.fill();
|
|
|
context.stroke();
|
|
|
break;
|
|
|
}
|
|
|
case 3:{
|
|
|
//绘制连接箭头
|
|
|
//计算箭头方向
|
|
|
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);
|
|
|
if (atype == 2){
|
|
|
a = Math.atan2((y1 - y2), (x1 - x2));
|
|
|
x3 = x1 - ll * Math.cos(a + ss * Math.PI/180);
|
|
|
y3 = y1 - ll * Math.sin(a + ss * Math.PI/180);
|
|
|
x4 = x1 - ll * Math.cos(a - ss * Math.PI/180);
|
|
|
y4 = y1 - ll * Math.sin(a - ss * Math.PI/180);
|
|
|
context.moveTo(x1, y1);
|
|
|
context.lineTo(x3, y3);
|
|
|
context.moveTo(x1, y1);
|
|
|
context.lineTo(x4, y4);
|
|
|
}
|
|
|
context.closePath();
|
|
|
context.stroke();
|
|
|
break;
|
|
|
}
|
|
|
case 4:{
|
|
|
//绘制折线连接箭头
|
|
|
if (aryPoint.length < 3)
|
|
|
break;
|
|
|
var ary = aryPoint[aryPoint.length - 2].split(',');
|
|
|
var px1 = parseFloat(ary[0]), py1 = parseFloat(ary[1]);
|
|
|
ary = aryPoint[aryPoint.length - 1].split(',');
|
|
|
var px2 = parseFloat(ary[0]), py2 = parseFloat(ary[1]);
|
|
|
if (Math.abs(px2 - px1) > Math.abs(py2 - py1))
|
|
|
py1 = py2;
|
|
|
else px1 = px2;
|
|
|
//计算箭头方向
|
|
|
var ll = 10, ss = 30;
|
|
|
var a = Math.atan2((py2 - py1), (px2 - px1));
|
|
|
var x3 = px2 - ll * Math.cos(a + ss * Math.PI/180);
|
|
|
var y3 = py2 - ll * Math.sin(a + ss * Math.PI/180);
|
|
|
var x4 = px2 - ll * Math.cos(a - ss * Math.PI/180);
|
|
|
var y4 = py2 - ll * Math.sin(a - ss * Math.PI/180);
|
|
|
context.strokeStyle = color;
|
|
|
context.lineWidth = size;
|
|
|
context.beginPath();
|
|
|
context.lineTo(px2, py2);
|
|
|
context.lineTo(x3, y3);
|
|
|
context.moveTo(px2, py2);
|
|
|
context.lineTo(x4, y4)
|
|
|
context.moveTo(px2, py2);
|
|
|
context.lineTo(px1, py1);
|
|
|
var i = aryPoint.length - 3;
|
|
|
var px = px1, py = py1;
|
|
|
while(i >= 0){
|
|
|
ary = aryPoint[i].split(',');
|
|
|
px2 = parseFloat(ary[0]), py2 = parseFloat(ary[1]);
|
|
|
if (Math.abs(px2 - px1) > Math.abs(py2 - py1))
|
|
|
py2 = py1;
|
|
|
else px2 = px1;
|
|
|
context.moveTo(px1, py1);
|
|
|
context.lineTo(px2, py2);
|
|
|
px = px1;
|
|
|
py = py1;
|
|
|
px1 = px2;
|
|
|
py1 = py2;
|
|
|
i --;
|
|
|
}
|
|
|
if (atype == 2){
|
|
|
px1 = px;
|
|
|
py1 = py;
|
|
|
a = Math.atan2((py2 - py1), (px2 - px1));
|
|
|
x3 = px2 - ll * Math.cos(a + ss * Math.PI/180);
|
|
|
y3 = py2 - ll * Math.sin(a + ss * Math.PI/180);
|
|
|
x4 = px2 - ll * Math.cos(a - ss * Math.PI/180);
|
|
|
y4 = py2 - ll * Math.sin(a - ss * Math.PI/180);
|
|
|
context.moveTo(px2, py2);
|
|
|
context.lineTo(x3, y3);
|
|
|
context.moveTo(px2, py2);
|
|
|
context.lineTo(x4, y4)
|
|
|
}
|
|
|
context.closePath();
|
|
|
context.stroke();
|
|
|
break;
|
|
|
}
|
|
|
case 5:{
|
|
|
//绘制数据存储
|
|
|
//计算宽高
|
|
|
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, t);
|
|
|
context.lineTo(l, t + h);
|
|
|
context.lineTo(l + w, t + h);
|
|
|
context.moveTo(l + w * 0.2, t);
|
|
|
context.lineTo(l + w * 0.2, t + h);
|
|
|
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) {
|
|
|
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;
|
|
|
} |