FabricJS - добавьте линию на холст и контролируйте только ее длину

Я использую FabricJS для разработки простого редактора плана этажа. При добавлении линии (которая должна быть стеной) на холст мне нужна возможность контролировать только длину линии, а не ее ширину-высоту.

Я попытался установить lockScalingY: true, но проблема в том, что при добавлении строки ручки управления расположены так близко друг к другу, что я не могу взаимодействовать только с горизонтальными ручками управления... угловые ручки фактически блокируют горизонтальные ручки...

Как это может быть сделано?


person Light    schedule 16.03.2013    source источник
comment
Даже глядя на демоверсии на fabricjs.com кажется, что там есть ошибки (по крайней мере, в Chrome).   -  person Lee Taylor    schedule 17.03.2013


Ответы (2)


Точный контроль смежных строк FabricJS

Графические программы, такие как Photoshop, справляются с этой распространенной проблемой, позволяя пользователю размещать линии рядом с желаемым пересечением, а затем использовать клавиши со стрелками, чтобы «подтолкнуть» линию на место попиксельно.

Код ниже иллюстрирует грубое решение, которое делает то же самое для строк FabricJS:

  1. Пользователь выбирает линию.
  2. Отключите ручки управления и границы.
  3. Позвольте пользователю "подтолкнуть" линию к идеальному выравниванию (здесь длина линии увеличена).
  4. Включите ручки управления и границы обратно.

Это просто "доказательство концепции" кода. В рабочем приложении:

  • Вы, вероятно, захотите использовать клавиши со стрелками вместо кнопок для «подталкивания».
  • Я сделал подталкивание на 10 пикселей за раз — вы можете делать это на 1 пиксель за раз.
  • А когда пользователь начнет подталкивать, вы автоматически отключите для него маркеры и границы.

Вот код и скрипт: http://jsfiddle.net/m1erickson/dd742/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="fabric.min.js"></script>

<style>
    body{ background-color: ivory; padding:30px; }
    canvas{border: 1px solid red; }
</style>

<script>
    $(function(){

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

        var line1=newLine(50,100,150,100,"red");
        var line2=newLine(160,50,160,150,"green");
        canvas.add(line1,line2);

        function newLine(x1,y1,x2,y2,color){
            var line=new fabric.Line(
                [x1,y1,x2,y2],
                {fill:color,strokeWidth:15,selectable:true}
            );
            return(line);
        };

        $("#hOff").click(function(){
            selectedLine.hasBorders=false;
            selectedLine.hasControls=false;
            canvas.renderAll();
        });

        $("#hOn").click(function(){
            selectedLine.hasBorders=false;
            selectedLine.hasControls=true;
            canvas.renderAll();
        });

        $("#shorter").click(function(){
            changeLineLength(selectedLine,-10);
            canvas.renderAll();
        });

        $("#longer").click(function(){  
            changeLineLength(selectedLine,10);
            canvas.renderAll();
        });

        function changeLineLength(line,adjustment){
            if(!selectedLine){return;}
            if(line.get("y1")==line.get("y2")){   // line is horizontal
                line.set("x2",line.get("x2")+adjustment);
            }else
            if(line.get("x1")==line.get("x2")){   // line is vertical
                line.set("y2",line.get("y2")+adjustment);   
            }else{    // line is diagonal
                line.set("x2",line.get("x2")+adjustment);   
                line.set("y2",line.get("y2")+adjustment);   
            }
        }

        canvas.observe('object:selected', function(eventTarget) {
            var event=eventTarget.e;
            var target=eventTarget.target;
            selectedLine=target;
        });

    }); // end $(function(){});
</script>

</head>

<body>
    <p>Select a line,</p><br/>
    <p>Turn handles Off</p><br/>
    <p>Make lines intersect by pressing longer/shorter</p><br/>
    <canvas id="canvas" width="600" height="200"></canvas> 
    <button id="hOff">Handles Off</button>
    <button id="shorter">Shorter</button>
    <button id="longer">Longer</button><br/>
    <button id="hOn">Handles On</button>
</body>
</html>
person markE    schedule 17.03.2013
comment
Спасибо за усилия с этим ответом. Я не хотел, чтобы интерфейс был таким, потому что я хочу, чтобы пользователь мог изменять длину стены с помощью мыши, но это интересное альтернативное решение. Есть ли способ скрыть только некоторые ручки управления? - person Light; 18.03.2013
comment
Нет, маркеры управления отображаются как группа без детального управления отдельными маркерами. Таким образом, варианты — это усовершенствованная версия этого хака или изменение исходного кода — ваши варианты. Кстати, исходный код доступен и хорошо прокомментирован, если вы хотите пойти туда;) - person markE; 18.03.2013

Может поможет кому.

Добавить обработчик к событию

'object:selected': _objSelected

Затем в обработчике установите для ненужного элемента управления значение false.

function _objSelected(e) 
{
    if(e.target.objectType == 'line')
    {
        var cv = e.target._controlsVisibility;
        // mt - middle top, tl - top left and etc.
        cv.mt = cv.mb = cv.tl = cv.bl = cv.tr = cv.br = false;
    }
}

Также я добавил objectType (настраиваемое свойство) и padding (для красоты) в новый объект Line.

var obj = new fabric.Line([50, 50, 150, 50], { padding: 10, objectType: 'line' });
person 0x000f    schedule 17.02.2016