javascript - Draggables و Resizables في SVG



raphael (4)

أرغب في جعل عنصر svg (مسار ، أو مستو ، أو دائرة) قادرًا على أن يكون قابلًا للسحب وأن يعطيه مقابض تغيير الحجم.

ولكن بخلاف HTML DOM ، لا تحتوي جميع العناصر على الزاوية العلوية اليسرى x و y التنسيق والعرض والارتفاع لمربع يحيط بالمحتوى. هذا يجعله غير مريح لإجراء تغيير عام أو إجراء السحب.

هل من المستحسن أن يتم رسم كل مسار أو دائرة داخل كائن svg الخاص به لإعطائي صندوقًا للعب معه؟

كيف يتم تنفيذ السحب / تغيير الحجم عادة في SVG؟


Answers

ملاحظة: لكل من السحب وتغيير الحجم ، سيكون عليك عمل حالات منفصلة لأنواع معينة من العناصر. إلقاء نظرة على المثال الذي أقدمه لاحقًا والذي يعالج سحب الحذف والمستطيلات في نفس مجموعة الوظائف.

لجعل عنصر قابل للسحب تستخدمه:

element.drag(move, start, up);

الوسيطات الثلاثة هي مراجع إلى الوظائف التي تتعامل مع الحركة (السحب) ، بدءاً من (الماوس لأسفل) ، والتوقف (الفأرة).

على سبيل المثال ، لإنشاء دائرة قابلة للسحب (من الوثائق):

window.onload = function() {
var R = Raphael("canvas", 500, 500);    
var c = R.circle(100, 100, 50).attr({
    fill: "hsb(.8, 1, 1)",
    stroke: "none",
    opacity: .5
});
var start = function () {
    // storing original coordinates
    this.ox = this.attr("cx");
    this.oy = this.attr("cy");
    this.attr({opacity: 1});
},
move = function (dx, dy) {
    // move will be called with dx and dy
    this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
    // restoring state
    this.attr({opacity: .5});
};
c.drag(move, start, up);    
};​

مثال jsFiddle


في المثال أعلاه ، يتم ضبط خصائص ox و oy على العنصر لتتبع موقعه ، ويتم استخدام هذه الخصائص بالتزامن مع dx و dy لتغيير موقع العنصر أثناء سحبه.

سحب وإسقاط أكثر تعقيدًا للإجابة على هذا السؤال .

لجعل الكائن قابلًا لتغيير حجمه ، يمكنك ببساطة إنشاء مجموعة ثانية من طرق السحب والإفلات لمعايرة البيانات وضبط عناصر height width المستهدفين استنادًا إلى سحب أداة التبديل.

هنا مليء بسحب وإفلات واحد وصندوق قابل لتغيير الحجم.

jsFiddle مثال على السحب والإسقاط ومربع قابل لتغيير الحجم

window.onload = function() {
var R = Raphael("canvas", 500, 500),
    c = R.rect(100, 100, 100, 100).attr({
            fill: "hsb(.8, 1, 1)",
            stroke: "none",
            opacity: .5,
            cursor: "move"
        }),
    s = R.rect(180, 180, 20, 20).attr({
            fill: "hsb(.8, .5, .5)",
            stroke: "none",
            opacity: .5
        }),
    // start, move, and up are the drag functions
    start = function () {
        // storing original coordinates
        this.ox = this.attr("x");
        this.oy = this.attr("y");
        this.attr({opacity: 1});

        this.sizer.ox = this.sizer.attr("x");
        this.sizer.oy = this.sizer.attr("y");
        this.sizer.attr({opacity: 1});
    },
    move = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({x: this.ox + dx, y: this.oy + dy});
        this.sizer.attr({x: this.sizer.ox + dx, y: this.sizer.oy + dy});        
    },
    up = function () {
        // restoring state
        this.attr({opacity: .5});
        this.sizer.attr({opacity: .5});        
    },
    rstart = function () {
        // storing original coordinates
        this.ox = this.attr("x");
        this.oy = this.attr("y");

        this.box.ow = this.box.attr("width");
        this.box.oh = this.box.attr("height");        
    },
    rmove = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({x: this.ox + dx, y: this.oy + dy});
        this.box.attr({width: this.box.ow + dx, height: this.box.oh + dy});
    };   
    // rstart and rmove are the resize functions;
    c.drag(move, start, up);
    c.sizer = s;
    s.drag(rmove, rstart);
    s.box = c;
};​

