【问题标题】:How to build a polygon drawing tool as a functional react component?如何构建多边形绘图工具作为功能性反应组件?
【发布时间】:2021-03-27 11:00:48
【问题描述】:

因此,我目前正在开展一个项目,该项目需要与您在平面布置图设计应用程序中所期望的功能相似的项目,并且我需要能够通过连接点击生成的点来绘制一个多边形(房间),线(墙)。

我发现了一些与我正在寻找的功能相似的非常棒的示例,但我不确定如何将其实现为功能性反应组件。

我已经看到 Fabric.jsKonva.js 在此类功能的其他一些实现中使用,但我似乎无法找到一个反应示例作为参考。

以下是我在codepen 上使用 jQuery 找到的示例

var min = 99;
var max = 999999;
var polygonMode = true;
var pointArray = new Array();
var lineArray = new Array();
var activeLine;
var activeShape = false;
var canvas
$(window).load(function() {
  prototypefabric.initCanvas();
  $('#create-polygon').click(function() {
    prototypefabric.polygon.drawPolygon();
  });
});
var prototypefabric = new function() {
  this.initCanvas = function() {
    canvas = window._canvas = new fabric.Canvas('c');
    canvas.setWidth($(window).width());
    canvas.setHeight($(window).height() - $('#nav-bar').height());
    //canvas.selection = false;

    canvas.on('mouse:down', function(options) {
      if (options.target && options.target.id == pointArray[0].id) {
        prototypefabric.polygon.generatePolygon(pointArray);
      }
      if (polygonMode) {
        prototypefabric.polygon.addPoint(options);
      }
    });
    canvas.on('mouse:up', function(options) {

    });
    canvas.on('mouse:move', function(options) {
      if (activeLine && activeLine.class == "line") {
        var pointer = canvas.getPointer(options.e);
        activeLine.set({
          x2: pointer.x,
          y2: pointer.y
        });

        var points = activeShape.get("points");
        points[pointArray.length] = {
          x: pointer.x,
          y: pointer.y
        }
        activeShape.set({
          points: points
        });
        canvas.renderAll();
      }
      canvas.renderAll();
    });
  };
};



prototypefabric.polygon = {
  drawPolygon: function() {
    polygonMode = true;
    pointArray = new Array();
    lineArray = new Array();
    activeLine;
  },
  addPoint: function(options) {
    var random = Math.floor(Math.random() * (max - min + 1)) + min;
    var id = new Date().getTime() + random;
    var circle = new fabric.Circle({
      radius: 5,
      fill: '#ffffff',
      stroke: '#333333',
      strokeWidth: 0.5,
      left: (options.e.layerX / canvas.getZoom()),
      top: (options.e.layerY / canvas.getZoom()),
      selectable: false,
      hasBorders: false,
      hasControls: false,
      originX: 'center',
      originY: 'center',
      id: id,
      objectCaching: false
    });
    if (pointArray.length == 0) {
      circle.set({
        fill: 'red'
      })
    }
    var points = [(options.e.layerX / canvas.getZoom()), (options.e.layerY / canvas.getZoom()), (options.e.layerX / canvas.getZoom()), (options.e.layerY / canvas.getZoom())];
    line = new fabric.Line(points, {
      strokeWidth: 2,
      fill: '#999999',
      stroke: '#999999',
      class: 'line',
      originX: 'center',
      originY: 'center',
      selectable: false,
      hasBorders: false,
      hasControls: false,
      evented: false,
      objectCaching: false
    });
    if (activeShape) {
      var pos = canvas.getPointer(options.e);
      var points = activeShape.get("points");
      points.push({
        x: pos.x,
        y: pos.y
      });
      var polygon = new fabric.Polygon(points, {
        stroke: '#333333',
        strokeWidth: 1,
        fill: '#cccccc',
        opacity: 0.3,
        selectable: false,
        hasBorders: false,
        hasControls: false,
        evented: false,
        objectCaching: false
      });
      canvas.remove(activeShape);
      canvas.add(polygon);
      activeShape = polygon;
      canvas.renderAll();
    } else {
      var polyPoint = [{
        x: (options.e.layerX / canvas.getZoom()),
        y: (options.e.layerY / canvas.getZoom())
      }];
      var polygon = new fabric.Polygon(polyPoint, {
        stroke: '#333333',
        strokeWidth: 1,
        fill: '#cccccc',
        opacity: 0.3,
        selectable: false,
        hasBorders: false,
        hasControls: false,
        evented: false,
        objectCaching: false
      });
      activeShape = polygon;
      canvas.add(polygon);
    }
    activeLine = line;

    pointArray.push(circle);
    lineArray.push(line);

    canvas.add(line);
    canvas.add(circle);
    canvas.selection = false;
  },
  generatePolygon: function(pointArray) {
    var points = new Array();
    $.each(pointArray, function(index, point) {
      points.push({
        x: point.left,
        y: point.top
      });
      canvas.remove(point);
    });
    $.each(lineArray, function(index, line) {
      canvas.remove(line);
    });
    canvas.remove(activeShape).remove(activeLine);
    var polygon = new fabric.Polygon(points, {
      stroke: '#333333',
      strokeWidth: 0.5,
      fill: 'red',
      opacity: 1,
      hasBorders: false,
      hasControls: false
    });
    canvas.add(polygon);

    activeLine = null;
    activeShape = null;
    polygonMode = false;
    canvas.selection = true;
  }
};
* {
  font-family: "Roboto", sans-serif;
  font-weight: 100;
}

body {
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.2.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet" />

<nav class="grey darken-4" role="navigation" id="nav-bar" style="height:50px;">
  <div class="nav-wrapper container">
    <a id="logo-container" class="brand-logo" style="line-height: 50px;font-size: 20px;">Fabric Polygon</a>
    <ul id="nav-mobile" class="right hide-on-med-and-down">
      <li><a id="create-polygon" style="line-height: 50px;font-size: 20px;cursor:pointer;">Create Polygon</a></li>
    </ul>
  </div>
</nav>
<div class="section no-pad-bot no-pad-top">
  <canvas id="c"></canvas>
</div>

这基本上是我想要实现的最终功能。

非常感谢任何帮助或建议!

【问题讨论】:

  • 您好,我正在寻找类似的东西。你最后做了什么?

标签: javascript reactjs canvas fabricjs polygon


【解决方案1】:

首先,您应该记住,react 旨在构建应用程序的可视组件以及它们与其余代码的交互,也就是说,react 不是一个涵盖您可能需要的所有内容的框架。

我什至不确定 react 是你需要的,也许你需要一个画布。也许画布驻留在反应组件中。

尽管如此,如果您决定要使用 react 来实现它,那么让我们在视觉上分解您需要的内容:

  • 一个包含所有多边形或线条的“画布”组件
  • 包含线条的“多边形”
  • “线”组件。

首先,在交互之前,请确保您创建了一个有意义的状态,该状态将被发送到画布,可能是一组多边形或线对象。一个线对象显然是两个点,可能是一种颜色等。

如果你已经对你的 polgyon 状态进行了模拟,那么是时候添加一个状态管理器(如 redux)和一些事件侦听器来在 DOM 中发生事件(如鼠标或键盘事件)时更新状态。

总结一下:

  • 对视觉元素使用 react。
  • 使用 redux 管理画布的状态。
  • 在初始化父组件(“画布”)时,创建事件侦听器来触发影响状态的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 2015-04-03
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    相关资源
    最近更新 更多