GithubHelp home page GithubHelp logo

nichollascarter / subjx Goto Github PK

View Code? Open in Web Editor NEW
207.0 8.0 40.0 3.29 MB

Drag/Resize/Rotate Javascript library

License: MIT License

CSS 0.20% JavaScript 95.80% HTML 3.97% Shell 0.03%
drag resize rotate snap svg vanilla-javascript no-dependencies javascript

subjx's Introduction

Subjx(dragging/resizing/rotating)

Draggable, Resizable, Rotatable library for creating drag-n-drop applications.

Demos

Usage

Library provides dragging/resizing/rotating/snapping SVG/HTML Elements.

Installation

Run npm install to install with npm.

npm install subjx

Including via a <script> tag:

<script src="../dist/js/subjx.js"></script>

Get started

Main function subjx returns Subjx instance which based on elements finded by passed parameters:

import subjx from 'subjx';
import 'subjx/dist/style/subjx.css';

// possible parameters
const xElem = subjx( 'selector' ) |
                subjx( element ) |
                subjx( elementArray );

Transformation(drag/resize/rotate)

// enabling tool by `drag` method with the optional parameters
// by default just call `.drag()`
const xDraggable = xElem.drag();

// for disabling use `disable` method for each object
xDraggable.disable();

"Draggable" API

// getter returns root DOM element of 'controls'
xDraggable.controls;

// provides access to useful options
xDraggable.storage;
// for example: to get reference to any handle's DOM
const {
  handles: { tl, tr, ...etc }
} = xDraggable.storage;

// enables dragging
// there is no need to call this method manually
xDraggable.enable(options);

// disables dragging, removes controls and handles
xDraggable.disable();

 // adds event listener for some events
xDraggable.on(eventName, cb);

// removes event listener for some events
xDraggable.off(eventName, cb);

// Event names
const EVENTS = [
    'dragStart',
    'drag',
    'dragEnd',
    'resizeStart',
    'resize',
    'resizeEnd',
    'rotateStart',
    'rotate',
    'rotateEnd'
];

// execute dragging manually
xDraggable.exeDrag({
    dx, // drag along the x axis
    dy // drag along the y axis
});

// execute resizing manually
xDraggable.exeResize({
    dx, // resize along the x axis
    dy, // resize along the y axis
    revX, // reverse resizing along the x axis
    revY, // reverse resizing along the y axis
    doW, // allow width resizing
    doH  // allow height resizing
});

// execute rotating manually
xDraggable.exeRotate({
    delta // radians
});

// Align element inside container: ['t', 'l', 'r', 'b', 'v', 'h']
xDraggable.applyAlignment('tr');

// Call this method when applying scale or viewBox values changing
// useful when element's container was transformed from outside
xDraggable.fitControlsToSize();

// Sets the origin for an element's transformations
xDraggable.setTransformOrigin(
    {
        x, // absolute the origin's position x coordinate
        y, // absolute he origin's position y coordinate
        dx, // offset the origin's position x coordinate
        dy // offset the origin's position y coordinate
    },
    pin // leaves current origin fixed if true or not if false
);

// Sets transform origin to default
xDraggable.resetTransformOrigin();

// Returns element's current dimensions
xDraggable.getDimensions();

Options

Property Description Type Default
container Transformation coordinate system 'selector' | element element.parentNode
controlsContainer Parent element of 'controls' 'selector' | element element.parentNode
axis Constrain movement along an axis string: 'x' | 'y' | 'xy' 'xy'
snap Snapping to grid in pixels/radians object { x: 10, y: 10, angle: 10 }
each Mimic behavior with other '.draggable' elements object { move: false, resize: false, rotate: false }
proportions Keep aspect ratio on resizing / scaling boolean false
draggable Allow or deny an action boolean true
resizable Allow or deny an action boolean true
rotatable Allow or deny an action boolean true
scalable Applies scaling only to root element boolean false
restrict Restricts element dragging/resizing/rotation 'selector' | element -
rotatorAnchor Rotator anchor direction string: 'n' | 's' | 'w' | 'e' 'e'
rotatorOffset Rotator offset number 50
transformOrigin Sets the origin for an element's transformations boolean | Array false

Notice: In most cases, it is recommended to use 'proportions' option

Methods

subjx('.draggable').drag({
    onInit(elements) {
        // fires on tool activation
    },
    onMove({ clientX, clientY, dx, dy, transform }) {
        // fires on moving
    },
    onResize({ clientX, clientY, dx, dy, transform, width, height }) {
        // fires on resizing
    },
    onRotate({ clientX, clientY, delta, transform }) {
        // fires on rotation
    },
    onDrop({ clientX, clientY }) {
        // fires on drop
    },
    onDestroy(el) {
        // fires on tool deactivation
    }
});

