JS charting API with user interaction - javascript

I'm looking for a javascript charting API that would allow user to dynamically modify value points (through drag'n drop) and then provide some callbacks to get those new values.
Do you have any suggestions?

Look at Awesome Free JavaScript Charts review and another one

There is a custom plugin for highcharts that provides dragging of chart points: http://jsfiddle.net/highcharts/AyUbx/:
(function (Highcharts) {
var addEvent = Highcharts.addEvent, each = Highcharts.each;
/**
* Filter by dragMin and dragMax
*/
function filterRange(newY, series, XOrY) {
var options = series.options,
dragMin = options['dragMin' + XOrY],
dragMax = options['dragMax' + XOrY];
if (newY < dragMin) {
newY = dragMin;
} else if (newY > dragMax) {
newY = dragMax;
}
return newY;
}
Highcharts.Chart.prototype.callbacks.push(function (chart) {
var container = chart.container,
dragPoint,
dragX,
dragY,
dragPlotX,
dragPlotY;
chart.redraw(); // kill animation (why was this again?)
addEvent(container, 'mousedown', function (e) {
var hoverPoint = chart.hoverPoint,
options;
if (hoverPoint) {
options = hoverPoint.series.options;
if (options.draggableX) {
dragPoint = hoverPoint;
dragX = e.pageX;
dragPlotX = dragPoint.plotX;
}
if (options.draggableY) {
dragPoint = hoverPoint;
dragY = e.pageY;
dragPlotY = dragPoint.plotY + (chart.plotHeight - (dragPoint.yBottom || chart.plotHeight));
}
// Disable zooming when dragging
if (dragPoint) {
chart.mouseIsDown = false;
}
}
});
addEvent(container, 'mousemove', function (e) {
if (dragPoint) {
var deltaY = dragY - e.pageY,
deltaX = dragX - e.pageX,
newPlotX = dragPlotX - deltaX - dragPoint.series.xAxis.minPixelPadding,
newPlotY = chart.plotHeight - dragPlotY + deltaY,
newX = dragX === undefined ? dragPoint.x : dragPoint.series.xAxis.translate(newPlotX, true),
newY = dragY === undefined ? dragPoint.y : dragPoint.series.yAxis.translate(newPlotY, true),
series = dragPoint.series,
proceed;
newX = filterRange(newX, series, 'X');
newY = filterRange(newY, series, 'Y');
// Fire the 'drag' event with a default action to move the point.
dragPoint.firePointEvent(
'drag', {
newX: newX,
newY: newY
},
function () {
proceed = true;
dragPoint.update([newX, newY], false);
chart.tooltip.refresh(chart.tooltip.shared ? [dragPoint] : dragPoint);
if (series.stackKey) {
chart.redraw();
} else {
series.redraw();
}
});
// The default handler has not run because of prevented default
if (!proceed) {
drop();
}
}
});
function drop(e) {
if (dragPoint) {
if (e) {
var deltaX = dragX - e.pageX,
deltaY = dragY - e.pageY,
newPlotX = dragPlotX - deltaX - dragPoint.series.xAxis.minPixelPadding,
newPlotY = chart.plotHeight - dragPlotY + deltaY,
series = dragPoint.series,
newX = dragX === undefined ? dragPoint.x : dragPoint.series.xAxis.translate(newPlotX, true),
newY = dragY === undefined ? dragPoint.y : dragPoint.series.yAxis.translate(newPlotY, true);
newX = filterRange(newX, series, 'X');
newY = filterRange(newY, series, 'Y');
dragPoint.update([newX, newY]);
}
dragPoint.firePointEvent('drop');
}
dragPoint = dragX = dragY = undefined;
}
addEvent(document, 'mouseup', drop);
addEvent(container, 'mouseleave', drop);
});
/**
* Extend the column chart tracker by visualizing the tracker object for small points
*/
var colProto = Highcharts.seriesTypes.column.prototype,
baseDrawTracker = colProto.drawTracker;
colProto.drawTracker = function () {
var series = this;
baseDrawTracker.apply(series);
each(series.points, function (point) {
point.graphic.attr(point.shapeArgs.height < 3 ? {
'stroke': 'black',
'stroke-width': 2,
'dashstyle': 'shortdot'
} : {
'stroke-width': series.options.borderWidth,
'dashstyle': series.options.dashStyle || 'solid'
});
});
};
})(Highcharts);

Related

Fabric JS : I need to delete an quadratic curved arrow tool after once created on canvas

