用konva在画布上绘制像表格这样的电子表格 [英] Drawing a spreadsheet like grid in canvas with konva

查看:607
本文介绍了用konva在画布上绘制像表格这样的电子表格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用HTML5画布和Konvajs画布库来进行类似于甘特图的任务显示.

将甘特图解构成其各个组成部分,目前使我产生如下视图.这里1是任务列表,2是任务栏区域,3是任务栏,4是文本单元格.

对于这个问题,我正在寻找构建1&的代码. 4.将要显示的数据将在带有嵌套任务列表的普通JS对象中传递,其中每个任务都有一个数字,名称,分配给人员的姓名,开始日期,结束日期,工期和完成百分比.

因此,要求是能够构建类似于电子表格的面板,如在甘特图的左侧所示.

我开发了一些内容,并将其作为答案发布.但是,这似乎很常见,我希望有人在那里可以使用他们可以剪切的代码.粘贴到SO中以带路.

注意:示例图像中的甘特图来自 Vertex42 . /p>

解决方案

所以这是我自己摸索的一种尝试.任何人都可以改进它,还是我走错了路.

我现在有一个雏鸟组件,用于将文本绘制到类似电子表格的单元格中,包括百分比完整阴影.为使答案清晰易懂,此附加组件位于此codepen 中.

 // this is the object that defines our grid
// 
var gridData = { name: 'grid1', width: 350, height: 400, rowHeight: 24, padding: 4, fill: 'azure', gridLineColor: '#ccc',  header: {size: 16, fill: 'black', color: 'white' },  data: {size: 16, fill: 'azure', color: 'black' },  
  row: [
      { cells:   // row 1
        [
          { width: 50, text: 'Item', style: 'header'},
          { width: 240, text: 'Name', style: 'header'},
          { width: 60, text: 'Status', style: 'header'},
        ]
      },
      { cells:    // row 2
        [
          { text: '1'},
          { text: 'Find tea pot'},
          { text: '100%'},
        ]
      },
      { cells:    // row 3
        [
          { text: '2'},
          { text: 'Boil water'},
          { text: '60%'},
        ]
      }
  ]
}

// From here on could be wrapped into a component that churns out grids. Maybe you pass in the id of the stage container
// and the data model you want to produce, etc.

// Set up the canvas / stage
var stage = new Konva.Stage({container: 'container1', width: 600, height: 300});

// Add a layer 
var layer = new Konva.Layer({draggable: false});
stage.add(layer);

// make a main group for the grid, call it a panel. Assigning a name may be handy later
var panel = new Konva.Group({name: gridData.name});  
layer.add(panel);  // Add the panel to the layer

// a group has no visual properties. Add a background rect to hold the colour fill
var panelRect = new Konva.Rect({width: gridData.width, height: gridData.height, fill: gridData.fill}) 
panel.add(panelRect);

var topLeft = {x: 0, y: 0}; // Since we are drawing a grid, we need to compute the position of each cell
for (var i = 0; i < gridData.row.length; i = i + 1){

  topLeft.x = 0; // reset x at start of each row
  
  // iterate for each cell on the row
  for (var j = 0; j < gridData.row[i].cells.length; j = j + 1){

    var cell = new Konva.Rect({name: 'cellBg',                          // assign a name for later searching 
                               x: topLeft.x, y: topLeft.y,              // position as computed 
                               width:  gridData.row[0].cells[j].width,  // use the first row from celldate to get the cell width
                               height: gridData.rowHeight,              // grid has a uniform row height
                               stroke: gridData.gridLineColor,          // and line colour
                               strokeWidth: 1,                          // use a set line width but you can add to the gridData object as needed.
                               fill: (i === 0 ? gridData.header.fill : gridData.data.fill),              // use the given header text color
                              });
    panel.add(cell);

    // Add text to the cell. Note that if you wanted to be using alignments you would need to draw the text off-screen and 
    // get width/height of that text then use those values for positioning calculations. Once you have the rect size of the
    // text, all the alignments are simple math.
    var text = new Konva.Text({ x: topLeft.x + gridData.padding,        // add padding to locate the text nicely into the cell 
                               y: topLeft.y + gridData.padding, 
                                                                        // use the given text size
                               fontSize: (i === 0 ? gridData.header.size : gridData.data.size),
                                                                       // use the given header text color
                               fill: (i === 0 ? gridData.header.color : gridData.data.color),              
                               text: gridData.row[i].cells[j].text,   // set the text value.
                               listening: false                       // stop text interfering with mouse events
                              });
    panel.add(text);
    
    cell.on('mouseover', function(evt){
      var shape = evt.target;
      $(shape).data('bgColor', shape.fill());
      shape.fill('lime');
      layer.draw();      
    })
    cell.on('mouseout', function(evt){
      var shape = evt.target;
      shape.fill($(shape).data('bgColor'));
      layer.draw();      
    })

    
    topLeft.x = topLeft.x + gridData.row[0].cells[j].width;             // offset the computed next cell x value by the width of the cell  
  }
  
  topLeft.y = topLeft.y +  gridData.rowHeight;                          // offset the computed next cell y value by the height of the row   
}