Subscribing new draggable element to previously activated(useful with each option)

const options = {};
const observable = subjx.createObservable();
subjx('.draggable').drag(options, observable);

// pass Observable to new element
const createDraggableAndSubscribe = e => {
    subjx(e.target).drag(options, observable);
};

Allowed SVG elements: g, path, rect, ellipse, line, polyline, polygon, circle

Cloning

Options

const xCloneable = xElem.clone({
    // dropping area
    stack: 'selector',
    // set clone parent
    appendTo: 'selector',
    // set clone additional style
    style: {
        border: '1px dashed green',
        background: 'transparent'
    }
});

Methods

subjx('.cloneable').clone({
    onInit(el) {
        // fires on tool activation
    },
    onMove(dx, dy) {
        // fires on moving
    },
    onDrop(e) {
        // fires on drop
    },
    onDestroy() {
        // fires on tool deactivation
    }
});

Disabling

xCloneable.disable();

License

MIT (c) Karen Sarksyan

subjx's People

Contributors

nichollascarter avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

subjx's Issues

Multiple sjx-wrapper's

Chrome 91.0.4650.0 x64
subjx 0.3.9

After init object's transformations and using it a bit, object gets more than one .sjx-wrapper, and it gets messy on the screen. It also becomes difficult to use transformation then.

ezgif-6-fec708b3f7c0

Resize components

Hi everyone.
How to resize all components inside the container when the container resize?

IE11 support?

This library seems to be not working in IE11 and i couldn't see any reference for that. Am i missing something?

`exeDrag` while dragging the shape applies dramatically

When dragging a shape, and in middle of drag, if I call exeDrag to move the shape by a pixel, the result would be HUGE changes. What I "guess" is happening by observing the behavior, looks like each call to exeDrag applies the delta from parameters, plus all the dragging user did by mouse. In the codeSandBox below, If you press "Arrow Down" the shape will be moved down only by one pixel. But if we call the same method to move shape by one pixel while dragging the shape, the shape moves drastically. Just start dragging the shape vertically. (and check the console to make sure how many times we are moving the shape by one pixel. It should not be this much dramatic)

CodeSandBox: https://codesandbox.io/p/sandbox/gallant-sun-tdk5lg?file=%2Fsrc%2Findex.js

Contact

Hello Karen,

I apologize for creating an Issue like this, but I could not find your contact details anywhere.

Im interested in having some features built into the project. I dont have the time to do it myself. Are you interested in contract work to develop this project further? Essentially, I would like to use this library to place objects on a map, and then save it so that it can be edited later. An example would be to place tool images in a fire truck so that new firefighters can find the equipment.

eg: https://thumbs.dreamstime.com/b/inside-fire-engine-fire-truck-side-view-equipment-packed-neatly-58081935.jpg

There would be a tool box with objects and line drawing like you have which would be placed down.

[email protected] SUBJECT: "SUBJX"

Cheers ~ ...Vern

resetCenterPoint(); inside onDrop event does not work on 0.3.9

Hi

I was preparing a new PR for the setCenterPoint(x,y) method of #56 but while basing the code on the resetCenterPoint(); I noticed it acts strangely.

You can see the demo here :
https://codesandbox.io/s/svg-drag-pan-zoom-forked-dfjer

I changed subjx to version 0.3.9 (1.0.0 gives an error) and changed the option :
rotationPoint: true,
and added in the callback :

  onDrop(e, el) {
    console.log("is dropped");
    this.resetCenterPoint();
  },

When the svg is dropped the control center seems to be shifted

I am still discovering the complexity of transformation matrix, but not enough to understand the issue.

Thanks

Constraints - Deleting SVGs - Moving & Selecting in Groups

My team is working on a floor planning application using SVGs. We would like to know if the following features are possible in subjx:

  1. Setting constraints so that SVGs cannot run into one another.

  2. Grouping, moving, and rotating objects together through an event like a mouse drag and removing single items in that group with a shift+click.

  3. Deletion of SVGs or entire group of SVGs at the same time.

  4. Changing the appearance and position of the rotator handle depending on which direction the object or group is facing.

The project is hosted on http://colab.web.csit.jccc.edu/

Github:
https://github.com/Colab-JCCC-Team/colab.git

We appreciate all of your work and hope to hear back from you soon.

