Страницы

Поиск по вопросам

Показаны сообщения с ярлыком dragndrop. Показать все сообщения
Показаны сообщения с ярлыком dragndrop. Показать все сообщения

вторник, 23 апреля 2019 г.

jquery drag and drop связи

Что хочу получить:
Картинка для визуализации. Задача состоит в том что бы связывать блоки (динамически протянуть стрелку от одного блок к другому) и в конце получить структуру для дальнейшей работы. Например:
a link to b
b link to c
Так же у одного блок может быть несколько связей. Прошу подсказать направление, как сделать связи.
перетаскивания сделал так:
jQuery UI Draggable - Default functionality

Drag me


Drag me



Ответ

Рабочий вариант, но код не в лучшем виде. Ссылка на plunker.
"use strict"; var can = $("#can").get(0), ctx = can.getContext('2d'); var boxes = []; function get_box(x, y) { for (var box of boxes) { if (x >= box.x && x < box.x + box.w && y >= box.y && y < box.y + box.h) { return box; } } return null; } function getxy(e) { return {x:e.clientX, y:e.clientY}; } class Box { constructor(x, y, w, h) { this.x = x; this.y = y; this.w = w; this.h = h; this.drag = null; this.name = String.fromCharCode("A".charCodeAt() + boxes.length); boxes.push(this); } on_mouse_down(e) { this.drag = { oldx: this.x, oldy: this.y, // old position of box msx: e.clientX, msy: e.clientY // mouse start x, y }; } on_mouse_move(e) { if (!this.drag) return; var dx = e.clientX - this.drag.msx, dy = e.clientY - this.drag.msy; this.x = this.drag.oldx + dx; this.y = this.drag.oldy + dy; draw_boxes(); } on_mouse_up(e) { this.drag = null; } draw() { ctx.save(); ctx.fillRect(this.x, this.y, this.w, this.h); ctx.font = "30px Georgia"; ctx.fillStyle = "white"; ctx.fillText(this.name, this.x + 10, this.y + 30); ctx.restore(); } center() { return {x: this.x + Math.floor(this.w/2), y: this.y + Math.floor(this.h/2) }; } } var link = null, links = []; function on_mouse_event(method_name) { return function (e) { for (var box of boxes) box[method_name](e); } } $("#can").mousedown(function (e) { var p = getxy(e), b = get_box(p.x, p.y); if (e.shiftKey) { new Box(p.x, p.y, 50, 50); draw_all(); return; } if (!b) return; if (e.ctrlKey) { link = {b}; return; } get_box(p.x, p.y).on_mouse_down(e); }); $("#can").mousemove((e) => { if (link) { link.t = getxy(e); } else { for (var box of boxes) box.on_mouse_move(e); } draw_all(); }); $("#can").mouseup((e) => { var x = e.clientX, y = e.clientY, b = get_box(x, y); if (link) { if (link.b == b || !b) { link = null; return; } links.push({from:link.b, to:b}); } else { for (var box of boxes) box.on_mouse_up(e); } link = null; }); $("#getlinks").click((e) => { var msg = ""; for (var l of links) { msg += `Box "${l.from.name}" свзяан с Box "${l.to.name}"
`; } $("#res").html(msg); }); new Box(10, 10, 50, 50); new Box(150, 150, 50, 50); function draw_boxes() { for (var box of boxes) { box.draw(); } } function draw_links() { for (var l of links) { var bc1 = l.from.center(), bc2 = l.to.center(); ctx.beginPath(); ctx.moveTo(bc1.x, bc1.y); ctx.lineTo(bc2.x, bc2.y); ctx.stroke(); } } function draw_link() { var bc = link.b.center(); ctx.beginPath(); ctx.moveTo(bc.x, bc.y); ctx.lineTo(link.t.x, link.t.y); ctx.stroke(); } function draw_all() { ctx.clearRect(0, 0, can.width, can.height); draw_links(); draw_boxes(); if (link) draw_link(); } draw_all(); html, body { margin: 0; padding: 0; }

This text is displayed if your browser does not support HTML5 Canvas.

MouseMove -- перемещение коробок.
Shift + Click -- добавить коробку.
Ctrl (на коробке) + MouseMove -- провести линию.


пятница, 26 октября 2018 г.

Как сделать перемещение нод TreeView?

Ветки нужно перемещать ноды на уровень выше в материнские и ниже в дочерние.
Моё дерево:
>

На другом примере работает нормально но в моём нет.
1 -2 --3 4 -5 --6
У меня любую ноду можно переместить в корень или в ту же ноду, в которой и находится. Например 3 можно переместить в корень либо в 2, где он уже есть.
В другие почему-то не перемещается.
public class Node { public string name_ { get; set; }
public ObservableCollection collection_node { get; set; }
public Node() {
collection_node = new ObservableCollection(); } }


Ответ

Рекомендую использовать GongSolutions.WPF.DragDrop, которую можно легко установить добавив соответствующий NuGet-пакет.
Дальше к своему TreeViewпросто добавляете два свойства:

где dd
xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
Теперь вы можете легко перетаскивать элементы:

понедельник, 15 октября 2018 г.

Как корректно ограничить область Drag'n'Drop?

Есть маленький div внутри большого div. Через JS применен Drag'n'Drop к малому div. Необходимо ограничить область перемещения меньшего блока.
Попытка реализации
Но если попробовать резко переместить белый блок влево или вверх, то он "залипнет" недалеко от границы. Как это исправить?
var small = document.getElementById('small'); small.onmousedown = function(e) { move(e); function move(e) { if (e.pageX > 0) { small.style.left = e.pageX + 'px'; } if (e.pageY > 0) { small.style.top = e.pageY + 'px'; } } document.onmousemove = function(e) { move(e); } small.onmouseup = function() { document.onmousemove = null; small.onmouseup = null } } #big { width: 12cm; height: 12cm; background-color: #DDDDDD; } #small { position: absolute; left: 0.75cm; top: 0.75cm; width: 4cm; height: 4cm; background-color: #FFFFFF; }



Ответ

Для правильного позиционирования small необходимо рассчитать координаты, за которые нельзя этот small выпускать. Т.е. мы имеем четыре границы: верхнюю, нижнюю, левую, правую.
Для наглядности в примере добавлены отступы у big и фон у body
var small = document.getElementById('small'); var big = document.getElementById('big'); //* флаг перетаскивания var isDrag = false; //* ограничения, за которые нельзя вытащить small var limits = { top: big.offsetTop, right: big.offsetWidth + big.offsetLeft - small.offsetWidth, bottom: big.offsetHeight + big.offsetTop - small.offsetHeight, left: big.offsetLeft }; //* вкл/выкл режим перетаскивания small.onmousedown = function(e) { isDrag = true; } document.onmouseup = function() { isDrag = false; } document.onmousemove = function(e) { if (isDrag) { move(e); } } //* вычисление координат function move(e) { var newLocation = { x: limits.left, y: limits.top }; if (e.pageX > limits.right) { newLocation.x = limits.right; } else if (e.pageX > limits.left) { newLocation.x = e.pageX; } if (e.pageY > limits.bottom) { newLocation.y = limits.bottom; } else if (e.pageY > limits.top) { newLocation.y = e.pageY; } relocate(newLocation); } //* размещение small function relocate(newLocation) { small.style.left = newLocation.x + 'px'; small.style.top = newLocation.y + 'px'; } body { background: #EEF; } #big { width: 12cm; height: 12cm; background-color: #DDDDDD; margin: 2cm; } #small { position: absolute; left: 2.75cm; top: 2.75cm; width: 4cm; height: 4cm; background-color: #FFFFFF; }


четверг, 11 октября 2018 г.

Drag&Drop по правилам WPF

Подскажите пожалуйста как сделать правильно drag&drop прибиндив его положение к MVVM, чтоб можно было бы его сохранить в файл просеарилизировав в JSON? Я знаю как это всё делается по "старинке", поставить событие на Mouse_Down, Mouse_Move и Mouse_Up, а когда происходит перетаскивание в Mouse_Move делать на подобии "canvas.setleft(uiobj, canvas.getleft(uiobj)+mouse.x)" (этот пример не будет работать я знаю), а вот как в mvvm всё это переделать я не знаю :-(


Ответ

Смотрите. Давайте поделим всё на визуальную и модельную части.
Визуальная часть занимается перетаскиванием. При определении факта начала перетаскивания нужно отвязаться от VM (проще всего, наверное, скрыть элемент и показать на его месте другой, заодно можно немного поменять его вид, например, на полупрозрачный), обработать перетаскивание через MouseMove/MouseUp, определить, куда был дропнут элемент, отослать новые координаты в VM, и снова включить отображение элемента.
VM обновит данные, новые координаты вступят в силу через привязку.
Всё.

Написал простой пример MVVM-приложения с перетаскиванием. Приложение рисует набор из перетаскиваемых квадратов. Программа простая, поэтому я обхожусь без модели. Будет выглядеть так:

Начинаем с VM. Общий суперкласс, чтобы не имплементировать INPC каждый раз (если вы пользуетесь MVVM-фреймворком, у вас наверняка такой уже определён):
class VM : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
Теперь класс, представляющий собой фигуру. Мы выкладываем публичные свойства с текущим значением позиции, и командой для смены позиции. Если вы будете сериализировать этот объект, не забудьте отметить команду несериализируемой.
class SquareVM : VM { public SquareVM() { RequestMove = new SimpleCommand(MoveTo); }
// стандартное свойство Point position; public Point Position { get { return position; } set { if (position != value) { position = value; NotifyPropertyChanged(); } } }
// выставляем команду, которая занимается перемещением public ICommand RequestMove { get; }
void MoveTo(Point newPosition) { // в реальности тут могут быть всякие проверки, конечно Position = newPosition; } }
Я использую примитивнейший вариант команды:
class SimpleCommand : ICommand { readonly Action onExecute; public SimpleCommand(Action onExecute) { this.onExecute = onExecute; }
public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) => true; public void Execute(object parameter) => onExecute((T)parameter); }
Теперь, главная VM, ничего особенного:
class MainVM : VM { public ObservableCollection Squares { get; } = new ObservableCollection() { new SquareVM() { Position = new Point( 30, 30) }, new SquareVM() { Position = new Point(100, 70) }, new SquareVM() { Position = new Point( 80, 0) }, new SquareVM() { Position = new Point( 90, 180) }, new SquareVM() { Position = new Point(200, 200) } }; }
На этом с VM-частью покончено.
Теперь, приложение. Стандартная заготовка для MVVM: App.xaml без StartupUri и переопределение OnStartup


public partial class App : Application { MainVM mainVM = new MainVM();
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); new MainWindow() { DataContext = mainVM }.Show(); } }
Переходим к интересной части: представление.
Окно отображает список элементов в Canvas'е. Для привязки списка элементов использован, как обычно, ItemsControl

Сам контрол тоже несложен, код для обработки мышиных сообщений я честно стащил из ответа на вопрос «Как отследить перемещение одного окна над другим?» и выкинул всё ненужное.

Маленькая тонкость: чтобы не следить за командой в DataContext'е, я объявил DependencyProperty RequestMoveCommand, и установил Binding на него. Также мы подписались в XAML'е на MouseDown и MouseUp
public partial class DraggableSquare : UserControl { public DraggableSquare() { InitializeComponent(); // устанавливаем Binding RequestMove из VM на свойство RequestMoveCommand: SetBinding(RequestMoveCommandProperty, new Binding("RequestMove")); }
// стандартное DependencyProperty #region dp ICommand RequestMoveCommand public ICommand RequestMoveCommand { get { return (ICommand)GetValue(RequestMoveCommandProperty); } set { SetValue(RequestMoveCommandProperty, value); } }
public static readonly DependencyProperty RequestMoveCommandProperty = DependencyProperty.Register("RequestMoveCommand", typeof(ICommand), typeof(DraggableSquare)); #endregion
Vector relativeMousePos; // смещение мыши от левого верхнего угла квадрата Canvas container; // канвас-контейнер
// по нажатию на левую клавишу начинаем следить за мышью void OnMouseDown(object sender, MouseButtonEventArgs e) { container = FindParent(); relativeMousePos = e.GetPosition(this) - new Point(); MouseMove += OnDragMove; LostMouseCapture += OnLostCapture; Mouse.Capture(this); }
// клавиша отпущена - завершаем процесс void OnMouseUp(object sender, MouseButtonEventArgs e) { FinishDrag(sender, e); Mouse.Capture(null); }
// потеряли фокус (например, юзер переключился в другое окно) - завершаем тоже void OnLostCapture(object sender, MouseEventArgs e) { FinishDrag(sender, e); }
void OnDragMove(object sender, MouseEventArgs e) { UpdatePosition(e); }
void FinishDrag(object sender, MouseEventArgs e) { MouseMove -= OnDragMove; LostMouseCapture -= OnLostCapture; UpdatePosition(e); }
// требуем у VM обновить позицию через команду void UpdatePosition(MouseEventArgs e) { var point = e.GetPosition(container); // не забываем проверку на null RequestMoveCommand?.Execute(point - relativeMousePos); }
// это вспомогательная функция, ей место в общей библиотеке private T FindParent() where T : FrameworkElement { FrameworkElement current = this; T t; do { t = current as T; current = (FrameworkElement)VisualTreeHelper.GetParent(current); } while (t == null && current != null); return t; } }
Теперь совсем всё!

Вот тут модификация этого кода, чтобы вместо квадратов таскался их уменьшенный и полупрозрачный предпросмотр.