Snap to polyline in SVG using javascript - javascript

I've been banging my head over this for some time now and I am hoping someone can help me out here.
I'm building a web application where you can draw Lines ("polylines") and symbols ("circle") in an SVG. What I would like to do is place a symbol on a line. Making it snap to the line. I also want it to be usable when using a tablet so I created a custom cursor that has an offset. This way you can position the cursor accurately when working on a tablet pc.
There are two options I thought of. Each has an issue I do not know how to solve.
Option 1: Using hover / touch event when placing a symbol on a line. Unfortanatly since I use a custom cursor with an offset this causes a problem. Is there any way to manipulate the DOM making it think the hover event takes place elsewhere on the screen (in a specific div)?
Option 2: Calculating the correct position. I figured out how to calculate the height of the 'imaginary' triangle (line to cursor). So I'm able to select the line the symbol should be placed on. Unfortunately to calculate the position on the selected line is a lot more code. Since that code will be run onmousemove / touchmove I fear this code will make the UI unstable.
Thanks in advance for any advice that will help me on my way.

Related

several questions regarding cytoscape.js

I've just started using cytoscape (with cytoscape-klay layout) to render some graphs and I'm unable to find answers to some of the questions I have:
Is there a way to left-align the graph? (graph seems to be centered horizontally, but in my use case, I need it to start from the left)
Edit: my graph is not pannable nor zoomable and panBy and shift doesn't seem to work
Is there a way to get the graph rendered without specifying the container dimensions? (right now, if I don't specify the dimensions, the canvas itself has a dimension of 0x0 and since I specify a width/height for every node, I think it should be possible)
Edit: I can't use an absolute positioned container since my view has some sticky parts. Also, I want the container dimension to be exactly what the graph needs as it is not pannable. I'm currently doing the following to accommodate both 1 and 2:
const dim = cy.$('*').boundingBox(); // get real size of graph
const container = document.getElementById('#cy');
container.setAttribute('style', `width: ${dim.w - 120}px; height: ${dim.h}px; transform: translateX(-175px)`);
Is there a way to define css in a css file or does it have to be in js?
Edit: I'm aware that I can use a js/json file - I'm wondering if I can also use a css file (I assume not, but I just want to make sure)
my nodes should be interactive (open / close) and since I work with Vue.js I prefer having my nodes as Vue components. while this seems impossible with cytoscape itself as it supports only a label for a node, I found nodeHtmlLabel package that gets me really close, it doesn't adhere to the styles that were set in js and reactivity seems to be a problem. Is there a better alternative?
Edit: I'm not asking about compound nodes. For a simple example of what I need, you can think of each node having a title and a description but only the title is visible and if you click on the node, it will open to show the description (node height would change)
can I customize the edges? (have an edge consist of a straight line connected to a bezier curved line, use my own control points, etc.) If not, how does these weights / distances work? do they work equally well for Top-Down and Left-Right graphs? (I'm trying to have something like this)
Edit: I'm aware of the current edge types, but I'm looking for something that is a merge between taxi and bezier. Since this is not currently supported, I wanted to know if there is any way to define a custom line myself
Background - I managed to get really close to the desired design with dagre-d3 but I have a problem with ranks and it seems that this package is unmaintained :(, hence I decided to look for an alternative

Best/easiest way to make a 2D Chess board using Javascript/HTML5?

I am building a web based chess game in Javascript. I'm using the HTML5 canvas to display the board by drawing rectangles.
I am trying to implement the move logic. So when a chess piece is clicked, and then they click on an empty block, I want to move it. However, it is quite tedious using the canvas. I need to do the following:
Update my 2D grid of objects to reflect the change, I set the current
square to undefined and set the new square to the object being moved
clearRect(..) which I still haven't got to work
Redraw the image at the new position
Is there a better way?
Also, how do I deal with the 'double click'. I currently using a boolean that holds if the piece was pressed, and if it was and they click on an empty square I call the move function. Are there any other ways of doing this? Additionally, are there any tools for making it seem like the chess piece is being dragged?
I appreciate any help. Thanks guys.
Over the years I've written a lot of chessboards for HTML. In the end the simplest approach I think is:
Keep an array (either 1d or 2d, both have pros and cons) with just piece names (e.g. "wp"=white pawn, "bn"=black night, "--" empty). Nothing to be gained with an OO-approach or even a generic piece object.
Use one single canvas for the board, drawing the pieces on them with drawImage.
Write a function that just draws everything and call it when needed (don't bother erasing/drawing single pieces).
For piece dragging empty the square and create a separate dragged div containing just the dragged piece (redrawing the full board during drag can be slow for low-end mobile devices).
For dragging attach move and up handlers to the document and not to the canvas, so that you won't miss up events when the mouse is outside of the browser window.
Start dragging on mousedown and attach events for mousemove and mouseup. This will work both on computers and on mobile phones without having to handle specific cases. Always call preventDefault and stopPropagation.
Make full-page view with no overflow and handle resize yourself (you'll need to add some mobile-specific metas to stop phones messing up with the page).
HTML can really do impressive things with just 2d canvas, as an example see this 2d/3d chessboard. One single file less than 300k (200k zipped).
Easiest you say?
Using chessboard.js has to be the easiest way and it is 2D.
HTML
<div id="board1" style="width: 400px"></div>
JavaScript
var board1 = ChessBoard('board1', 'start');
It has very good documentation and tons of different examples (customization) and can be downloaded here.
Learning by coding -- Good for you!
Here are a few tips to get you started:
A reusable structure for your game:
Create a JS object for each of your chess pieces and save those piece-objects in an array.
// an example piece object
var blackKing={
player:'black',
pieceType:'king',
image:blackKingImageObject,
currentSquare:['E','1'],
isCaptured: false,
// etc...
}
// a pieces-array
var pieces=[];
pieces.push(blackKing);
Create a function that does all of these things:
clearRect the entire canvas,
redraw the chess board,
use the piece-array to redraw all the pieces onto the chessboard.
About click vs double-click vs dragging:
Yes, that's troublesome and requires special handling.
Many coders handle it this way:
Listen for mousedown and save that timestamp and initial mouse position.
If a mouseup plus another mousedown occurs quickly it's a double-click.
If a mousemove of more than a few pixels occurs then it's the start of a drag.
Otherwise, it's a single-click.

Drag and drop elements into an iframe. Droppable area has wrong coordinates and collisions are wrong

I need to implement drag and drop functionalities in a web application between elements present in a web page, and elements inside an iframe (before you start complaining about iframes, I NEED it for technical reasons, it's not an option).
I have elements in the page that can be dragged into target droppable elements inside an iframe.
I've managed to do it with both jQuery UI and YUI, though both libraries present the same problem: the target element (droppable target) coordinates are misinterpreted, the drop area considered by both libraries is wrong and does not represent the actual droppable object, hence the collisions between the dragged object and the dropped element are messed up entirely. It's like the library sees the droppable element positioned in another place from where it effectively is.
I think this is due to the iframe not being positioned on top-left of page, but in the middle. I think this because I've read many people complaining about this issue and the problem went off if the iframe was top-left positioned. Someone suggest that the coordinates of the droppable element may be calculated based on screenX and screenY, instead of clientX and clientY, and this may be the cause of the issue, not taking into consideration the elements are inside an iframe, and so the coordinates differ between other elements outside the iframe.
So, since it seems there's no way to fix this directly using the library functionalities, and I really don't have time to try every library avaiable out there, I'm thinking about fixing the issue by modifying (patching) the internal functions of the library in question.
The questions are:
1) Did someone experience this behavior before, and managed to fix the issue? Or, is there a library which is able to do this flawlessly?
2) Is there some way to fix this issue using the methods and functionalities of the library itself? And if not,
3) Does somebody know which part of the library calculates the droppable area coordinates, so that I can fix it as a last extreme option?
Thanks in advance, even the smallest help will be appreciated!
EDIT
This fiddle demonstrate the problem. Try to move the green square inside the red square (which is inside an iframe). You will notice the collision between the two squares is wrong.
http://jsfiddle.net/DQdZ9/23/
This is not a "silver bullet" , but I'll go ahead and post this as an answer, but I'm not sure how much value it will have for you. I tracked down a key function in jQuery UI that might be what you're looking for. It's in $.ui.ddmanager (the drag and drop manager), and the function is prepareOffsets. This line:
m[i].offset = m[i].element.offset();
seems to be the one that is setting up the offset for use when the element is actually dropped. This might be a place to fiddle with to adjust the resulting offset based on whether the droppable element is a child of the iframe.
There is another function above it $.ui.intersect that performs the logic to see if the draggable and droppable are intersecting each other.
I'm in the latest release of jQuery UI, and the file is jquery-ui-1.8.14.custom.js on line 2012-2029. If you get the single droppable file itself, jquery.ui.droppable.js, it's on lines 203-220. And these are the dev files, not the min files.

trouble accessing objects inside of 3d cube

my link: http://dl.dropbox.com/u/7727742/playlistsite6/index5.html
I have a 3d cube using a variation of zachstronaut's demo
(link: http://www.zachstronaut.com/lab/galaxy-box/ ). It uses javascript, translate3d, scale3d, etc...
I've tried assigning different z-index values in the css file, but with no luck. I can access the objects outside the cube(you can see this with the hover effect), but not the objects inside the cube. I have a hunch it is because it's not doing a z-sort type of function like pre3d.js. I was wondering if anyone could offer some insight into where I should look for a solution.
Object coordinates are generated randomly, so you may have to refresh once or twice to get some objects that are inside the cube.
Thanks!
EDIT:
Only tested in safari and chrome dev
Webkit ignores z-indexes on anything that has translate3d defined, as it logically should. z-index is meant for a 2D world, it's like taking a bunch of paper and saying "this one is on top" -- you still have a flat surface. Unfortunately, if you want to be able to select one of the "stars" inside of your box, you're all but out of luck since you're using HTML nodes.
The normal way of doing this is using a click-map -- basically every object gets rendered twice. Once normally and once in a single color with no shading, etc. The 2nd rendering is never shown and is simply used to tell what the user clicked on. You get the color where they clicked and that color maps to a specific object. If you were using canvas, you would do it that way and just change the rendering order on the 2nd render.
Since you're using HTML nodes, you can't do that. You have a couple of options:
You can calculate which star is under the mouse on mouse-move based on viewport rotation and x/y/z position of the star
you can attempt the above method by overlaying an identical rendering without the cube and where the stars have a 0% opacity. Each star in your new rendering would map to a star in your existing one, and you'd have easy mouse-over detection.
Post the results! :)
First of all, I'm glad you found my demo interesting!
You're not going to have much luck trying to do a hover or capture a click event on objects inside of a 3D CSS3 cube for the exact same reason you wouldn't have much luck capturing a hover or click events on a div underneath another div... in HTML all the DOM events go to the top most DOM node. If one div overlaps another div, you can't click the one that is underneath. Everything inside the 3D cube is "underneath" another DOM node.
Things are further complicated because you're taking objects in 3D space and asking a user to interact with them on a 2D plane (the browser window) using a 2D input device (the mouse).
You could hide the faces of the cube so that they wouldn't block the user's clicks. You could do something like cwolves suggested.
Sorry I couldn't be more help... HTML kind of fails us a bit here. Welcome to the bleeding edge!

HTML/Javascript inking or drawing control suggestions?

I am looking for something that will allow users to write out a signature in an HTML form. I am looking for something that will run locally on the machine so if it can be done through a javascript function or something else that would be great.
I have seen the canvas HTML5 object, but I haven't found any examples that work well with IE. I am continuing to look, but was just wondering if anyone knows of anythign else out there that will allow a user to write out a signature?
You could do that with Flex or Silverlight, if you're not averse to plugins.
Otherwise, the only way I can think of to do this would be to create a function that places a very small graphic of a 1 pixel dot over and over again at the point of the cursor when it is dragged with the mouse button depressed. (Depressing, eh?) The dots would replicate more profusely and create a thicker line where the cursor pauses, and make a thinner line as it moves faster. The dots would in any case be close enough together to appear as a line, the way halftone printing uses dots to make photographs appear in newspapers.
I could write this for you but you'd have to pay me. :)
not really 'anything else', but canvas can be made to work even in msie6 with google's excanvas (which maps canvas to vml iirc).
canvas painter does this, just successfully drew my signature in both ff3.6 and msie6, so that might make for a good starting point?

Categories