drop event and default options

Hi, Karen.

First of all, amazing work with that project. I love it, I'm currently using it (or the most part of it) for a big project of my own. I faced two difficulties so far, which I wanted to discuss with you.

  1. On the drop event, the drop container doesn't exist, as an argument to the drop function, so I cannot actually catch where I'm dropping a certain element to. It would be great, if such an argument exists, so for example you can move an element between two containers.

  2. I cannot seem to find a good solution to removing one of the three options (drag,resize,rotate) as a default behavior when I initialize the library. For example, if I want to use only resize and rotate, it would be great, if in the options I can tell drag:false or something similar, so I do not get the whole functionality. I can simulate on the drag event - return false but still I don't think that is the correct way things should go.

Again I wanted to say, everything is great and I see that you have made wonders with this library! Good luck!

Save/Load state?

Hi there! Awesome project!

I was wondering...how, exactly, would I save and load scale/rotation/position of items once they've been positioned in the browser?

Moving / "Dragging" an element with arrow keys?

Hi there Karen!

Just stumbled upon your awesome project and it looks very useful. I was wondering if there is a way to move / "drag" an element using the arrow keys? Sometimes it comes in handy tu nudge an element a few pixels with the arrows instead of clicking and dragging. :-)

When the container is scaled, it cannot drag properly

When scale=1, then its works fine there are no issues while dragging into the container. But when scale is less than 1 or greater than 1 then dragging the components into container becomes slow, it's like lagging.
Please help me, its urgent

Live elements?

It's possible enable/disable live elements?
Or maybe doubleclick in image to activate/deactivate?

I am creating an image editor, texts, svg ...
The elements are created on demand, hence my question.

Your plugin is fantastic, congratulations and thanks for sharing!

Double click to disable

Hello

I really like the simplicity of the interface.

In the demo https://codesandbox.io/s/svg-drag-pan-zoom-wb95s double click on items works to disable the drag tool until version 0.2.7 included. From 0.3.0-beta.0 it creates an error and nothing in the last version.

Tested on chrome/linux Version 96.0.4664.45 (Official Build) (64-bit)

Thanks you

Can we add new div while first time onMove() method?

subjx('.clone').clone({
    stack: '#container',
    appendTo: '#stack',
    onInit(el) {
    },
    onMove(dx, dy) {
    },
    onDrop(e, el, clone) {
    },
    onDestroy() {
    }
});

when onMove method starts, can we change the style of div or can we change the div on the fly?
suppose below is the HTML initial element which is drags
<div class='clone clonable'>Start Drag</div>

and when onMove() method start, i want to edit the above HTML like this.

<div class='clone clonable'>
    <img id="signature-LDNRHuZkQx" style="background: rgb(255, 214, 91); opacity: 0.8; border: 1px solid rgb(255, 255, 118); border-radius: 5px; width: 400px; height: 100px">
</div>

@nichollascarter @semantic-release-bot @fatihkutuk @sysmaya

When the container is scaled, it cannot rotate properly

eg:

<div class="container"  style="width: 500px; height: 500px; position: relative;transform-origin: center center; transform: scale(0.5); ">
</div>

Will you support this feature in the next release?
Looking forward to your reply .

setTransformOrigin && exeRotate

Hello, Thank you for such an excellent plugin.
Could you post some help, or maybe an example of how to use exeRotate() using an arbitrary center point?
I have tried using setTransformOrigin() before exeRotate()... but no luck.
Thank you.

Only one is required.

I want to make an application to draw and transform basic shapes.
Obviously I must select them to transform them.
The point is that I only need ONE editing transform.
I select one, and deselect the others.
Like in CorelDraw.
There is only one Active Selector.
Question: How do I turn off, hide, ALL selectors??

event handling

Hi,

Great project :-)
It´s not possible to prevent the event on "onDrop" from fire other event.

Please see this exsample where it fires a click event on the container after onDrop.
(see console log)

http://jsfiddle.net/z6skbf7r/1/

Also the "top center" and "bottom center" handles do not work and the "middle right" and "middle left" do the same as "top right" and "top left"
( this is also a problem in your demo, testet in Chrome on windows)

btw.... your demo do not work in microsofe Egde, because it do not support: "...methods" in the json config

Keep up the good work :-)

How can we update the xDraggables once I have applied some offset left and top stylings to the parent element?