I am trying to make a quadratic curved arrow tool.
I was used demo in the following link for creating the tool.
http://kpomservices.com/oldweb/HTML5_Canvas_Curved_Lines.php
i was success to create an tool as I needs.
but I am getting some issues with that.
Hope someone here can help me on that issues...
here is the code I am using for creating the tool ..
line_number++;
var line;
var reinit_stroke = "";
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
function _getQBezierValue(t, p1, p2, p3) {
var iT = 1 - t;
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
return {
x: _getQBezierValue(position, startX, cpX, endX),
y: _getQBezierValue(position, startY, cpY, endY)
};
}
canvas.on({
'object:selected': onObjectSelected,
'object:moving': onObjectMoving,
'before:selection:cleared': onBeforeSelectionCleared
});
(function drawQuadratic() {
line = new fabric.Path('M 65 0 Q 100, 100, 200, 0', { fill: '', selectable: false,hasBorders: false,hasControls: false,stroke: #000});
line.path[0][1] = posx;
line.path[0][2] = posy;
line.path[1][1] = posx+50;
line.path[1][2] = posy+50;
line.path[1][3] = posx+100;
line.path[1][4] = posy+100;
line.id = line_number;
//line.selectable = false;
canvas.add(line);
canvas.sendBackwards(line);
var pt = getQuadraticCurvePoint(line.path[0][1], line.path[0][2], line.path[1][1], line.path[1][2], line.path[1][3], line.path[1][4], 0.5);
var p1 = makeCurvePoint(pt.x, pt.y, null, line, null)
p1.name = "p1";
p1.id = line_number;
canvas.add(p1);
var p0 = makeCurveCircle(posx, posy, line, p1, null);
p0.name = "p0";
p0.id = line_number;
canvas.add(p0);
var p2 = makeArrow(posx+100, posy+100, null, p1, line);
p2.name = "p2";
p2.id = line_number;
canvas.add(p2);
var dx = line.path[1][3] - posx;
var dy = line.path[1][4] - posy;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
p2.setAngle(angle + 90);
p2.setCoords();
canvas.bringToFront(p2);
canvas.bringToFront(p0);
canvas.bringToFront(p1);
line.p2 = p2;
})();
function makeArrow(left, top, line1, line2, line3) {
var c = new fabric.Triangle({
width: 5,
height: 5,
left: left+5,
top: top+5,
strokeWidth: 10,
fill: #000,
opacity: 1,
stroke: #000
});
c.hasBorders = c.hasControls = false;
c.angle = 90;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
function makeCurveCircle(left, top, line1, line2, line3) {
var c = new fabric.Circle({
radius: 5,
left: left,
top: top,
strokeWidth: 10,
fill: #000,
stroke: #000
});
c.hasBorders = c.hasControls = false;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
function makeCurvePoint(left, top, line1, line2, line3) {
var c = new fabric.Circle({
radius: 5,
left: left,
top: top,
strokeWidth: 10,
fill: #000,
opacity: 0,
stroke: #000
});
c.hasBorders = c.hasControls = false;
c.angle = 90;
c.line1 = line1;
c.line2 = line2;
c.line3 = line3;
return c;
}
var prevselobj;
function onObjectSelected(e) {
var activeObject = e.target;
reinit_stroke = activeObject.stroke;
if (activeObject.name == "p0" || activeObject.name == "p2") {
if (prevselobj) {
prevselobj.line2.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
prevselobj.line2.selectable = false;
}
activeObject.line2.animate('opacity', '1', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.line2.selectable = true;
prevselobj = activeObject;
}
}
function onBeforeSelectionCleared(e) {
var activeObject = e.target;
if (activeObject.name == "p0" || activeObject.name == "p2") {
activeObject.line2.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.line2.selectable = false;
}
else if (activeObject.name == "p1") {
activeObject.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas),
});
activeObject.selectable = true;
}
}
function onObjectMoving(e) {
if (e.target.name == "p0" || e.target.name == "p2") {
var p = e.target;
var curvedline;
if (p.line1) {
p.line1.path[0][1] = p.left;
p.line1.path[0][2] = p.top + p.height/2;
curvedline = p.line1;
} else if (p.line3) {
p.line3.path[1][3] = p.left;
if(p.line3.path[0][2] <= p.line3.path[1][4])
p.line3.path[1][4] = p.top - p.height/2;
if(p.line3.path[0][2] > p.line3.path[1][4])
p.line3.path[1][4] = p.top + p.height/2;
p.line3.setCoords();
curvedline = p.line3;
}
if (curvedline) {
curvedline.setCoords();
var pt = getQuadraticCurvePoint(curvedline.path[0][1], curvedline.path[0][2], curvedline.path[1][1], curvedline.path[1][2], curvedline.path[1][3], curvedline.path[1][4], 0.5);
p.line2.left = pt.x;
p.line2.top = pt.y;
if (curvedline.p2) {
var pt = getQuadraticCurvePoint(curvedline.path[0][1], curvedline.path[0][2], curvedline.path[1][1], curvedline.path[1][2], curvedline.path[1][3], curvedline.path[1][4], 0.99);
curvedline.p2.left = pt.x;
curvedline.p2.top = pt.y;
var dx = curvedline.path[1][3] - pt.x;
var dy = curvedline.path[1][4] - pt.y;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
curvedline.p2.setAngle(angle + 90);
curvedline.p2.setCoords();
}
p.line2.setCoords();
}
if (e.target.text) {
e.target.text.left = p.left;
e.target.text.top = p.top;
e.target.text.setCoords();
}
} else if (e.target.name == "p1") {
var p = e.target;
if (p.line2) {
p.line2.path[1][1] = p.left;
p.line2.path[1][2] = p.top;
}
curvedline = p.line2;
if (curvedline) {
var pt = getQuadraticCurvePoint(curvedline.path[0][1], curvedline.path[0][2], curvedline.path[1][1], curvedline.path[1][2], curvedline.path[1][3], curvedline.path[1][4], 0.5);
p.left = pt.x;
p.top = pt.y;
p.setCoords();
}
if (curvedline) {
var pt = getQuadraticCurvePoint(curvedline.path[0][1], curvedline.path[0][2], curvedline.path[1][1], curvedline.path[1][2], curvedline.path[1][3], curvedline.path[1][4], 0.99);
curvedline.p2.left = pt.x;
curvedline.p2.top = pt.y;
var dx = curvedline.path[1][3] - pt.x;
var dy = curvedline.path[1][4] - pt.y;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
curvedline.p2.setAngle(angle + 90);
curvedline.p2.setCoords();
}
} else if (e.target.name == "p0" || e.target.name == "p2") {
var p = e.target;
p.line1 && p.line1.set({
'x2': p.left,
'y2': p.top
});
p.line2 && p.line2.set({
'x1': p.left,
'y1': p.top
});
p.line3 && p.line3.set({
'x1': p.left,
'y1': p.top
});
p.line4 && p.line4.set({
'x1': p.left,
'y1': p.top
});
}
p && reinit();
}
function reinit() {
canvas.remove(line);
line = new fabric.Path(line.path, { fill: '',selectable: false });
line.id = line_number;
line.stroke = reinit_stroke;
canvas.add(line);
canvas.sendBackwards(line);
}
canvas.on('mouse:over', function(e) {
if(e.target.type == "path")
{
canvas.sendBackwards(e.target);
}
});
I am using following code for delete the tool.
(Note: this code runs when I click on the delete button.
Delete button deletes the object selected. )
here is the code...
var objs = canvas.getObjects();
if (activeObject) {
active_id = activeObject.get('id');
canvas.forEachObject(function (obj) {
if(obj.get('id') == active_id)
{
if(obj.type == 'path')
{
obj.selectable = true;
canvas.remove(obj);
}
canvas.remove(obj);
}
});
canvas.remove(activeObject);
}
the issue I am getting is after delete this, If I create one other curved arrow in the designer(i.e. without reload the page) and move the nodes then its still showing the old path object which we already deleted.
and If I delete the newly created curved arrow then it removes all path from canvas, In short all Path object behave like one(Hope this is understandable) .
so, the path object is not getting deleted properly it is just getting hidden when I am deleting it. Or may be it is deleted but created again when I am moving another path object..
and if we save the canvas as json then we can see the path objects which are deleted too.
What I need to do is to delete the path object properly and save just the Path object currently showing on the canvas with nodes.
Please tell me if there is some solution for this issues..
Thanks..
I found the solution for the delete curve Issue.
We need to change the code at the reinit() functions.
It was overwrite the line_id to all the line(or say path) in the canvas.
Here is the code to replace with reinit() function..
function reinit() {
var objs = canvas.getObjects();
current_line = canvas.getActiveObject();
canvas.forEachObject(function (obj) {
if(obj.type == 'path' && obj.get("id") == current_line.get("id"))
{
canvas.remove(obj);
line = new fabric.Path(obj.path, { fill: '',selectable: false });
line.id = current_line.get("id");
line.stroke = reinit_stroke;
canvas.add(line);
canvas.sendBackwards(line);
}
});
}
Hope this can be helpful for someone who need this kind of solution..

lightweight draggable jQuery, drag the screen

Online sample: http://jsfiddle.net/5tpPx/
The issue is that, if drag the black square and the mouse off the red square area, the black square follows mouse's movement once move the mouse back to the red square area. How to fix that? like once the mouse of side of the red square area then trigger mouseup?
// jQuery draggable plugin
(function($) {
$.fn.draggable = function(options) {
var $handle = this,
$draggable = this,
draggable = $draggable[0];
parent = draggable.parentNode;
options = $.extend({}, {
handle: null,
cursor: 'move'
}, options);
if( options.handle ) {
$handle = $(options.handle);
}
$handle
.css('cursor', options.cursor)
.on("mousedown", function(e) {
var p_dims = parent.getBoundingClientRect(),
d_dims = draggable.getBoundingClientRect(),
w = p_dims.width-d_dims.width,
h = p_dims.height-d_dims.height;
var x = d_dims.left - e.pageX,
y = d_dims.top - e.pageY,
z = $draggable.css('z-index');
$draggable.css('z-index', 100000);
$(document.documentElement)
.on('mousemove.draggable', function(e) {
var l = x+e.pageX-p_dims.left,
t = y+e.pageY-p_dims.top;
if (l < 0) l = 0;
else if (l > w) l = w;
if (t < 0) t = 0;
else if (t > h) t = h;
console.log(l, t);
$draggable.offset({
left: l+p_dims.left,
top: t+p_dims.top
});
})
.one('mouseup', function() {
$(this).off('mousemove.draggable');
$draggable.css('z-index', z);
});
// disable selection
e.preventDefault();
});
};
})(jQuery);
$('.drag').draggable();
I've updated your code http://jsfiddle.net/5tpPx/3/
added a class dragoff when leaving the parent container and removing it only when the mousedown event it fired again.
Also checked if handle has class dragoff before setting its coords.
// jQuery draggable plugin
(function($) {
$.fn.draggable = function(options) {
var $handle = this,
$draggable = this,
draggable = $draggable[0];
parent = draggable.parentNode;
options = $.extend({}, {
handle: null,
cursor: 'move'
}, options);
if( options.handle ) {
$handle = $(options.handle);
}
$handle
.css('cursor', options.cursor)
.on("mousedown", function(e) {
$handle.removeClass('dragoff')
var p_dims = parent.getBoundingClientRect(),
d_dims = draggable.getBoundingClientRect(),
w = p_dims.width-d_dims.width,
h = p_dims.height-d_dims.height;
var x = d_dims.left - e.pageX,
y = d_dims.top - e.pageY,
z = $draggable.css('z-index');
$draggable.css('z-index', 100000);
$(document.documentElement)
.on('mousemove.draggable', function(e) {
if($handle.hasClass('dragoff')){
e.preventDefault();
return false;
}
var l = x+e.pageX-p_dims.left,
t = y+e.pageY-p_dims.top;
if (l < 0) l = 0;
else if (l > w) l = w;
if (t < 0) t = 0;
else if (t > h) t = h;
console.log(l, t);
$draggable.offset({
left: l+p_dims.left,
top: t+p_dims.top
});
})
.one('mouseup', function() {
$(this).off('mousemove.draggable');
$draggable.css('z-index', z);
});
// disable selection
e.preventDefault();
});
$handle.parent().hover(function(){
},function(){
$handle.addClass('dragoff')
})
};
})(jQuery);
$('.drag').draggable();
Clearly there's a typo in this script. It says:
.one('mouseup', function() {
$(this).off('mousemove.draggable');
$draggable.css('z-index', z);
});
But should be:
.on('mouseup', function() {
$(this).off('mousemove.draggable');
$draggable.css('z-index', z);
});

Cloudzoom and woocommerce attributes

I cannot get cloudzoom to work with my woocommerce site, every time I choose an attribute ie size the main image disappears, it is like cloudzoom is trying to force an attribute image. I am absolutely pants at javascript and looking through the file I cannot see where I need to edit or delete the code. Any help would be greatly appreciated, I don't need the atribute image function to work at all so just stripping out the code would suit me. Here is the code...
(function ($) {
$(document).ready(function () {
$('.cloud-zoom, .cloud-zoom-gallery').CloudZoom();
});
function format(str) {
for (var i = 1; i < arguments.length; i++) {
str = str.replace('%' + (i - 1), arguments[i]);
}
return str;
}
function CloudZoom(jWin, opts) {
var sImg = $('img', jWin);
var img1;
var img2;
var zoomDiv = null;
var $mouseTrap = null;
var lens = null;
var $tint = null;
var softFocus = null;
var $ie6Fix = null;
var zoomImage;
var controlTimer = 0;
var cw, ch;
var destU = 0;
var destV = 0;
var currV = 0;
var currU = 0;
var filesLoaded = 0;
var mx,
my;
var ctx = this, zw;
// Display an image loading message. This message gets deleted when the images have loaded and the zoom init function is called.
// We add a small delay before the message is displayed to avoid the message flicking on then off again virtually immediately if the
// images load really fast, e.g. from the cache.
//var ctx = this;
setTimeout(function () {
// <img src="/images/loading.gif"/>
if ($mouseTrap === null) {
var w = jWin.width();
jWin.parent().append(format('<div style="width:%0px;position:absolute;top:75%;left:%1px;text-align:center" class="cloud-zoom-loading" >Loading...</div>', w / 3, (w / 2) - (w / 6))).find(':last').css('opacity', 0.5);
}
}, 200);
var ie6FixRemove = function () {
if ($ie6Fix !== null) {
$ie6Fix.remove();
$ie6Fix = null;
}
};
// Removes cursor, tint layer, blur layer etc.
this.removeBits = function () {
//$mouseTrap.unbind();
if (lens) {
lens.remove();
lens = null;
}
if ($tint) {
$tint.remove();
$tint = null;
}
if (softFocus) {
softFocus.remove();
softFocus = null;
}
ie6FixRemove();
$('.cloud-zoom-loading', jWin.parent()).remove();
};
this.destroy = function () {
jWin.data('zoom', null);
if ($mouseTrap) {
$mouseTrap.unbind();
$mouseTrap.remove();
$mouseTrap = null;
}
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
//ie6FixRemove();
this.removeBits();
// DON'T FORGET TO REMOVE JQUERY 'DATA' VALUES
};
// This is called when the zoom window has faded out so it can be removed.
this.fadedOut = function () {
if (zoomDiv) {
zoomDiv.remove();
zoomDiv = null;
}
this.removeBits();
//ie6FixRemove();
};
this.controlLoop = function () {
if (lens) {
var x = (mx - sImg.offset().left - (cw * 0.5)) >> 0;
var y = (my - sImg.offset().top - (ch * 0.5)) >> 0;
if (x < 0) {
x = 0;
}
else if (x > (sImg.outerWidth() - cw)) {
x = (sImg.outerWidth() - cw);
}
if (y < 0) {
y = 0;
}
else if (y > (sImg.outerHeight() - ch)) {
y = (sImg.outerHeight() - ch);
}
lens.css({
left: x,
top: y
});
lens.css('background-position', (-x) + 'px ' + (-y) + 'px');
destU = (((x) / sImg.outerWidth()) * zoomImage.width) >> 0;
destV = (((y) / sImg.outerHeight()) * zoomImage.height) >> 0;
currU += (destU - currU) / opts.smoothMove;
currV += (destV - currV) / opts.smoothMove;
zoomDiv.css('background-position', (-(currU >> 0) + 'px ') + (-(currV >> 0) + 'px'));
}
controlTimer = setTimeout(function () {
ctx.controlLoop();
}, 30);
};
this.init2 = function (img, id) {
filesLoaded++;
//console.log(img.src + ' ' + id + ' ' + img.width);
if (id === 1) {
zoomImage = img;
}
//this.images[id] = img;
if (filesLoaded === 2) {
this.init();
}
};
/* Init function start. */
this.init = function () {
// Remove loading message (if present);
$('.cloud-zoom-loading', jWin.parent()).remove();
/* Add a box (mouseTrap) over the small image to trap mouse events.
It has priority over zoom window to avoid issues with inner zoom.
We need the dummy background image as IE does not trap mouse events on
transparent parts of a div.
*/
$mouseTrap = jWin.parent().append(format("<div class='mousetrap' style='background-image:url(\".\");z-index:3;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;\'></div>", sImg.outerWidth(), sImg.outerHeight(), 0, 0)).find(':last');
//////////////////////////////////////////////////////////////////////
/* Do as little as possible in mousemove event to prevent slowdown. */
$mouseTrap.bind('mousemove', this, function (event) {
// Just update the mouse position
mx = event.pageX;
my = event.pageY;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseleave', this, function (event) {
clearTimeout(controlTimer);
//event.data.removeBits();
if(lens) { lens.fadeOut(299); }
if($tint) { $tint.fadeOut(299); }
if(softFocus) { softFocus.fadeOut(299); }
zoomDiv.fadeOut(300, function () {
ctx.fadedOut();
});
return false;
});
//////////////////////////////////////////////////////////////////////
$mouseTrap.bind('mouseenter', this, function (event) {
mx = event.pageX;
my = event.pageY;
zw = event.data;
if (zoomDiv) {
zoomDiv.stop(true, false);
zoomDiv.remove();
}
var xPos = opts.adjustX,
yPos = opts.adjustY;
var siw = sImg.outerWidth();
var sih = sImg.outerHeight();
var w = opts.zoomWidth;
var h = opts.zoomHeight;
if (opts.zoomWidth == 'auto') {
w = siw;
}
if (opts.zoomHeight == 'auto') {
h = sih;
}
//$('#info').text( xPos + ' ' + yPos + ' ' + siw + ' ' + sih );
var appendTo = jWin.parent(); // attach to the wrapper
switch (opts.position) {
case 'top':
yPos -= h; // + opts.adjustY;
break;
case 'right':
xPos += siw; // + opts.adjustX;
break;
case 'bottom':
yPos += sih; // + opts.adjustY;
break;
case 'left':
xPos -= w; // + opts.adjustX;
break;
case 'inside':
w = siw;
h = sih;
break;
// All other values, try and find an id in the dom to attach to.
default:
appendTo = $('#' + opts.position);
// If dom element doesn't exit, just use 'right' position as default.
if (!appendTo.length) {
appendTo = jWin;
xPos += siw; //+ opts.adjustX;
yPos += sih; // + opts.adjustY;
} else {
w = appendTo.innerWidth();
h = appendTo.innerHeight();
}
}
zoomDiv = appendTo.append(format('<div id="cloud-zoom-big" class="cloud-zoom-big" style="display:none;position:absolute;left:%0px;top:%1px;width:%2px;height:%3px;background-image:url(\'%4\');z-index:2;"></div>', xPos, yPos, w, h, zoomImage.src)).find(':last');
// Add the title from title tag.
if (sImg.attr('title') && opts.showTitle) {
zoomDiv.append(format('<div class="cloud-zoom-title">%0</div>', sImg.attr('title'))).find(':last').css('opacity', opts.titleOpacity);
}
// Fix ie6 select elements wrong z-index bug. Placing an iFrame over the select element solves the issue...
if ($.browser.msie && $.browser.version < 7) {
$ie6Fix = $('<iframe frameborder="0" src="#"></iframe>').css({
position: "absolute",
left: xPos,
top: yPos,
zIndex: 99,
width: w,
height: h
}).insertBefore(zoomDiv);
}
zoomDiv.fadeIn(500);
if (lens) {
lens.remove();
lens = null;
} /* Work out size of cursor */
cw = (sImg.outerWidth() / zoomImage.width) * zoomDiv.width();
ch = (sImg.outerHeight() / zoomImage.height) * zoomDiv.height();
// Attach mouse, initially invisible to prevent first frame glitch
lens = jWin.append(format("<div class = 'cloud-zoom-lens' style='display:none;z-index:1;position:absolute;width:%0px;height:%1px;opacity:0.4'></div>", cw, ch)).find(':last');
$mouseTrap.css('cursor', lens.css('cursor'));
var noTrans = false;
// Init tint layer if needed. (Not relevant if using inside mode)
if (opts.tint) {
/* lens.css('background', 'url("' + sImg.attr('src') + '")'); */
$tint = jWin.append(format('<div style="display:none;position:absolute; left:0px; top:0px; width:%0px; height:%1px; background-color:%2;" />', sImg.outerWidth(), sImg.outerHeight(), opts.tint)).find(':last');
$tint.css('opacity', opts.tintOpacity);
noTrans = true;
$tint.fadeIn(500);
}
if (opts.softFocus) {
lens.css('background', 'url("' + sImg.attr('src') + '")');
softFocus = jWin.append(format('<div style="position:absolute;display:none;top:2px; left:2px; width:%0px; height:%1px;" />', sImg.outerWidth() - 2, sImg.outerHeight() - 2, opts.tint)).find(':last');
softFocus.css('background', 'url("' + sImg.attr('src') + '")');
softFocus.css('opacity', 0.5);
noTrans = true;
softFocus.fadeIn(500);
}
if (!noTrans) {
lens.css('opacity', opts.lensOpacity);
}
if ( opts.position !== 'inside' ) { lens.fadeIn(500); }
// Start processing.
zw.controlLoop();
return; // Don't return false here otherwise opera will not detect change of the mouse pointer type.
});
};
img1 = new Image();
$(img1).load(function () {
ctx.init2(this, 0);
});
img1.src = sImg.attr('src');
img2 = new Image();
$(img2).load(function () {
ctx.init2(this, 1);
});
img2.src = jWin.attr('href');
}
$.fn.CloudZoom = function (options) {
// IE6 background image flicker fix
try {
document.execCommand("BackgroundImageCache", false, true);
} catch (e) {}
this.each(function () {
var relOpts, opts;
// Hmm...eval...slap on wrist.
eval('var a = {' + $(this).attr('rel') + '}');
relOpts = a;
if ($(this).is('.cloud-zoom')) {
$(this).css({
'position': 'relative',
'display': 'block'
});
$('img', $(this)).css({
'display': 'block'
});
// Wrap an outer div around the link so we can attach things without them becoming part of the link.
// But not if wrap already exists.
if ($(this).parent().attr('id') != 'wrap') {
$(this).wrap('<div id="wrap" style="top:0px;z-index:4;position:relative;"></div>');
}
opts = $.extend({}, $.fn.CloudZoom.defaults, options);
opts = $.extend({}, opts, relOpts);
$(this).data('zoom', new CloudZoom($(this), opts));
} else if ($(this).is('.cloud-zoom-gallery')) {
opts = $.extend({}, relOpts, options);
$(this).data('relOpts', opts);
$(this).bind('click', $(this), function (event) {
var data = event.data.data('relOpts');
// Destroy the previous zoom
$('#' + data.useZoom).data('zoom').destroy();
// Change the biglink to point to the new big image.
$('#' + data.useZoom).attr('href', event.data.attr('href'));
// Change the small image to point to the new small image.
$('#' + data.useZoom + ' img').attr('src', event.data.data('relOpts').smallImage);
// Init a new zoom with the new images.
$('#zoom-cb').attr('href', event.data.attr('href'));
$('#' + event.data.data('relOpts').useZoom).CloudZoom();
return false;
});
}
});
return this;
};
$.fn.CloudZoom.defaults = {
zoomWidth: 'auto',
zoomHeight: 'auto',
position: 'right',
tint: false,
tintOpacity: 0.5,
lensOpacity: 0.5,
softFocus: false,
smoothMove: 3,
showTitle: false,
titleOpacity: 0.5,
adjustX: 0,
adjustY: 0
};
})(jQuery);

HTML5 Canvas issue

Is there a way to stop users on dragging the mouse down so they only can click instead of click and drag. I want htem to be only to draw dots on the canvas or any pattern i define similar to a stamp tool.
function Sketcher( canvasID, brushImage ) {
this.renderFunction = (brushImage == null || brushImage == undefined) ? this.updateCanvasByLine : this.updateCanvasByBrush;
this.brush = brushImage;
this.touchSupported = Modernizr.touch;
this.canvasID = canvasID;
this.canvas = $("#"+canvasID);
this.context = this.canvas.get(0).getContext("2d");
this.context.strokeStyle = "#000000";
this.context.lineWidth = 3;
this.lastMousePoint = {x:0, y:0};
if (this.touchSupported) {
this.mouseDownEvent = "touchstart";
this.mouseMoveEvent = "touchmove";
this.mouseUpEvent = "touchend";
}
else {
this.mouseDownEvent = "mousedown";
this.mouseMoveEvent = "mousemove";
this.mouseUpEvent = "mouseup";
}
this.canvas.bind( this.mouseDownEvent, this.onCanvasMouseDown() );
}
Sketcher.prototype.onCanvasMouseDown = function () {
var self = this;
return function(event) {
self.mouseMoveHandler = self.onCanvasMouseMove()
self.mouseUpHandler = self.onCanvasMouseUp()
$(document).bind( self.mouseMoveEvent, self.mouseMoveHandler );
$(document).bind( self.mouseUpEvent, self.mouseUpHandler );
self.updateMousePosition( event );
self.renderFunction( event );
}
}
Sketcher.prototype.onCanvasMouseMove = function () {
var self = this;
return function(event) {
self.renderFunction( event );
event.preventDefault();
return false;
}
}
Sketcher.prototype.onCanvasMouseUp = function (event) {
var self = this;
return function(event) {
$(document).unbind( self.mouseMoveEvent, self.mouseMoveHandler );
$(document).unbind( self.mouseUpEvent, self.mouseUpHandler );
self.mouseMoveHandler = null;
self.mouseUpHandler = null;
}
}
Sketcher.prototype.updateMousePosition = function (event) {
var target;
if (this.touchSupported) {
target = event.originalEvent.touches[0]
}
else {
target = event;
}
var offset = this.canvas.offset();
this.lastMousePoint.x = target.pageX - offset.left;
this.lastMousePoint.y = target.pageY - offset.top;
}
Sketcher.prototype.updateCanvasByLine = function (event) {
this.context.beginPath();
this.context.moveTo( this.lastMousePoint.x, this.lastMousePoint.y );
this.updateMousePosition( event );
this.context.lineTo( this.lastMousePoint.x, this.lastMousePoint.y );
this.context.stroke();
}
Sketcher.prototype.updateCanvasByBrush = function (event) {
var halfBrushW = this.brush.width/2;
var halfBrushH = this.brush.height/2;
var start = { x:this.lastMousePoint.x, y: this.lastMousePoint.y };
this.updateMousePosition( event );
var end = { x:this.lastMousePoint.x, y: this.lastMousePoint.y };
var distance = parseInt( Trig.distanceBetween2Points( start, end ) );
var angle = Trig.angleBetween2Points( start, end );
var x,y;
for ( var z=0; (z<=distance || z==0); z++ )
{
x = start.x + (Math.sin(angle) * z) - halfBrushW;
y = start.y + (Math.cos(angle) * z) - halfBrushH;
//console.log( x, y, angle, z );
this.context.drawImage(this.brush, x, y);
}
}
Sketcher.prototype.toString = function () {
var dataString = this.canvas.get(0).toDataURL("image/png");
var index = dataString.indexOf( "," )+1;
dataString = dataString.substring( index );
return dataString;
}
Sketcher.prototype.toDataURL = function () {
var dataString = this.canvas.get(0).toDataURL("image/png");
return dataString;
}
Sketcher.prototype.clear = function () {
var c = this.canvas[0];
this.context.clearRect( 0, 0, c.width, c.height );
}
You can achieve this by simply ignoring the mousemove and mouseup event handlers by either not initializing them or using flags to indicate that you are in stamp mode.
All you need is:
canvas.onmousedown = function(e) {
var pos = getMousePos(e);
render(pos.x, pos.y);
}
That's it, and it works similar for touch events.
To use flag (I would not recommend adding and removing handlers all the time):
var isStampMode = true;
canvas.onmousemove = function(e) {
if (isStampMode) return;
...
}
and similar for mouse up (but not really necessary unless it depends on what you do in mousedown).
Live example here
Hope this helps!

OpenLayers: Rotate image with ModifyFeature as Polygon or other

I need to allow user to rotate bitmap features on map with OpenLayers.Control.ModifyFeature or another way as it work for Polygons or other geometry objects, except Point, but only for Point I can set "externalGraphic" with my bitmap. Example of ModifyFeature to rotation as I expected here: ModifyFeature example
When I add Vector with Point geometry and activate ModifyFeature there is no rotation tool showing - only drag-drop. I know what is a point, but I need to have tool for rotate bitmap features. It may be image on any another geometry object, but with custom image.
After long research I found an example in gis.stackexchange.com, and fix it.
Here is a code which works for me:
OpenLayers.Control.RotateGraphicFeature = OpenLayers.Class(OpenLayers.Control.ModifyFeature, {
rotateHandleStyle: null,
initialize: function(layer, options) {
OpenLayers.Control.ModifyFeature.prototype.initialize.apply(this, arguments);
this.mode = OpenLayers.Control.ModifyFeature.ROTATE; // This control can only be used to rotate the feature
this.geometryTypes = ['OpenLayers.Geometry.Point'] // This control can only be used to rotate point because the 'exteralGraphic' is a point style property
var init_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style.select);
this.rotateHandleStyle = OpenLayers.Util.extend(init_style, {
externalGraphic: "./static/resources/images/cross.png",
graphicWidth: 12,
graphicHeight: 12,
fillOpacity: 1
});
},
resetVertices: function() {
// You need to set yours renderIntent or use "vertex"
if (this.feature && this.feature.renderIntent == "vertex") {
var vertex = this.feature;
this.feature = this.backup_feature;
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.collectRadiusHandle();
return;
}
if (this.dragControl.feature) {
this.dragControl.outFeature(this.dragControl.feature);
}
if (this.vertices.length > 0) {
this.layer.removeFeatures(this.vertices, {silent: true});
this.vertices = [];
}
if (this.virtualVertices.length > 0) {
this.layer.removeFeatures(this.virtualVertices, {silent: true});
this.virtualVertices = [];
}
if (this.dragHandle) {
this.layer.destroyFeatures([this.dragHandle], {silent: true});
this.dragHandle = null;
}
if (this.radiusHandle) {
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.radiusHandle = null;
}
if (this.feature && this.feature.geometry &&
this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
if ((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
this.collectDragHandle();
}
if ((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
OpenLayers.Control.ModifyFeature.RESIZE))) {
this.collectRadiusHandle();
}
if (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE) {
if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) {
this.collectVertices();
}
}
}
this.collectRadiusHandle();
},
collectRadiusHandle: function() {
var scope = this,
feature = this.feature,
geometry = this.feature.geometry || this.backup_feature.geometry,
centroid = geometry.getCentroid().transform(this.WGS84_google_mercator, this.WGS84),
lon = centroid.x, lat = centroid.y;
if (this.feature.geometry) {
this.backup_feature = this.feature;
} else {
this.feature.geometry = this.backup_feature.geometry;
}
var originGeometry = new OpenLayers.Geometry.Point(lon, lat);
// radius geometry position.
var pixel_dis_x = 10,
pixel_dis_y = -10;
var rotationFeatureGeometry = new OpenLayers.Geometry.Point(lon+pixel_dis_x, lat+pixel_dis_y);
var rotationFeature = new OpenLayers.Feature.Vector(rotationFeatureGeometry, null, this.rotateHandleStyle);
var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
rotationFeatureGeometry.move = function(x, y) {
OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
var dx1 = this.x - originGeometry.x;
var dy1 = this.y - originGeometry.y;
var dx0 = dx1 - x;
var dy0 = dy1 - y;
if (rotate) {
var a0 = Math.atan2(dy0, dx0);
var a1 = Math.atan2(dy1, dx1);
var angle = a1 - a0;
angle *= 180 / Math.PI;
var old_angle = feature.attributes.angle;
var new_angle = old_angle - angle;
feature.attributes.angle = new_angle;
// redraw the feature
scope.feature.layer.redraw.call(scope.feature.layer);
}
};
rotationFeature._sketch = true;
this.radiusHandle = rotationFeature;
this.radiusHandle.renderIntent = this.vertexRenderIntent;
this.layer.addFeatures([this.radiusHandle], {silent: true});
},
CLASS_NAME: "OpenLayers.Control.RotateGraphicFeature"
});
Style of your Vector may be as:
new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
externalGraphic: "link/to/icon",
graphicHeight: "32px",
graphicWidth: "25px",
fillOpacity: 1,
rotation: "${angle}",
graphicZIndex: 1
})
})
UPD: I fixed it for OpenLayers 2.13.1
OpenLayers.Control.RotateGraphicFeature = OpenLayers.Class(OpenLayers.Control.ModifyFeature, {
rotateHandleStyle: null,
initialize: function (layer, options) {
OpenLayers.Control.ModifyFeature.prototype.initialize.apply(this, arguments);
this.mode = OpenLayers.Control.ModifyFeature.ROTATE; // This control can only be used to rotate the feature
this.geometryTypes = ['OpenLayers.Geometry.Point'] // This control can only be used to rotate point because the 'exteralGraphic' is a point style property
var init_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style.select);
this.rotateHandleStyle = OpenLayers.Util.extend(init_style, {
externalGraphic: "./static/resources/images/cross.png",
graphicWidth: 12,
graphicHeight: 12,
fillOpacity: 1
});
},
resetVertices: function () {
// You need to set yours renderIntent or use "vertex"
if (this.feature && this.feature.renderIntent == "vertex") {
var vertex = this.feature;
this.feature = this.backup_feature;
if (this.dragControl.feature) {
this.dragControl.outFeature(this.dragControl.feature);
}
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
delete this.radiusHandle;
this.collectRadiusHandle();
return;
}
if (this.vertices.length > 0) {
this.layer.removeFeatures(this.vertices, {silent: true});
this.vertices = [];
}
if (this.virtualVertices.length > 0) {
this.layer.removeFeatures(this.virtualVertices, {silent: true});
this.virtualVertices = [];
}
if (this.dragHandle) {
this.layer.destroyFeatures([this.dragHandle], {silent: true});
this.dragHandle = null;
}
if (this.radiusHandle) {
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.radiusHandle = null;
}
if (this.feature && this.feature.geometry &&
this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
if ((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
this.collectDragHandle();
}
if ((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
OpenLayers.Control.ModifyFeature.RESIZE))) {
this.collectRadiusHandle();
}
if (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE) {
if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) {
this.collectVertices();
}
}
}
this.collectRadiusHandle();
},
collectRadiusHandle: function () {
var scope = this,
feature = this.feature,
data = feature.attributes,
geometry = this.feature.geometry || this.backup_feature.geometry,
center = this.feature.geometry.bounds.getCenterLonLat();
centroid = geometry.getCentroid().transform(this.WGS84_google_mercator, this.WGS84),
lon = centroid.x, lat = centroid.y;
if (data.type && Tms.settings.roadObjectTypeSettings[data.type].NoAzimuth) {
return;
}
if (this.feature.geometry) {
this.backup_feature = this.feature;
} else {
this.feature.geometry = this.backup_feature.geometry;
}
var originGeometry = new OpenLayers.Geometry.Point(lon, lat);
var center_px = this.map.getPixelFromLonLat(center);
// you can change this two values to get best radius geometry position.
var pixel_dis_x = 20,
pixel_dis_y = 20;
var radius_px = center_px.add(pixel_dis_x, pixel_dis_y);
var rotation_lonlat = this.map.getLonLatFromPixel(radius_px);
var rotationFeatureGeometry = new OpenLayers.Geometry.Point(
rotation_lonlat.lon, rotation_lonlat.lat
);
var rotationFeature = new OpenLayers.Feature.Vector(rotationFeatureGeometry, null, this.rotateHandleStyle);
var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
rotationFeatureGeometry.move = function(x, y) {
OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
var dx1 = this.x - originGeometry.x;
var dy1 = this.y - originGeometry.y;
var dx0 = dx1 - x;
var dy0 = dy1 - y;
if (rotate) {
var a0 = Math.atan2(dy0, dx0);
var a1 = Math.atan2(dy1, dx1);
var angle = a1 - a0;
angle *= 180 / Math.PI;
var old_angle = feature.attributes.angle;
var new_angle = old_angle - angle;
feature.attributes.angle = new_angle;
// redraw the feature
scope.feature.layer.redraw.call(scope.feature.layer);
}
};
rotationFeature._sketch = true;
this.radiusHandle = rotationFeature;
this.radiusHandle.renderIntent = this.vertexRenderIntent;
this.layer.addFeatures([this.radiusHandle], {silent: true});
},
CLASS_NAME: "OpenLayers.Control.RotateGraphicFeature"
});

Categories