css Fabric.js便笺类型文字环绕

brqmpdu1  于 2022-12-05  发布在  其他
关注(0)|答案(3)|浏览(151)

我正试图使一个便利贴类型的实用程序与织物画布。它将有助于被用作注解器。
我希望文本在给定的矩形宽度上自动换行。
有人能更新我的小提琴作品吗?
非常感谢您的建议。
下面是我的小提琴的一部分的链接:
http://jsfiddle.net/U7E9q/5/

var canvas = new fabric.Canvas('fabric-canvas');

canvas.hoverCursor = 'pointer';

var text = new fabric.IText("Enter Text Here ",{
      fontSize: 20,
      top: 100,
      left: 100,
      backgroundColor: '#faa',
      lockScalingX: true,
      lockScalingY: true,
      selectable: true
});
//alert(text.text);
  var rect   = new fabric.Rect({
    text_field: text,
    width: 200,
    height: 50,
    fill: '#faa',
    rx: 10,
    ry: 10,
    top: 100,
    left: 100
  });

  canvas.add(rect);
  canvas.add(text);

canvas.on('object:moving', function (event){
   canvas.renderAll(); 
});

createListenersKeyboard();

function createListenersKeyboard() {
    document.onkeydown = onKeyDownHandler;
    //document.onkeyup = onKeyUpHandler;
}

function onKeyDownHandler(event) {
    //event.preventDefault();

    var key;
    if(window.event){
        key = window.event.keyCode;
    }
    else{
        key = event.keyCode;
    }

    switch(key){
        //////////////
        // Shortcuts
        //////////////
        // Copy (Ctrl+C)
        case 67: // Ctrl+C
            if(ableToShortcut()){
                if(event.ctrlKey){
                    event.preventDefault();
                    copy();
                }
            }
            break;
        // Delete (Ctrl+D)
        case 127: // Ctrl+D
            if(ableToShortcut()){
                if(event.deleteKey){
                    delet();
                }
            }
            break;            
        // Paste (Ctrl+V)
        case 86: // Ctrl+V
            if(ableToShortcut()){
                if(event.ctrlKey){
                    event.preventDefault();
                    paste();
                }
            }
            break;            
        default:
            // TODO
            break;
    }
}

function ableToShortcut(){
    /*
    TODO check all cases for this

    if($("textarea").is(":focus")){
        return false;
    }
    if($(":text").is(":focus")){
        return false;
    }
    */
    return true;
}

function copy(){
    if(canvas.getActiveGroup()){
        for(var i in canvas.getActiveGroup().objects){
            var object = fabric.util.object.clone(canvas.getActiveGroup().objects[i]);
            object.set("top", object.top+5);
            object.set("left", object.left+5);
            copiedObjects[i] = object;
        }                    
    }
    else if(canvas.getActiveObject()){
        var object = fabric.util.object.clone(canvas.getActiveObject());
        object.set("top", object.top+5);
        object.set("left", object.left+5);
        copiedObject = object;
        copiedObjects = new Array();
    }
}

function paste(){
    if(copiedObjects.length > 0){
        for(var i in copiedObjects){
            canvas.add(copiedObjects[i]);
        }                    
    }
    else if(copiedObject){
        canvas.add(copiedObject);
    }
    canvas.renderAll();    
}

function delet(){
        var activeObject = canvas.getActiveObject();
        canvas.remove(activeObject);
        console.log('after remove getActiveObject(): ', canvas.getActiveObject(), activeObject === canvas.getActiveObject());
        canvas.renderAll();    
}
6mzjoqzu

6mzjoqzu1#

如果你把便笺条作为一个矩形和文本的组合来管理,你可以改进同样的行为。当你需要编辑组中的文本时,你只需要取消组合并克隆元素,将克隆的元素附加到画布上,并将文本设置为可编辑。
您需要处理类似双击的事件来处理此行为,然后处理鼠标按下或与画布的其他交互来重新组合它们。

798qvoo8

798qvoo82#