So I added some offset left and top stylings to the parent element of the SVG element( this is the element on which I have used the subjx library to apply drag, resize etc operations). But after applying those stylings, the blue border also seems to get shifted by that much amount only. How can I fix this? For ex, if I apply offset left = 10px to the parent element, the subjx border around my SVG element also gets shifted to the right by 10px.

Rotating to 90deg disables rotating and resizing

It is a Basic Example from repo github page. I removed few elements and refectored JS script.
When starting from 0 and rotating to 90, -90, 270 or -270 degrees (releasing mouse button), it becomes impossible to rotate or resize object no more. It happens when angle snap is set positive or default (10). When set to 0, it is tough to set exact 90 angle, so the issue does not happen then.

Chrome 91 x64, Firefox latest, Ubuntu 20.04 x64

http://jsfiddle.net/qr9pc23y/1/

Update

Also if you start with object rotated (translated) by 90deg, resize and rotate is not working.

ForeignObject Support

As the title suggest Foreign object support should be made possible.
I have developed this piece of code to make elements inside foreign object movable By using a rect inside a g and then using the data from rect, apply that data on the foreign object elements. but its like in an ups and down state and buggy.

HTML:

<g x="100" y="100">
  <foreignObject x="100" y="100" width="200" height="200">
    <body xmlns="http://www.w3.org/1999/xhtml">
      <video xmlns="http://www.w3.org/1999/xhtml" src="myvideo.mp4" width="100%" height="100%"></video>
    </body>
  </foreignObject>
  <rect id="id" data-original-id="myid" type="video" class="drag-svg" x="100" y="100" width="200" height="200" fill="red" fill-opacity="0"></rect>
</g>

JS:

// Subjx - additional draggable,resizable and rotatable functionality
function makeDraggableSubjx(element, controls, event, type = false, width = false, height = false) {
    let elm, x, y, rotate, trnf, controls_transform;
    if (type) {
        elm = $(element).prev();
    } else {
        elm = $(element).prev();
    }

    switch (event) {
        case 'init':
            trnf = $(controls).attr('transform');
            x = $(controls).find('rect').attr('x');
            y = $(controls).find('rect').attr('y');

            elm.attr({x: x, y: y, transform: trnf});
            break;
        case 'move':
            trnf = $(controls).attr('transform');
            x = $(controls).find('rect').attr('x');
            y = $(controls).find('rect').attr('y');

            // Set x & y position
            elm.attr({x: x, y: y, transform: trnf});
            break;

        case 'resize':
            trnf = $(controls).attr('transform');
            x = $(controls).find('rect').attr('x');
            y = $(controls).find('rect').attr('y');

            elm.attr({x: x, y: y, transform: trnf, width: width, height: height});
            break;

        case 'rotate':
            trnf = $(controls).attr('transform');
            x = $(controls).find('rect').attr('x');
            y = $(controls).find('rect').attr('y');

            let controls_rotate = SVG(controls).transform('rotate');
            elm.attr({x: x, y: y, transform: trnf, angle: controls_rotate});
            break;

        case 'drop':
            trnf = $(controls).attr('transform');
            x = $(controls).find('rect').attr('x');
            y = $(controls).find('rect').attr('y');

            // Set x & y position
            elm.attr({x: x, y: y, transform: trnf});
            break;
    }

    elm, x, y, rotate, trnf, controls_transform = null;
}

Registering the function inside move,edit,rotate etc.

  onInit(el) {
      switch ($(el).attr("type")) {
          case 'video':
              makeDraggableSubjx(el, this.controls, 'init');
              break;
      }
  },
  onMove({clientX, clientY, dx, dy, transform}) {
      switch ($(this.el).attr("type")) {
          case 'video':
              makeDraggableSubjx(this.el, this.controls, 'move');
              break;
      }
  },
  onResize({clientX, clientY, dx, dy, width, height}) {
      switch ($(this.el).attr("type")) {
          case 'video':
              makeDraggableSubjx(this.el, this.controls, 'resize', false, width, height);
              break;
      }
  },
  onRotate({clientX, clientY, delta, transform}) {
      switch ($(this.el).attr("type")) {
          case 'video':
              makeDraggableSubjx(this.el, this.controls, 'rotate');
              break;
      }
  },
  onDrop({clientX, clientY}) {
      switch ($(this.el).attr("type")) {
          case 'video':
              makeDraggableSubjx(this.el, this.controls, 'drop');
              break;
      }
  },

Looking for better implementation.
Thanks for this beautiful plugin.

PLUS: using SVG.js plugin up there (for an aid to manuplate svg easily)

mimic move for new elements

Hello,

I see that we can mimic move with this option
each: {
move: true,
}

