I need your help. I'm working on the project where necessary to implement a circular slider with draggable button-control by it. I decided to use this jQuery-Knob slider. it's great but I need to add button that could be possible to set styles and be dragged
I made a decision to add div element through javascript and then tie native Jquery Knob params of dragging to it.
Here what I have done
And here is my code
function addBtnControl(self) {
// cache variables
var button = document.getElementById('knob-ctrl'),
cx = 22*self.scale,
cy = 20*self.scale,
a = self.arc(self.cv),
start = xyOnArc(self.xy-cx, self.xy-cy, self.radius/self.scale, a.s);
// check if pointer-events are supported
// if not than use fallback btn ctrl for IE
App.config.Modernizr.addTest('csspointerevents',function(){
return 'pointerEvents' in document.documentElement.style;
});
if (App.config.Modernizr.csspointerevents) {
self.cursorExt = 0;
button.style.left = start.x + "px";
button.style.top = start.y + "px";
}
function xyOnArc(cx, cy, radius, radianAngleX) {
var x = cx + radius * Math.cos(radianAngleX);
var y = cy + radius * Math.sin(radianAngleX);
return ({
x: x,
y: y
});
}
}
// init Button Ctrl
addBtnControl(this);
I dynamically added a button and borrowed params that must be enough to make a well-suited draggable control but I've been doing something wrong because if I scale a browser or just open on another screen size it looks like this
So something wrong with the functions and params that passed to it.
Actually jQuery knob was using Canvas, so adding external layers with it makes more complex.
Alternatively i suggest to use the jQuery roundSlider plugin which is similar to knob, but it constructs based on the div elements only. So you can make any custom appearances as per your wish.
For more details check the demos and documentation page.
Check this demo from jsFiddle which is similar to your requirement.
Screenshot of the Output:
Related
I'm using the Jcrop jQuery library to allow users to choose a round/circle crop area on images they upload. Their demo page is: http://jcrop.org/demos/circle
When the image is too big to fit on screen, Jcrop can be given the JS options:
boxWidth: 500, //Maximum width to display bigger images
boxHeight: 500, //Maximum height to display bigger images
This successfully resizes the image down to fit the screen for the whole image, however the draggable selection zone instead displays the image at its original full size. And therefore the selection zone does not match everything surrounding it.
Please see the problem at: https://jsfiddle.net/LiebeMachen/mjw88acr/15/
Try dragging around the circle over various places in the image, and you'll see that what is in the circle is actually the full size version of the image, when it should fit in with the surrounding area based on how much the image was sized down for display.
As far as I know, this issue doesn't occur when Jcrop using a regular square/rectangle selection. It seems to be specific to doing a circle selection. There are some question similar question on here about this, but those questions were not using circle selection, and their fixes don't seem to help here with a circle.
My actual in-page Javascript just starts from line 2875 in the JavaScript pane on jsfiddle. All the JS above that is just the jcrop.js library itself.
How can I keeping using the boxWidth/boxHeight settings to scale large images down, while getting the selection zone to also do the same?
The problem you experience comes from the fact that the sample on jcrop website (which you probably used for the circular crop) does not do proper computation of the css for the circular selection.
By adjusting the background-size in the CircularSel besides background-position, you will get what you expected. See snippet below, and don't forget to replace "your_image_id_goes_here" with your actual image id.
// Create a new Selection object extended from Selection
var CircleSel = function () { };
// Set the custom selection's prototype object to be an instance
// of the built-in Selection object
CircleSel.prototype = new $.Jcrop.component.Selection();
// Then we can continue extending it
$.extend(CircleSel.prototype, {
zoomscale: 1,
attach: function () {
this.frame.css({
background: 'url(' + scope.imageUrl() + ')'
});
},
positionBg: function (b) {
var midx = (b.x + b.x2) / 2;
var midy = (b.y + b.y2) / 2;
var ox = (-midx * this.zoomscale) + (b.w / 2);
var oy = (-midy * this.zoomscale) + (b.h / 2);
//this.frame.css({ backgroundPosition: ox+'px '+oy+'px' });
this.frame.css({
backgroundPosition: -(b.x + 1) + 'px ' + (-b.y - 1) + 'px',
// ############## BEGIN FIX ##############
//The following line of code will float your boat
backgroundSize: $('#your_image_id_goes_here').width() + 'px ' + $('#your_image_id_goes_here').height() + 'px'
// ############## END FIX ##############
});
},
redraw: function (b) {
// Call original update() method first, with arguments
$.Jcrop.component.Selection.prototype.redraw.call(this, b);
this.positionBg(this.last);
return this;
},
prototype: $.Jcrop.component.Selection.prototype
});
I am using Ariutta's svg-pan-zoom with svg.js. I have disabled the native Arriuta doubleclick functionality and have tried adding my own, which ultimately consists of a pan adjustment and an animation.
Usually this works fine, but sometimes when I load my page the doubleclick function acts strangely. According to my debugging, it looks like sometimes when my app loads, the doubleclick function I wrote is called twice for each doubleclick. This causes the animation to behave strangely, and there seems to be no consistent basis for when this issue arises. Restarting my server sometimes works, and sometimes doesn't. I pretty much just have to continue reloading my page until the issue goes away.
My initial thoughts are that maybe there is something off in the load order of my files, and sometimes things load out of order. Currently investigating this. My other thought was that maybe this has something to do with the svg.js animation library or my trying to replace the native double-click function in arriuta's plugin. Thoughts?
myApp.service('AnimatorService', function(){
this.dblClickBehavior = function(svgCanvas, zoom){
$('.node').dblclick(function(){
// get pan
pan = zoom.getPan();
// get screen width and height
var sizes = zoom.getSizes();
var centerX = (sizes.width)/2;
var centerY = (sizes.height)/2;
// get center position of svg object double clicked
var x0 = this.instance.first().attr('cx');
var y0 = this.instance.first().attr('cy');
//determine the correct pan value necessary to center the svg
panAdjustX = centerX - x0*sizes.realZoom;
panAdjustY = centerY - y0*sizes.realZoom;
//center the svg object by adjust pan
zoom.pan({'x' :centerX - x0*sizes.realZoom, 'y' : centerY - y0*sizes.realZoom});
//simple animation on the object
this.instance.first().animate().radius(centerX);
});
}
});
When it behaves correctly, the svg image centers and then grows. When it behaves incorrectly, it centers and then shrinks into nothingness.
You tagged svg.js so I will give an svg.js answer. There is a plugin svg.panZoom.js now which can be used to easily implement the functionality you want:
var canvas = SVG('container').viewbox(0,0,1000,1000)
canvas.image('https://www.zooroyal.de/magazin/wp-content/uploads/2017/05/cat-2783601_1920.jpg', 1000, 1000)
.attr('preserveAspectRatio', 'none')
canvas.on('dblclick', function(e) {
var p = this.point(e.pageX, e.pageY)
var zoomLvl = 3
// zoom into point p to zoomLvl
canvas.animate().zoom(zoomLvl, p)
})
Here is a fiddle: https://jsfiddle.net/Fuzzy/95t6oL8y/5/
When you want to be able to panZoom your svg, too. Just add a call to canvas.panZoom()
If I create a text element and add a drag handler it does not move on a touch device. I can see that the move event gets triggered, but the element does not drag. If I create a path element and attach the same drag handlers that path element moves just fine on a touch device. All elements move fine on both Chrome and Firefox on my laptop.
Is there anything special that I have to do to get text elements to drag on a touch device?
Here's a snippet of what I'm doing. I did remove some pieces of code that were unrelated, so it may look a little strange.
var word = paper.text(xVal, yVal, "text"]);
word.drag(window.move, window.start, window.up)
window.start = function() {
this.lastDx = 0;
this.lastDy = 0;
};
window.move = function(dx, dy) {
this.transform("...T" + (dx - this.lastDx) + "," + (dy - this.lastDy));
this.lastDx = dx;
this.lastDy = dy;
return this;
};
window.up = function() {
this.lastDx = 0;
this.lastDy = 0;
};
After some trial and error I was able to get around this by creating a rectangle that "wraps" the text. I put a fill on the rectangle but with an opacity of 0 and then grouped the rectangle and the text together and made the set the draggable piece.
There is a fix in Raphael 2.1.1 for this issue. Prior versions reported NaN for dx/dy on touch devices so if you were using those for dragging then it won't work.
See https://github.com/DmitryBaranovskiy/raphael/issues/328
Recently, I have started dabbling with HTML5 and the mighty canvas. However, I am trying to accomplish something and I am not sure what the best way would be to handle it.
I am trying to make a randomly generated set of buildings with windows, as you can see in the following example that uses divs:
Example Using Divs
The issue that I am coming up with is that I want to be able to randomly generate images/content in the windows of these buildings, and be able to easily capture when a window is clicked, but I am not sure how to go about handling it using the canvas.
Example Building:
function Building()
{
this.floors = Math.floor((Math.random()+1)*7); //Number of Floors
this.windows = Math.floor((Math.random()+1)*3); //Windows per Floor
this.height = (this.floors*12); //1px window padding
this.width = (this.windows*12); //1px window padding
//Do I need to build an array with all of my windows and their locations
//to determine if a click occurs?
}
Example Window:
function Window(x,y)
{
this.x = x; //X Coordinate
this.y = y; //Y Coordinate
this.color = //Random color from a range
this.hasPerson //Determines if a person in is the window
this.hasObject //Determines if an object is in the window
}
Summary: I am trying to generate random buildings with windows, however I am unsure how to go about building them, displaying them and tracking window locations using the canvas.
UPDATE:
I was finally able to get the buildings to generate as I was looking for, however now all I need to do is generate the windows within the buildings and keep track of their locations.
Building Generation Demo
I guess if you are drawing the window, you already have the function to create their canvas path. So you can apply the isPointInPath function on all window you have to determine if the user clicked on a window.
canvasContext.beginPath()
{
(functions corresponding to your window path)
}
canvasContext.closePath()
var isInWindow = canvasContext.isInPath(clicPosX,clicPosY);
Actualy you have to check where mouse is clicked, and if it's in window, then call some function. And yes, you will need to have array, of locations.
Take a look here
Draw your squares using fillRect, store their north-western point coordinates into an array. You'll also need these rectangles' dimensions, but since they are all equal squares — no need to store them in the array.
Then add a click listener to the canvas element, in which detect the pointer's position via pageX/pageY minus the position of the canvas element.
Then on each click traverse the array of rectangles and see if they contain the pointer's coordinates:
if (((pageX > rectX && pageX < rectX + rectWidth) || (pageX < rectX && pageX > rectX + rectWidth))) &&
((pageY > rectY && pageY < rectY + rectHeight) || (pageY < rectY && pageY > rectY + rectHeight))) {
/* clicked on a window */
}
Demo.
I am using JQuery-UI draggables and droppables to clone elements onto a div.
What is the best way to draw a line between elements on a page using JQuery.
What is the best way to refresh lines on the page? I will have multiple lines on the page and only want to update a particular line rather than refresh every line.
I now have this working.
In my experience, don't use jquery.svg, it may have been the pressure to solve it without learning my way around another plugin, but I found it more hassle than it was worth and caused compatibilty issues.
It's possible to solve using the HTML5 canvas and excanvas compatibility script, and a great html5 walkthrough, BUT because of how the HTML5 canvas works, it requires that all the linse on the canvas are destroyed and redrawn if a line needs to be removed or its position needs to be updated.
The elements that I draw lines between are inside a parent element that represents a relationship. The child elements represent a start and end, so I can redraw all of these relationships by getting a collection of the parents using e.g. $('.relationshipClass') and interrogating the set's elements' children to get the points of the line.
To use this code you will have to come up with an approach to easily get the line points available to redraw.
Markup:
Nice and simple, a html <div> to hold any elements that are drawn between (most probably JQuery UI draggables), and a <canvas> that will be in the same position
<div id="divCanvasId" class="divCanvasClass"></div>
<canvas id="html5CanvasId"></canvas>
CSS:
Don't control the <canvas> element's width with CSS, see Question on Canvas streching. Position the <canvas> in the same position as the <div> and behind it (with the z-index), this will show the lines up behind the <div> and prevent the <canvas> from blocking any drag and drop interactions with the <div>'s children.
canvas
{
background-color: #FFFFFF;
position: absolute;
z-index: -10;
/* control height and width in code to prevent stretching */
}
Javascript approach:
Create utility methods: the example code is inside a JQuery plugin that contains:
A helper function to reset the canvas (changing the width will delete all of
A helper function to draw lines between two elements
A function that draws lines between all the elements that require one
When you add a new line or adjust the position of a line, you destroy the existing lines and draw all of the lines.
You can put the code below into conventional functions or leave as a plugin.
Javascript code:
N.B. not tested after anonymisation.
$(document).ready(function () {
$.fn.yourExt = {
_readjustHTML5CanvasHeight: function () {
//clear the canvas by readjusting the width/height
var html5Canvas = $('#html5CanvasId');
var canvasDiv = $('#divCanvasId');
if (html5Canvas.length > 0) {
html5Canvas[0].width = canvasDiv.width();
html5Canvas[0].height = canvasDiv.height();
}
}
,
//uses HTML5 <canvas> to draw line representing relationship
//IE support with excanvas.js
_drawLineBetweenElements: function (sourceElement, targetElement) {
//draw from/to the centre, not the top left
//don't use .position()
//that will be relative to the parent div and not the page
var sourceX = sourceElement.offset().left + sourceElement.width() / 2;
var sourceY = sourceElement.offset().top + sourceElement.height() / 2;
var targetX = targetElement.offset().left + sourceElement.width() / 2;
var targetY = targetElement.offset().top + sourceElement.height() / 2;
var canvas = $('#html5CanvasId');
//you need to draw relative to the canvas not the page
var canvasOffsetX = canvas.offset().left;
var canvasOffsetY = canvas.offset().top;
var context = canvas[0].getContext('2d');
//draw line
context.beginPath();
context.moveTo(sourceX - canvasOffsetX, sourceY - canvasOffsetY);
context.lineTo(targetX - canvasOffsetX, targetY - canvasOffsetY);
context.closePath();
//ink line
context.lineWidth = 2;
context.strokeStyle = "#000"; //black
context.stroke();
}
,
drawLines: function () {
//reset the canvas
$().yourExt._readjustHTML5CanvasHeight();
var elementsToDrawLinesBetween;
//you must create an object that holds the start and end of the line
//and populate a collection of them to iterate through
elementsToDrawLinesBetween.each(function (i, startEndPair) {
//dot notation used, you will probably have a different method
//to access these elements
var start = startEndPair.start;
var end = startEndPair.end;
$().yourExt._drawLineBetweenElements(start, end);
});
}
You can now call these functions from event handlers (e.g. JQuery UI's drag event) to draw lines.
Make a hr or div with 1px height set background, and animate its width using jquery when needed.