From 34009d77b34a1ddfa1702a7f238739dd9c09fca0 Mon Sep 17 00:00:00 2001 From: mxd <838425805@qq.com> Date: Sat, 7 Sep 2019 19:56:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=97=A5=E5=BF=97=E3=80=81?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E6=94=B9=E4=B8=BAcanvas=E7=BB=98=E5=88=B6?= =?UTF-8?q?=E3=80=82=E6=8F=90=E9=AB=98=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/static/css/editor.css | 6 +- .../src/main/resources/static/editor.html | 1 + .../main/resources/static/js/canvas-viewer.js | 317 ++++++++++++++++++ .../src/main/resources/static/js/editor.js | 229 +++++++------ 4 files changed, 441 insertions(+), 112 deletions(-) create mode 100644 spider-flow-web/src/main/resources/static/js/canvas-viewer.js diff --git a/spider-flow-web/src/main/resources/static/css/editor.css b/spider-flow-web/src/main/resources/static/css/editor.css index be26855..dbee86c 100644 --- a/spider-flow-web/src/main/resources/static/css/editor.css +++ b/spider-flow-web/src/main/resources/static/css/editor.css @@ -91,14 +91,10 @@ html,body{ } .test-window-container .output-container{ - height: 320px; - overflow: auto; + /* height: 320px; */ } .test-window-container .log-container{ - max-height: 100px; - overflow: auto; border: 1px solid #ccc; - padding: 0 10px; } .test-window-container .log-container textarea{ width : 100%; diff --git a/spider-flow-web/src/main/resources/static/editor.html b/spider-flow-web/src/main/resources/static/editor.html index 3a4111d..7038368 100644 --- a/spider-flow-web/src/main/resources/static/editor.html +++ b/spider-flow-web/src/main/resources/static/editor.html @@ -15,6 +15,7 @@ + diff --git a/spider-flow-web/src/main/resources/static/js/canvas-viewer.js b/spider-flow-web/src/main/resources/static/js/canvas-viewer.js new file mode 100644 index 0000000..dbddcdc --- /dev/null +++ b/spider-flow-web/src/main/resources/static/js/canvas-viewer.js @@ -0,0 +1,317 @@ +window.requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback,element){ + window.setTimeout(callback, 1000 / 60); +} +window.cancelAnimationFrame=window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame || window.oCancelAnimationFrame || function( id ){ + window.clearTimeout( id ); +} +var canvas = document.getElementById('logviewer'); +function CanvasText(options){ + options = options || {}; + this.maxWidth = options.maxWidth || 2147483648; + this.color = options.color; + this.text = options.text.toString(); + this.click = options.click; + this.startX = 0; + this.endX = 0; +} +function CanvasViewer(options){ + options = options || {}; + this.canvas = options.element; + this.context = this.canvas.getContext('2d'); + this.style = options.style || {}; + this.context.font = this.style.font || 'bold 14px Consolas'; + this.context.textBaseline = this.style.textBaseLine || 'middle'; + this.lines = []; + this.lineHeight = 24; + this.maxRows = Math.ceil(this.canvas.height / this.lineHeight); + this.scrollHeight = this.canvas.height; + this.scrollTop = 0; + var _this = this; + this.mouseEvent = 0; + this.mouseDownX = 0; + this.mouseDownY = 0; + this.startIndex = 0; + this.startX = 5; + this.mouseX = 0; + this.mouseY = 0; + this.colsOffsetX = [0]; + this.maxWidth = this.canvas.width - 8; + this.onClick = options.onClick || function(){}; + this.grid = options.grid; + this.header = options.header; + this.canvas.onmousemove = function(e){ + var x = e.offsetX; + var y = e.offsetY; + _this.mouseX = x; + _this.mouseY = y; + var _hover = false; + if(x < _this.canvas.width - 8 && y < _this.canvas.height - 8){ + var row = _this.startIndex + parseInt(y / _this.lineHeight) + (y % _this.lineHeight == 0 ? 0 : 1) - 1; + var texts = _this.lines[row]; + if(texts){ + for(var i =0,len = texts.length;i x){ + _hover = true; + break; + } + } + } + } + if(_hover){ + _this.canvas.style.cursor = 'pointer'; + }else{ + _this.canvas.style.cursor = 'default'; + } + //鼠标按下且有纵向滚动条 + if(_this.mouseEvent == 1 && _this.hasScroll){ + _this.scrollTo(Math.max(Math.min(Math.floor((y / (_this.canvas.height - 8)) * _this.lines.length - _this.maxRows / 2),_this.lines.length - _this.maxRows),0)); + } + //鼠标按下且有横向滚动条 + if(_this.mouseEvent == 2 && _this.hasXScroll){ + var delta = e.offsetX - _this.mouseDownX; + _this.startX = Math.min(-(_this.maxWidth-_this.canvas.width) * (x / (_this.canvas.width - 8)),0) + 5; + } + + } + this.canvas.onmousewheel = function(e){ + if(e.wheelDelta > 0){ //向上滚动 + _this.scrollTo(Math.max(_this.startIndex - 2,0)); + }else{ + _this.scrollTo(Math.max(Math.min(_this.startIndex + 1,_this.lines.length - _this.maxRows),0)); + } + } + this.canvas.onmousedown = function(e){ + if(e.offsetX > _this.canvas.width - 8 && e.offsetY < _this.canvas.height - 8){ + _this.mouseEvent = 1; + _this.mouseDownX = e.offsetX; + _this.mouseDownY = e.offsetY; + } + if(e.offsetX < _this.canvas.width - 8 && e.offsetY > _this.canvas.height - 8){ + _this.mouseEvent = 2; + _this.mouseDownX = e.offsetX; + _this.mouseDownY = e.offsetY; + } + } + this.canvas.onmouseup = this.canvas.onmouseout = function(){ + _this.mouseEvent = 0; + _this.mouseDownX = 0; + _this.mouseDownY = 0; + } + this.canvas.onclick = function(e){ + var x = e.offsetX; + var y = e.offsetY; + if(x < _this.canvas.width - 8 && y < _this.canvas.height - 8){ + var row = _this.startIndex + parseInt(y / _this.lineHeight) + (y % _this.lineHeight == 0 ? 0 : 1) - 1; + var _hover = false; + var texts = _this.lines[row]; + if(texts){ + for(var i =0,len = texts.length;i x){ + _this.onClick(text); + break; + } + } + } + } + + } + var animate = function(){ + _this.animateIndex = requestAnimFrame(animate); + _this.redraw(); + } + animate(); +} +CanvasViewer.prototype.destory = function(){ + cancelAnimationFrame(animateIndex); + this.texts = null; +} +CanvasViewer.prototype.append = function(texts){ + var width = texts.length * 10 - 10; + for(var i =0,len = texts.length;i 0){ + w = this._drawLongText(text.text,0,0,text.maxWidth,true); + }else{ + w = this.context.measureText(content).width; + } + this.colsOffsetX[i] = Math.max(this.colsOffsetX[i] || 0,w); + width += w; + } + this.maxWidth = Math.max(this.maxWidth,width); + this.lines.push(texts); +} +CanvasViewer.prototype.resize = function(){ + var prevMaxRows = this.maxRows; + this.maxRows = Math.ceil(this.canvas.height / this.lineHeight); + this.context = this.canvas.getContext('2d'); + this.context.font = 'bold 14px Consolas'; + this.context.textBaseline = 'middle'; + this.scrollTo(this.startIndex + (prevMaxRows - this.maxRows)); + this.redraw(); +} +CanvasViewer.prototype._drawScroll = function(){ + var surplus = this.lines.length - this.maxRows; + this.hasScroll = surplus > 0; + + this.context.clearRect(x,canvasHeight,8,8); + if(this.hasScroll){ + var canvasHeight = this.canvas.height - 8; + this.scrollHeight = canvasHeight + this.lineHeight * surplus; + this.slideHeight = Math.max(canvasHeight * (canvasHeight / this.scrollHeight),10); + this.scrollTop = Math.min(this.startIndex / this.lines.length * canvasHeight,canvasHeight - this.slideHeight); + this.context.save(); + this.context.beginPath(); + var x = this.canvas.width - 8; + var y = this.scrollTop; + var r = 4; + var width = 8; + var height = this.slideHeight; + this.context.fillStyle = '#f1f1f1'; + this.context.fillRect(x,0,8,canvasHeight); + + + this.context.moveTo(x + r, y); + this.context.arcTo(x + width, y, x + width, y + r, r); + this.context.arcTo(x + width, y + height, x + width - r, y + height, r); + this.context.arcTo(x, y + height, x, y + height - r, r); + this.context.arcTo(x, y, x + r, y, r); + if(this.mouseEvent == 1){ + this.context.fillStyle = '#787878'; + }else if(this.mouseX > x && this.mouseY > y &&this.mouseY < y + height){ + this.context.fillStyle = '#a8a8a8'; + }else{ + this.context.fillStyle = '#c1c1c1'; + } + this.context.fill(); + this.context.restore(); + } + // + this.hasXScroll = this.maxWidth > this.canvas.width - 8; + if(this.hasXScroll){ + var canvasWidth = this.canvas.width - 8; + this.scrollWidth = this.maxWidth; + this.slideWidth = Math.max(canvasWidth * (canvasWidth / this.scrollWidth),10); + + this.scrollLeft = Math.min(-this.startX / this.maxWidth * canvasWidth,canvasWidth - this.slideWidth); + this.context.save(); + this.context.beginPath(); + var x = this.scrollLeft; + var y = this.canvas.height - 8; + var r = 4; + var width = this.slideWidth; + var height = 8; + this.context.fillStyle = '#f1f1f1'; + this.context.fillRect(0,this.canvas.height - 8,canvasWidth,8); + + this.context.moveTo(x + r, y); + this.context.arcTo(x + width, y, x + width, y + r, r); + this.context.arcTo(x + width, y + height, x + width - r, y + height, r); + this.context.arcTo(x, y + height, x, y + height - r, r); + this.context.arcTo(x, y, x + r, y, r); + if(this.mouseEvent == 2){ + this.context.fillStyle = '#787878'; + }else if(this.mouseX > x && this.mouseY > y &&this.mouseX < x + width){ + this.context.fillStyle = '#a8a8a8'; + }else{ + this.context.fillStyle = '#c1c1c1'; + } + this.context.fill(); + this.context.restore(); + } +} +CanvasViewer.prototype.scrollTo = function(index){ + if(index < 0){ + index = this.lines.length - 1; + } + this.startIndex = Math.max(Math.min(Math.max(index,0),this.lines.length - this.maxRows),0); + if(this.startIndex > 0){ + this.startIndex = this.startIndex + 1; + } +} +CanvasViewer.prototype.redraw = function(){ + var lines = this.lines.slice(this.startIndex,this.startIndex + this.maxRows); + this.context.clearRect(0,0,this.canvas.width,this.canvas.height); + this.context.lineWidth = 1; + this.context.strokeStyle = '#e6e6e6'; + this.context.font = this.style.font || 'bold 14px Consolas'; + this.context.textBaseline = this.style.textBaseLine || 'middle'; + var cols = [0]; + var maxY = 0; + var maxX = 0; + for(var i=0,l =lines.length;i 0){ + width = this._drawLongText(content,x,y,text.maxWidth); + }else{ + this.context.fillText(content,x,y); + } + text.startX = x; + text.endX = x + width; + x = x + ((this.grid ? this.colsOffsetX[j] : 0) || width) + 10; + maxX = x - 5; + if(this.grid){ + cols[j + 1] = Math.max(cols[j + 1] || 0,maxX); + } + } + } + if(this.grid && lines.length > 0){ + for(var i=0;i<=lines.length;i++){ + if(this.grid){ + this.context.save(); + this.context.beginPath(); + this.context.moveTo(2.5,i * 24 + 0.5); + this.context.lineTo(maxX + 0.5, i * 24 + 0.5); + this.context.stroke(); + this.context.restore(); + } + } + for(var i=0;i < cols.length;i++){ + var x = cols[i]; + this.context.save(); + this.context.beginPath(); + this.context.moveTo(x + 0.5,0.5); + this.context.lineTo(x + 0.5, maxY); + this.context.stroke(); + this.context.restore(); + } + } + this._drawScroll(); +} +CanvasViewer.prototype._drawLongText = function(text,x,y,maxWidth,calcWidth){ + var length = text.length; + var index = 0; + var width = 0; + while(index < length){ + var str = text.substr(index,1); + var w = this.context.measureText(str).width; + width+= w; + if(width > maxWidth){ + width-=w; + break; + } + if(calcWidth === undefined){ + this.context.fillText(str,x + width - w,y); + } + index++; + } + if(index < length){ + var w = this.context.measureText('...').width; + width+=w; + if(calcWidth === undefined){ + this.context.fillText('...',x + width - w,y); + } + + } + return width; +} \ No newline at end of file diff --git a/spider-flow-web/src/main/resources/static/js/editor.js b/spider-flow-web/src/main/resources/static/js/editor.js index 36cb342..06e538f 100644 --- a/spider-flow-web/src/main/resources/static/js/editor.js +++ b/spider-flow-web/src/main/resources/static/js/editor.js @@ -559,9 +559,11 @@ function bindToolbarClickAction(editor){ // editor.setXML($(".xml-container textarea").val()); // editor.onSelectedCell(); }).on('click','.btn-test',function(){ + var LogViewer; + var tableMap = {}; layui.layer.open({ id : 'test-window', - content : '
', + content : '
', area : ["1000px","600px"], shade : 0, title : '测试窗口', @@ -571,17 +573,19 @@ function bindToolbarClickAction(editor){ var $log = $(".test-window-container .log-container"); if($output.is(":hidden")){ $output.show(); - $output.css({ - height : $log.is(":hidden") ? '420px' : '320px' - }) - $log.css({ - maxHeight : '100px' - }) + $output.find("canvas").css('height', $log.is(":hidden") ? 460 : 320) + $log.attr('height',100) + LogViewer.resize(); + for(var tableId in tableMap){ + tableMap[tableId].resize(); + } }else{ $output.hide(); - $log.css({ - maxHeight : '420px' - }) + $log.attr('height',460); + LogViewer.resize(); + for(var tableId in tableMap){ + tableMap[tableId].resize(); + } } return false; }, @@ -590,25 +594,36 @@ function bindToolbarClickAction(editor){ var $log = $(".test-window-container .log-container"); if($log.is(":hidden")){ $log.show(); - $log.css({ - maxHeight : $output.is(":hidden") ? '420px' : '100px' - }) - $output.css({ - height : '320px' - }) + $log.attr('height',$output.is(":hidden") ? 460 : 100) + $output.find("canvas").attr('height',320); + LogViewer.resize(); + for(var tableId in tableMap){ + tableMap[tableId].resize(); + } }else{ $log.hide(); - $output.css({ - height : '420px' - }) + $output.find("canvas").attr('height',460); + LogViewer.resize(); + for(var tableId in tableMap){ + tableMap[tableId].resize(); + } } - var logElement = $(".test-window-container .log-container")[0]; - logElement.scrollTop = logElement.scrollHeight; return false; }, success : function(){ - var tableMap = {}; var logElement = $(".test-window-container .log-container")[0]; + var colors = { + 'array' : '#2a00ff', + 'object' : '#2a00ff', + 'boolean' : '#600100', + 'number' : '#000E59' + } + LogViewer = new CanvasViewer({ + element : logElement, + onClick : function(e){ + onCanvasViewerClick(e,'日志'); + } + }) var socket = createWebSocket({ onopen : function(){ socket.send(JSON.stringify({ @@ -624,55 +639,59 @@ function bindToolbarClickAction(editor){ var tableId = 'output-' + message.nodeId; var $table = $('#' + tableId); if($table.length == 0){ - $table = $('').appendTo($(".test-window-container .output-container")); - $table.attr('id',tableId).attr("class","layui-table").attr("size","mini"); - var cols = []; - for(var i =0,len = message.outputNames.length;i').appendTo($(".test-window-container .output-container")); + $table.attr('id',tableId); + tableMap[tableId] = new CanvasViewer({ + element : document.getElementById(tableId), + grid : true, + header : true, + style : { + font : '12px Arial' + }, + onClick : function(e){ + onCanvasViewerClick(e,'表格'); + } }) + var cols = []; + var texts = []; + for(var i =0,len = message.outputNames.length;i' + displayText + '') + texts.push(new CanvasText({ + text : displayText, + maxWidth : 230, + color : colors[variableType] || '#025900', + click : true + })) } } - messageElement.innerHTML = msg; - div.appendChild(messageElement); - fragment.appendChild(div); - logElement.appendChild(fragment); - logElement.scrollTop = logElement.scrollHeight; + LogViewer.append(texts); + LogViewer.scrollTo(-1); } } }); @@ -708,34 +723,34 @@ function bindToolbarClickAction(editor){ }).on('click','.btn-save',function(){ Save(); }) - $('body').on('click','.log-container .variable',function(){ - var msg = $(this).html(); - var json; - try{ - json = JSON.parse(msg); - if(!(Array.isArray(json) || typeof json == 'object')){ - json = null; - } - }catch(e){ - +} +function onCanvasViewerClick(e,source){ + var msg = e.text; + var json; + try{ + json = JSON.parse(msg); + if(!(Array.isArray(json) || typeof json == 'object')){ + json = null; } - layer.open({ - type : 1, - title : '日志内容', - content: '
'+(json ? '' : msg.replace(/\n/g,'
'))+'
', - shade : 0, - area : json ? ['700px','500px'] : 'auto', - maxmin : true, - maxWidth : json ? undefined : 700, - maxHeight : json ? undefined : 500, - success : function(dom,index){ - var $dom = $(dom).find(".message-content"); - if(json){ - jsonTree.create(json,$dom[0]); - } - } - }); - }); + }catch(e){ + + } + layer.open({ + type : 1, + title : source +'内容', + content: '
'+(json ? '' : msg.replace(/\n/g,'
'))+'
', + shade : 0, + area : json ? ['700px','500px'] : 'auto', + maxmin : true, + maxWidth : json ? undefined : 700, + maxHeight : json ? undefined : 500, + success : function(dom,index){ + var $dom = $(dom).find(".message-content"); + if(json){ + jsonTree.create(json,$dom[0]); + } + } + }); } function createWebSocket(options){ options = options || {};