تقع معالجات الأحداث المضمّنة (يمكنك استخدام المزيد بالطبع بالتزامن مع .node() ) وصف السحب والإسقاط في أسفل الصفحة في الوثائق .

يمكنك ببساطة إنشاء لوحة قماش رافائيل ، ومن ثم سيكون كل عنصر عنصرًا مختلفًا. ما عليك سوى تعيينها للمتغيرات حتى يمكنك التعامل معها ، كما في المثال أعلاه (استخدم c للإشارة إلى عنصر الدائرة الذي تم إنشاؤه).

ردا على التعليقات هنا هو سحب وإسقاط بسيط + دائرة قادرة على تغيير الحجم. الخدعة هي أن الدوائر تستخدم سمات cx و cy لتحديد المواقع cy r . الميكانيكا هي نفسها إلى حد كبير ... سيكون شكل القطع الناقص أكثر تعقيدًا بعض الشيء ، ولكن مرة أخرى هي مجرد مسألة التعامل مع السمات الصحيحة.

jsFiddle مثال السحب والإسقاط ودائرة resizeable

window.onload = function() {
    var R = Raphael("canvas", 500, 500),
        c = R.circle(100, 100, 50).attr({
            fill: "hsb(.8, 1, 1)",
            stroke: "none",
            opacity: .5
        }),
        s = R.circle(125, 125, 15).attr({
            fill: "hsb(.8, .5, .5)",
            stroke: "none",
            opacity: .5
        });
    var start = function () {
        // storing original coordinates
        this.ox = this.attr("cx");    
        this.oy = this.attr("cy");

        this.sizer.ox = this.sizer.attr("cx");    
        this.sizer.oy = this.sizer.attr("cy")

        this.attr({opacity: 1});
        this.sizer.attr({opacity: 1});
    },
    move = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({cx: this.ox + dx, cy: this.oy + dy});
        this.sizer.attr({cx: this.sizer.ox + dx, cy: this.sizer.oy + dy});
    },
    up = function () {
        // restoring state
        this.attr({opacity: .5});
        this.sizer.attr({opacity: .5});
    },
    rstart = function() {
        // storing original coordinates
        this.ox = this.attr("cx");
        this.oy = this.attr("cy");        

        this.big.or = this.big.attr("r");
    },
    rmove = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({cx: this.ox + dy, cy: this.oy + dy});
        this.big.attr({r: this.big.or + Math.sqrt(2*dy*dy)});
    };
    c.drag(move, start, up);    
    c.sizer = s;
    s.drag(rmove, rstart);
    s.big = c;
};

جرب Graphiti هنا هو الرابط: Draw2d و Graphiti

ويستند على رافائيل وسهلة الاستخدام للغاية.



يعمل jQuery UI draggable السلوك ، لكنك تحتاج إلى تحديث الموضع يدويًا في معالج السحب ، حيث لا يعمل موضع CSS النسبي داخل SVG.

svg.rect(20,10,100,50, 10, 10, {fill:'#666'});
svg.rect(40,20,100,50, 10, 10, {fill:'#999'});
svg.rect(60,30,100,50, 10, 10, {fill:'#ccc'});

$('rect')
  .draggable()
  .bind('mousedown', function(event, ui){
    // bring target to front
    $(event.target.parentElement).append( event.target );
  })
  .bind('drag', function(event, ui){
    // update coordinates manually, since top/left style props don't work on SVG
    event.target.setAttribute('x', ui.position.left);
    event.target.setAttribute('y', ui.position.top);
  });




javascript svg raphael