http://jsfiddle.net/4HE3U/1/
以上是一把能让你满意的小提琴
基本上我已经做了一组文本和矩形,我已经把它添加到画布。只有一个变化,你需要做的是,你可以采取一个文本框,以获得当前的即时贴文本内容,因为我们不能编辑文本的i-文本在线一旦我们添加到任何组。目前没有办法为IText处理的事件,因为他们没有传递给它,如果它包含在一个组。我认为这也是处理这个问题的首选方法,因为它会让用户感到困惑--如果他开始编辑多个文本怎么办?这可能会导致混乱。也许你可以稍微修改一下你的脚本来解决这个问题。
我已添加文本和矩形
第一个

tjvv9vkg

tjvv9vkg3#

这里是便笺功能。文字换行工作和字体大小改变w.r.t便笺宽度和高度。编辑模式激活双击。

export const createStickyNotes = (canvas, options) => {
  fabric.StickyNote = fabric.util.createClass(fabric.Group, {
    type: "StickyNote",
    initialize: function (options) {
      this.set(options);
      var height = this.height;
      var width = this.width;

      this.rectObj = new fabric.Rect({
        width: width,
        height: height,
        fill: this.rectObj?.fill ?? "rgba(251,201,112,1)",
        originX: "center",
        originY: "center",
        objectCaching: false,
        stateProperties: ["fill"],
      });
      this.textObj = new fabric.Textbox(this.textObj?.text ?? "Notes", {
        originX: "center",
        originY: "center",
        textAlign: "center",
        width: 100,
        hasControls: false,
        fontSize: this.textObj?.fontSize ?? 30,
        lineHeight: 1,
        stateProperties: ["text", "fontSize"],
        scaleX: this.textObj?.scaleX ?? 1,
        scaleY: this.textObj?.scaleY ?? 1,
        objectCaching: false,
        breakWords: true,
        fontFamily: "Open Sans",
      });

      this._objects = [this.rectObj, this.textObj];
      //   this custom _set function will set custom properties value to object when it will load from json.
      // at that time loadFromJson function will call this initialize function.
      // this._setCustomProperties(this.options);
      canvas.renderAll();

      //evenet will fire if the object is double clicked by mouse
      this.on("mousedblclick", (e) => {
        var pasteFlag = false;
        var scaling = e.target.getScaledWidth() / 100;
        var textForEditing;
        canvas.bringToFront(e.target);
        e.target.selectable = false;
        const [rectObj, textObj] = this.getObjects();
        textObj.clone(function (clonedObj) {
          clonedObj.set({
            left: e.target.left,
            top: e.target.top,
            lockMovementY: true,
            lockMovementX: true,
            hasBorders: false,
            scaleX: scaling,
            scaleY: scaling,
            breakWords: true,
            width: textObj.width,
            stateProperties: [],
          });
          textForEditing = clonedObj;
        });

        this.remove(textObj);
        canvas.add(textForEditing);
        canvas.setActiveObject(textForEditing);

        textForEditing.enterEditing();
        textForEditing.selectAll();

        textForEditing.paste = (function (paste) {
          return function (e) {
            disableScrolling();
            pasteFlag = true;
          };
        })(textForEditing.paste);

        textForEditing.on("changed", function (e) {
          var fontSize = textForEditing.fontSize;
          var charCount = Math.max(textForEditing._text.length, 1);
          var charWR =
            (textForEditing.textLines.length * width) / (charCount * fontSize);

          if (textForEditing.height < height - 15) {
            fontSize = Math.min(
              Math.sqrt(
                ((height - 10 - fontSize) / 1.16) *
                  (width / (charCount * charWR))
              ),
              30
            );
          }
          if (textForEditing.height > height - 15) {
            fontSize = Math.sqrt(
              ((height - 10) / 1.16) * (width / (charCount * charWR))
            );
          }
          if (pasteFlag) {
            pasteFlag = false;
            while (
              textForEditing.height > height - 15 &&
              textForEditing.fontSize > 0
            ) {
              fontSize = textForEditing.fontSize -= 0.2;
              canvas.renderAll();
            }
          }
          textForEditing.fontSize = fontSize;
        });

        textForEditing.on("editing:exited", () => {
          enableScrolling();
          canvas.setActiveObject(textObj);
          textObj.set({
            text: textForEditing.text,
            fontSize: textForEditing.fontSize,
            visible: true,
          });
          this.add(textObj);
          this.selectable = true;
          canvas.remove(textForEditing);
          canvas.discardActiveObject();
        });
      });

      function disableScrolling() {
        var x = window.scrollX;
        var y = window.scrollY;
        window.onscroll = function () {
          window.scrollTo(x, y);
        };
      }

      var _wrapLine = function (_line, lineIndex, desiredWidth, reservedSpace) {
        var lineWidth = 0,
          splitByGrapheme = this.splitByGrapheme,
          graphemeLines = [],
          line = [],
          // spaces in different languges?
          words = splitByGrapheme
            ? fabric.util.string.graphemeSplit(_line)
            : _line.split(this._wordJoiners),
          word = "",
          offset = 0,
          infix = splitByGrapheme ? "" : " ",
          wordWidth = 0,
          infixWidth = 0,
          largestWordWidth = 0,
          lineJustStarted = true,
          additionalSpace = splitByGrapheme ? 0 : this._getWidthOfCharSpacing();

        reservedSpace = reservedSpace || 0;
        desiredWidth -= reservedSpace;
        for (var i = 0; i < words.length; i++) {
          // i would avoid resplitting the graphemes
          word = fabric.util.string.graphemeSplit(words[i]);
          wordWidth = this._measureWord(word, lineIndex, offset);
          offset += word.length;

          // Break the line if a word is wider than the set width
          if (this.breakWords && wordWidth >= desiredWidth) {
            if (!lineJustStarted) {
              graphemeLines.push(line);
              line = [];
              lineWidth = 0;
              lineJustStarted = true;
            }
            this.fontSize *= desiredWidth / (wordWidth + 1);
            // Loop through each character in word
            for (var w = 0; w < word.length; w++) {
              var letter = word[w];
              var letterWidth =
                (this.getMeasuringContext().measureText(letter).width *
                  this.fontSize) /
                this.CACHE_FONT_SIZE;
              line.push(letter);
              lineWidth += letterWidth;
            }
            word = [];
          } else {
            lineWidth += infixWidth + wordWidth - additionalSpace;
          }

          if (lineWidth >= desiredWidth && !lineJustStarted) {
            graphemeLines.push(line);
            line = [];
            lineWidth = wordWidth;
            lineJustStarted = true;
          } else {
            lineWidth += additionalSpace;
          }

          if (!lineJustStarted) {
            line.push(infix);
          }
          line = line.concat(word);

          infixWidth = this._measureWord([infix], lineIndex, offset);
          offset++;
          lineJustStarted = false;
          // keep track of largest word
          if (wordWidth > largestWordWidth && !this.breakWords) {
            largestWordWidth = wordWidth;
          }
        }

        i && graphemeLines.push(line);

        if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {
          this.dynamicMinWidth =
            largestWordWidth - additionalSpace + reservedSpace;
        }

        return graphemeLines;
      };

      fabric.util.object.extend(fabric.Textbox.prototype, {
        _wrapLine: _wrapLine,
      });

      function enableScrolling() {
        window.onscroll = function () {};
      }
    },

    toObject: function (propertiesToInclude) {
      // This function is used for serialize this object. (used for create json)
      // not inlclude this.textObj and this.rectObj into json because when object will load from json, init fucntion of this class is called and it will assign this two object textObj and rectObj again.
      var obj = this.callSuper(
        "toObject",
        [
          "objectCaching",
          "textObj",
          "rectObj",
          // ... property list that you want to add into json when this object is convert into json using toJSON() function. (serialize)
        ].concat(propertiesToInclude)
      );
      // delete objects array from json because then object load from json, Init function will call. which will automatically re-assign object and assign _object array.
      delete obj.objects;
      return obj;
    },
  });

  fabric.StickyNote.async = true;
  fabric.StickyNote.fromObject = function (object, callback) {
    // This function is used for deserialize json and convert object json into button object again. (called when we call loadFromJson() fucntion on canvas)
    return fabric.Object._fromObject("StickyNote", object, callback);
  };

  return new fabric.StickyNote(options);
};
//How to use 

 var options = {
      width: 100,
      height: 100,
      originX: "center",
      originY: "center",
    };
    var notes = StickyNotes(canvas, options);
    canvas.add(notes);

相关问题