layer.draw();
stage.draw(); 

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.min.js"></script>
<div id='container1' style="width: 300px, height: 200px; background-color: silver;"></div> 

I am working on a Gantt-like task display using HTML5 canvas, and the Konvajs canvas library.

Deconstructing a Gantt chart into its components leads me currently to a view as below. Here 1 is the list of tasks, 2 is the task bar area, 3 is a task bar, and 4 is a text cell.

For this question I am seeking code to construct 1 & 4. The data to be displayed will be delivered in plain JS objects with a nested list of tasks where each task has a number, name, assigned-to person name, start date, end date, days duration, and % complete.

So the requirement is to be able to construct a spreadsheet-like panel such as is seen on the left hand side of a Gantt chart.

I have something part developed which I shall post as an answer. However this seems like such as common need that I am hoping there is someone out there with code they can cut & paste into SO to lead the way.

Note: Gantt in sample image is from Vertex42.

解决方案

So here is my own fumbling attempt at an approach. Can anyone improve upon it or am I going down the wrong road.

EDIT: I now have a fledgling component for drawing text into the spreadsheet-like cells, including the percent complete shading. To keep this answer uncluttered, this additional component is in this codepen.

// this is the object that defines our grid
// 
var gridData = { name: 'grid1', width: 350, height: 400, rowHeight: 24, padding: 4, fill: 'azure', gridLineColor: '#ccc',  header: {size: 16, fill: 'black', color: 'white' },  data: {size: 16, fill: 'azure', color: 'black' },  
  row: [
      { cells:   // row 1
        [
          { width: 50, text: 'Item', style: 'header'},
          { width: 240, text: 'Name', style: 'header'},
          { width: 60, text: 'Status', style: 'header'},
        ]
      },
      { cells:    // row 2
        [
          { text: '1'},
          { text: 'Find tea pot'},
          { text: '100%'},
        ]
      },
      { cells:    // row 3
        [
          { text: '2'},
          { text: 'Boil water'},
          { text: '60%'},
        ]
      }
  ]
}

// From here on could be wrapped into a component that churns out grids. Maybe you pass in the id of the stage container
// and the data model you want to produce, etc.

// Set up the canvas / stage
var stage = new Konva.Stage({container: 'container1', width: 600, height: 300});

// Add a layer 
var layer = new Konva.Layer({draggable: false});
stage.add(layer);

// make a main group for the grid, call it a panel. Assigning a name may be handy later
var panel = new Konva.Group({name: gridData.name});  
layer.add(panel);  // Add the panel to the layer

// a group has no visual properties. Add a background rect to hold the colour fill
var panelRect = new Konva.Rect({width: gridData.width, height: gridData.height, fill: gridData.fill}) 
panel.add(panelRect);

var topLeft = {x: 0, y: 0}; // Since we are drawing a grid, we need to compute the position of each cell
for (var i = 0; i < gridData.row.length; i = i + 1){

  topLeft.x = 0; // reset x at start of each row
  
  // iterate for each cell on the row
  for (var j = 0; j < gridData.row[i].cells.length; j = j + 1){

    var cell = new Konva.Rect({name: 'cellBg',                          // assign a name for later searching 
                               x: topLeft.x, y: topLeft.y,              // position as computed 
                               width:  gridData.row[0].cells[j].width,  // use the first row from celldate to get the cell width
                               height: gridData.rowHeight,              // grid has a uniform row height
                               stroke: gridData.gridLineColor,          // and line colour
                               strokeWidth: 1,                          // use a set line width but you can add to the gridData object as needed.
                               fill: (i === 0 ? gridData.header.fill : gridData.data.fill),              // use the given header text color
                              });
    panel.add(cell);

    // Add text to the cell. Note that if you wanted to be using alignments you would need to draw the text off-screen and 
    // get width/height of that text then use those values for positioning calculations. Once you have the rect size of the
    // text, all the alignments are simple math.
    var text = new Konva.Text({ x: topLeft.x + gridData.padding,        // add padding to locate the text nicely into the cell 
                               y: topLeft.y + gridData.padding, 
                                                                        // use the given text size
                               fontSize: (i === 0 ? gridData.header.size : gridData.data.size),
                                                                       // use the given header text color
                               fill: (i === 0 ? gridData.header.color : gridData.data.color),              
                               text: gridData.row[i].cells[j].text,   // set the text value.
                               listening: false                       // stop text interfering with mouse events
                              });
    panel.add(text);
    
    cell.on('mouseover', function(evt){
      var shape = evt.target;
      $(shape).data('bgColor', shape.fill());
      shape.fill('lime');
      layer.draw();      
    })
    cell.on('mouseout', function(evt){
      var shape = evt.target;
      shape.fill($(shape).data('bgColor'));
      layer.draw();      
    })

    
    topLeft.x = topLeft.x + gridData.row[0].cells[j].width;             // offset the computed next cell x value by the width of the cell  
  }
  
  topLeft.y = topLeft.y +  gridData.rowHeight;                          // offset the computed next cell y value by the height of the row   
}

layer.draw();
stage.draw();

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.min.js"></script>
<div id='container1' style="width: 300px, height: 200px; background-color: silver;"></div>

这篇关于用konva在画布上绘制像表格这样的电子表格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