the problem is that it seems to work only with existing elements.
-> When i add a new element on the scene and move it, mimic with others existing elements not working.
We saw it on your example with thoses two yellow rectangle http://jsfiddle.net/nichollascarter/qgwzch0v/

My idea is to create a function like this -> if i move a draggable element (i can know that with your onmove function) then move all elements with class ".draggable" which have also specific class (for example ".mimic").

Add and remove the .mimic class will be easier for me, i can do it.
...But my real problem is how can i use your code in subjx.dev to call a mimic function ??

Thanks in advance !

Final size and rotation

While i rotate or resize the item, the events gives the delta changes but not final values. So when i rotate element it gives, 0 10 20 30 until i release mouse button then starts again 0. 10 20

In this way, there is no way i can track what is the final rotation or sizes of the element.

For size, i'm reading the width/height property of DOM element. This kinda works

For rotation, I had to to very bad things

image

How can i destroy an created instance

iam trying this

  var myInstance= subjx("myselector").drag(svgOptions);

its working like that its okey

img

but when i try

  myInstance.disable()

then it give this error => myInstance.disable is not a function

simple demo

Hi, are you able to provide a simple demo using an image?

Get transform matrix on "resize" event.

Hi Nichollas,

Thanks for your great work. Its nice plugin. Just want to ask, is there any way to pull transform matrix on resize event?
I can get transform matrix via API for drag and rotate event, but unfortunately can't for resize.

Thanks for your advance,
Regards.

Change layering of elements?

Hi, is it possible to change the layering of the elements by clicking on them (or having a menu to select what is in the foreground, what in the background?). Thanks!

Just a suggestion

It would be helpful to be able to restrict the selector movements to a single XY axis.
Example: If I drag the object and hold down the X key, it will only move along that axis. Ignore the movements in Y.

In this way, movements are only allowed in Vertical or Horizontal.

I'll review the plugin code, looking for a way to implement it.
Fantastic and Great Plugin. Thank you !!

TypeError: Argument not an object

I'm new to this library and I'm getting this error: Uncaught TypeError: Window.getComputedStyle: Argument 1 is not an object. I didn't install it through npm though. I just imported it as a CDN by JSDelivr. Could this be the problem?

windows scroll offset problem fixed

replace offset(node) with:

function offset(node) {
    var _offset = node.getBoundingClientRect();
    
    var _scrollLeft = 0;
    if(document.documentElement)
    	_scrollLeft = document.documentElement.scrollLeft;
    else if(document.body.parentNode)
    	_scrollLeft = document.body.parentNode.scrollLeft;
    
    var _scrollTop = 0;
    if(document.documentElement)
    	_scrollTop = document.documentElement.scrollTop;
    else if(document.body.parentNode)
    	_scrollTop = document.body.parentNode.scrollTop;

    return { bottom: _offset.bottom, height: _offset.height, left: _offset.left + _scrollLeft, right: _offset.right, top: _offset.top + _scrollTop, width: _offset.width, x: _offset.x, y: _offset.y };
};

How can I clone with SVG's?

Hello, in your codes there is a clone example, but how can I use this example with SVG's?

Subjx('.clone').clone({
    stack: '#stack',
    style: 'clone',
    drop(e, el, clone) {

        const stack = Subjx('#stack')[0],
            offset = stack.getBoundingClientRect(),
            div = document.createElement('div');

        div.style.top = (e.pageY - offset.top) + 'px';
        div.style.left = (e.pageX - offset.left) + 'px';

        div.classList.add('draggable');

        stack.appendChild(div);

        Draggables.push(...Subjx(div).drag());
    }
});

rotationPoint option

Hi

Sorry to bother you again.

You did not specify on the readme the rotationPoint option.
I tried to put a boolean and it works fine I can drag the rotation center.

I also tried
rotationPoint: [200, 200],
but it does not seem to change the position of this point.

Is there anyway to move this point in the init function ? Maybe by adding parameters to the function resetCenterPoint?

Thanks I am already greatly impressed by the possibilities enabled by subjx.

Straight line problem

Hi, I am using your tool, it is really very good, but I have a problem with straight lines. If the line is not straight, then there is no problem, but if it is straight, then the frame is too small and I cannot move it.
Line:
image
Straight line:
image
image
Straigth line with rotation:
image

Really Great Plugin

I was struggling with the dragging and resizing things, I am using gsap and then i found this plugin, Its a breeze;
Now my only request here is that Please maintain this plugin so that we can all make this better.
I can provide financial managers to you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.