I have a <div> element, which should adjust width + height according to the document properties. I need to resize the <div> whenever the user scrolls inside the window.
Is there a possibility to bind the events to this specific object?
var instance = (function() {
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth || 0,
y = w.innerHeight || e.clientHeight || g.clientHeight || 0,
z = Math.max(g.scrollHeight || 0, e.scrollHeight || 0, g.offsetHeight || 0, e.offsetHeight || 0, g.clientHeight || 0, e.clientHeight || 0);
// private
function getMeById(id) {
return d.getElementById(id);
};
// public
return {
updateContainer: function(id) {
console.log('updateContainer');
var container = getMeById(id);
container.style.position = 'absolute';
container.style.width = x + 'px';
container.style.minHeight = z + 'px';
},
bindScroll: function() {
w.addEventListener('scroll', updateContainer(), false);
}
};
})();
instance.updateContainer("test");
/* #TODO: Bind events to object
w.addEventListener('resize', () => {
console.log('resize');
var container = getMeById("test");
updateContainer(container);
}, true);
w.addEventListener('scroll', () => {
console.log('scroll');
var container = getMeById("test");
updateContainer(container);
}, true);
*/
<div id="test"></div>
As you can see from the bindScroll() function it makes no sense right now.
Is there anyway to achieve the task?
You may pass the id into the eventListener callback through binding it to the updateContainer:
updateContainer: function(id) {
console.log('updateContainer');
var container = getMeById(id);
container.style.position = 'absolute';
container.style.width = x + 'px';
container.style.minHeight = z + 'px';
},
bindScroll: function(id) {
window.addEventListener('scroll', this.updateContainer.bind(this,id), false);
}
So one can do:
instance.bindScroll("testcontainer");
Note: x and z are not live so you may reload the values...
If you add more and more functions, your code could get difficult to manage. You could use inheritance and a constructor instead:
function instance(id){
this.el=document.querySelector(id);
}
instance.prototype={
bindScroll:function(){
window.addEventListener("scroll",this.update.bind(this),false);
return this;
},
update: function() {
var container = this.el;
container.style.position = 'absolute';
container.style.width = x + 'px';
container.style.minHeight = z + 'px';
return this;
}
};
So you could do:
var test=new instance("#test")
test.update().bindScroll();
Related
I am trying to develop a javascript library that makes it easier for me to generate DOM Elements and edit their attributes. The problem I am having is that there is so many attributes for some elements that it is making for messy code. For instance I have to programmatically set the color of border, background, shadow, etc. using a method call before generation.
See setBorder Nested in function Div in jLibrary.php
function Div() {
Div.POSITION = {
STATIC : 'static',
ABSOLUTE : 'absolute',
RELATIVE : 'relative',
FIXED : 'fixed'
}
Div.BORDER = {
SOLID : 'solid',
DOTTED : 'dotted'
}
Div.ALIGN = {
LEFT : 0,
CENTER : 1,
RIGHT : 2,
TOP : 0,
MIDDLE : 1,
BOTTOM : 2
}
var ELEMENT;
var CSS;
var horizontalAlign;
var verticalAlign;
var colorQueue;
(function() {
this.div = document.createElement('div');
ELEMENT = this.div;
CSS = this.div.style;
colorQueue = 'rgb(' + new Array(0, 0, 0) + ')';
document.body.appendChild(this.div);
}());
this.setPosition = function(postype) {
if (!horizontalAlign && !verticalAlign) {
CSS.position = postype;
}
}
this.setBounds = function(x, y, width, height) {
CSS.left = x + 'px';
CSS.top = y + 'px';
CSS.width = width + 'px';
CSS.height = height + 'px';
}
this.setColorQueue = function(r, g, b) {
colorQueue = 'rgb(' + new Array(r, g, b) + ')';
alert(colorQueue);
}
this.setBackgroundColorToQueue = function(){
CSS.backgroundColor = colorQueue;
}
this.createShadow = function(x, y, width, height){
CSS.boxShadow = y + 'px ' + x + 'px ' + width + 'px ' + height + 'px ' + colorQueue;
}
this.createBorder = function(width,style){
CSS.border = width + 'px ' + style + ' ' + colorQueue;
/* Theoretical Method.
this.setColor = function(r,g,b){ //This will not work the way I want it...
CSS.border = 'rgb(' + new Array(r, g, b) + ')';
}
*/
}
this.rotateDiv = function(degrees){
CSS.transform = 'rotate(' + degrees + 'deg)';
}
this.horizontalAlign = function(horiz) {
var freeSpaceX = ((window.innerWidth - ELEMENT.offsetWidth) / 2);
var defPadding = '8px';
var defPaddingCenter;
var defPaddingRight;
var defPaddingLeft;
horizontalAlign = true;
if (CSS.position == 'relative' || CSS.position == 'static' || CSS.position == 'absolute') {
CSS.position = 'absolute';
defPaddingCenter = 4;
defPaddingRight = 4;
defPaddingLeft = 8;
} else if (CSS.position == 'fixed') {
defPaddingCenter = 4;
defPaddingRight = 4;
defPaddingLeft = 8;
}
if (horiz == 0) {
if (!verticalAlign) {
CSS.marginTop = defPadding;
}
CSS.marginLeft = defPaddingLeft + 'px';
} else if (horiz == 1) {
if (!verticalAlign) {
CSS.marginTop = defPadding;
}
CSS.marginLeft = freeSpaceX - defPaddingCenter + 'px';
} else if (horiz == 2) {
if (!verticalAlign) {
CSS.marginTop = defPadding;
}
CSS.marginLeft = (freeSpaceX - defPaddingRight) * 2 + 'px';
}
}
this.verticalAlign = function(vertical) {
var freeSpaceY = ((window.innerHeight - ELEMENT.offsetHeight) / 2);
var defPadding = '8px';
var defPaddingTop;
var defPaddingMid;
var defPaddingBot;
verticalAlign = true;
if (CSS.position == 'relative' || CSS.position == 'static') {
CSS.position = 'absolute';
}
defPaddingTop = 8;
defPaddingMid = 8;
defPaddingBot = 8;
if (vertical == 0) {
if (!horizontalAlign) {
CSS.marginLeft = defPadding;
}
CSS.marginTop = defPadding;
} else if (vertical == 1) {
if (!horizontalAlign) {
CSS.marginLeft = defPadding;
}
CSS.marginTop = freeSpaceY - defPaddingMid + 'px';
} else if (vertical == 2) {
if (!horizontalAlign) {
CSS.marginLeft = defPadding;
}
CSS.marginTop = (freeSpaceY * 2) - defPaddingBot + 'px';
}
}
}
setBorder Example in index.php
var div1 = new Div();
div1.setPosition(Div.POSITION.ABSOLUTE);
div1.setBounds(0,700, 200,200);
div1.setColorQueue(0,0,0); //This method must be called every time a different color is needed for a certain attribute.
div1.createBorder(5, Div.BORDER.SOLID); // I really want something like this --> div1.createBorder(5,Div.BORDER.SOLID).setColor(0,0,0);
You can try using the Builder pattern:
function DivBuilder() {
var color;
var border;
var position;
var bounds;
this.DivBuilder = function() {}
this.color = function(c) {
//set the color
this.color = c;
return this;
}
this.border = function(b) {
//set the border
this.border = b;
return this;
}
this.position = function(p) {
//set position
this.position = p;
return this;
}
this.bounds = function(b) {
//set bounds
this.border = b;
return this;
}
this.build = function () {
//build the new Div object with the properties of the builder
var d = new Div(this);
return d;
}
}
and then:
var divb = new DivBuilder();
divb.position().bounds().border().color();
var div = divb.buid();
Main advantage over the telescopic constructor pattern (well, the adaptation of it to javascript) is that you can choose easier which property you want to initialize without having to create many different constructor cases.
If you want to write this.createBorder(...).setColor(...) It means that createBorder should return an object with the setColor method...
Thanks to Sebas I was able to come up with this... Please vote up Sebas if this helped you.
Nested in this.createBorder()
this.createBorder = function(width) {
CSS.border = width + 'px';
function DivBorderBuilder() {
this.setColor = function(r, b, g) {
alert('color');
CSS.borderColor = 'rgb(' + new Array(r, g, b) + ')';
return this;
}
this.setStyle = function(s){
CSS.borderStyle = s;
return this;
}
}return new DivBorderBuilder();
}
Creating Border in index.php
<script>
var div1 = new Div();
div1.setPosition(Div.POSITION.ABSOLUTE);
div1.setBounds(0,700, 200,200);
div1.createBorder(5).setStyle(Div.BORDER.SOLID).setColor(255,0,0);// Works Perfectly Now !
</script>
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);
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!
The Issue
I am using the following example code to draw arrows on google map.
Here is the main overlay function that creates the svg files for the arrow.
// A small directable Arrow overlay for GMaps V3
// Bill Chadwick Feb 2012 after my previous V2 API version
// Free for any use as far as I am concerned
// Some public domain code VML/SVG utility code of Ben Appleton's is reused at the end of this file
var arrowOverlayMarkerCounter; //unique id counter for SVG arrow head markers
function ArrowOverlay(map, location, rotation, color, opacity, tooltip) {
this.map_ = map;
this.location_ = location;
this.rotation_ = rotation || 0.0;
var r = this.rotation_ + 90; //compass to math
this.dx_ = 20 * Math.cos(r * Math.PI / 180); //other end of arrow line to point
this.dy_ = 20 * Math.sin(r * Math.PI / 180);
this.color_ = color || "#0000FF";
this.opacity_ = opacity || 0.7;
this.tooltip_ = tooltip || "";
this.div_ = null;
this.setMap(map);
this.handle_ = null;//click event handler handle
if (arrowOverlayMarkerCounter == null)
arrowOverlayMarkerCounter = 0;
else
arrowOverlayMarkerCounter += 1;
this.svgId_ = "ArrowOverlay" + arrowOverlayMarkerCounter.toString();
}
ArrowOverlay.prototype = new google.maps.OverlayView();
ArrowOverlay.prototype.onAdd = function() {
// Create the DIV and set some basic attributes.
var div = document.createElement('DIV');
div.title = this.tooltip_;
div.style.cursor = "help";
var obj = this;
this.handle_ = google.maps.event.addDomListener(div, 'click', function() { google.maps.event.trigger(obj, "click") });
//set up arrow invariants
if (supportsVML()) {
var l = createVmlElement('v:line', div);
l.strokeweight = "3px";
l.strokecolor = this.color_;
l.style.position = 'absolute';
var s = createVmlElement("v:stroke", l);
s.opacity = this.opacity_;
s.startarrow = "classic"; // or "block", "open" etc see VML spec
this.vmlLine_ = l;
}
else {
// make a 40x40 pixel space centered on the arrow
var svgNS = "http://www.w3.org/2000/svg";
var svgRoot = document.createElementNS(svgNS, "svg");
svgRoot.setAttribute("width", 40);
svgRoot.setAttribute("height", 40);
svgRoot.setAttribute("stroke", this.color_);
svgRoot.setAttribute("fill", this.color_);
svgRoot.setAttribute("stroke-opacity", this.opacity_);
svgRoot.setAttribute("fill-opacity", this.opacity_);
div.appendChild(svgRoot);
var svgNode = document.createElementNS(svgNS, "line");
svgNode.setAttribute("stroke-width", 3);
svgNode.setAttribute("x1", 20);
svgNode.setAttribute("y1", 20);
svgNode.setAttribute("x2", 20 + this.dx_);
svgNode.setAttribute("y2", 20 + this.dy_);
//make a solid arrow head, can't share these, as in SVG1.1 they can't get color from the referencing object, only their parent
//a bit more involved than the VML
if (this.rotation_ >= 0) {
var svgM = document.createElementNS(svgNS, "marker");
svgM.id = this.svgId_;
svgM.setAttribute("viewBox", "0 0 10 10");
svgM.setAttribute("refX", 0);
svgM.setAttribute("refY", 5);
svgM.setAttribute("markerWidth", 4);
svgM.setAttribute("markerHeight", 3);
svgM.setAttribute("orient", "auto");
var svgPath = document.createElementNS(svgNS, "path"); //could share this with 'def' and 'use' but hardly worth it
svgPath.setAttribute("d", "M 10 0 L 0 5 L 10 10 z");
svgM.appendChild(svgPath);
svgRoot.appendChild(svgM);
svgNode.setAttribute("marker-start", "url(#" + this.svgId_ + ")");
}
svgRoot.appendChild(svgNode);
this.svgRoot_ = svgRoot;
this.svgNode_ = svgNode;
}
// Set the overlay's div_ property to this DIV
this.div_ = div;
var panes = this.getPanes();
panes.overlayImage.appendChild(this.div_);
}
ArrowOverlay.prototype.draw = function() {
var overlayProjection = this.getProjection();
var p = overlayProjection.fromLatLngToDivPixel(this.location_);
var div = this.div_;
if (!div)
return;
if (!div.style)
return;
// Calculate the DIV coordinates of the ref point of our arrow
var x2 = p.x + this.dx_;
var y2 = p.y + this.dy_;
if (supportsVML()) {
this.vmlLine_.from = p.x + "px, " + p.y + "px";
this.vmlLine_.to = x2 + "px, " + y2 + "px";
}
else {
this.svgRoot_.setAttribute("style", "position:absolute; top:" + (p.y - 20) + "px; left:" + (p.x - 20) + "px");
}
}
ArrowOverlay.prototype.onRemove = function() {
if (this.handle_ != null) {
google.maps.eventclear.removeListener(this.handle_);
}
this.div_.parentNode.removeChild(this.div_);
}
ArrowOverlay.prototype.setVisible = function(v) {
if (v)
this.show();
else
this.hide();
}
ArrowOverlay.prototype.getVisible = function(v) {
if (this.div_) {
return (this.div_.style.display == "");
}
return false;
}
ArrowOverlay.prototype.hide = function() {
if (this.div_) {
this.div_.style.display = "none";
}
}
ArrowOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.display = "";
}
}
ArrowOverlay.prototype.setPosition = function(l) {
this.location_ = l;
this.draw();
}
ArrowOverlay.prototype.getPosition = function() {
return this.location_;
}
ArrowOverlay.prototype.setHeading = function(h) {
this.rotation_ = h || 0.0;
var r = this.rotation_ + 90; //compass to math
this.dx_ = 20 * Math.cos(r * Math.PI / 180); //other end of arrow line to point
this.dy_ = 20 * Math.sin(r * Math.PI / 180);
if (!supportsVML()) {
this.svgNode_.setAttribute("x2", 20 + this.dx_);
this.svgNode_.setAttribute("y2", 20 + this.dy_);
}
this.draw();
}
ArrowOverlay.prototype.getHeading = function() {
return this.rotation_;
}
ArrowOverlay.prototype.setTooltip = function(t) {
this.tooltip_ = t;
}
ArrowOverlay.prototype.getTooltip = function() {
return this.tooltip_;
}
ArrowOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility == "hidden") {
this.show();
} else {
this.hide();
}
}
}
ArrowOverlay.prototype.fromDivPixelToLatLng = function(x, y) {
var overlayProjection = this.getProjection();
return overlayProjection.fromDivPixelToLatLng(new google.maps.Point(x, y));
}
ArrowOverlay.prototype.fromLatLngToContainerPixel = function(p) {
var overlayProjection = this.getProjection();
return overlayProjection.fromLatLngToContainerPixel(p);
}
// SVG utils from here http://appleton-static.appspot.com/static/simple_poly.js
// by Ben Appleton of Google
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
function supportsSVG() {
return document.implementation.hasFeature(
'http://www.w3.org/TR/SVG11/feature#Shape',
'1.1');
}
// VML utils from here http://appleton-static.appspot.com/static/simple_poly.js
// by Ben Appleton of Google
var VML_NAMESPACE = 'urn:schemas-microsoft-com:vml';
function createVmlElement(tagName, parent) {
var element = document.createElement(tagName);
parent.appendChild(element);
element.style['behavior'] = 'url(#default#VML)';
return element;
}
function supportsVML() {
if (supportsVML.result_ == null) {
if (!maybeCreateVmlNamespace()) {
return supportsVML.result_ = false;
}
// Create some VML. Its 'adj' property will be an object only when VML
// is enabled.
var div = document.createElement('DIV');
document.body.appendChild(div);
div.innerHtml = '<v:shape id="vml_flag1" adj="1" />';
var child = div.firstChild;
if (child) child.style['behavior'] = 'url(#default#VML)';
supportsVML.result_ = !child || (typeof child['adj'] == 'object');
div.parentNode.removeChild(div);
}
return supportsVML.result_;
}
function maybeCreateVmlNamespace() {
var hasVmlNamespace = false;
if (document.namespaces) {
for (var x = 0; x < document.namespaces.length; x++) {
var ns = document.namespaces(x);
if (ns.name == 'v') {
if (ns.urn == VML_NAMESPACE) {
hasVmlNamespace = true;
} else {
throw new Error('document namespace v: is required for VML ' +
'but has been reserved for ' + ns.urn);
}
}
}
if (!hasVmlNamespace) {
// Import namespace
hasVmlNamespace = true;
document.namespaces.add('v', VML_NAMESPACE);
}
}
return hasVmlNamespace;
}
Question
I can not figure out how to change the length of those arrow? Can I somehow add a length parameter to the function ArrowOverlay?
I would do something like this (scale also works with x, y):
<svg>
<g id="idG" transform="scale(1, 1)">
..your arrow
</g>
</svg>
document.getElementById("idG").setAttribute("transform", "scale(" + horizontalScale + "," + verticalScale + ")");
Example: http://k8.no-ip.org/stackoverflow/13540341.htm
I'm using Raphael.js. Everytime i load the page i get an error that reads:
con is undefined
x = con.x
I looked up con in the Raphael documentation, and this is what i found:
var con = R._getContainer.apply(0, arguments),
container = con && con.container,
x = con.x,
y = con.y,
width = con.width,
height = con.height;
//...
con is clearly defined here. Here is the code I am trying to load:
var paper = new Raphael(ele('canvas_container'), 500, 500);
window.onload = function() {
var circle = paper.circle(100,100,100);
for (i = 0; i < 5; i++) {
var multiplier = i * 5;
paper.circle(250 + (2 * multiplier), 100 + multiplier, 50 - multiplier);
}
}
Has anyone else gotten this error? Is this a bug in the version of Raphael that I have or is there some other problem?
Try moving the paper instantiation inside your window's load function:
window.onload = function() {
var paper = new Raphael(ele('canvas_container'), 500, 500);
var circle = paper.circle(100,100,100);
for (i = 0; i < 5; i++) {
var multiplier = i * 5;
paper.circle(250 + (2 * multiplier), 100 + multiplier, 50 - multiplier);
}
}
If you try to get an element by its id before the DOM is ready, getElementById won't return anything. As you can see here, trying your code on an empty document shows the same result.
Raphael.js expects there to be a hard coded HTML element on the page with the name of the Raphael canvas (ie: "canvas_container"). If the HTML element is created during run time (dynamically in your JavaScript code), it will throw this error.
R._engine.create = function () {
var con = R._getContainer.apply(0, arguments),
container = con && con.container,
x = con.x,
y = con.y,
width = con.width,
height = con.height;
if (!container) {
throw new Error("SVG container not found.");
}
var cnvs = $("svg"),
css = "overflow:hidden;",
isFloating;
x = x || 0;
y = y || 0;
width = width || 512;
height = height || 342;
$(cnvs, {
height: height,
version: 1.1,
width: width,
xmlns: "http://www.w3.org/2000/svg"
});
if (container == 1) {
cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
R._g.doc.body.appendChild(cnvs);
isFloating = 1;
} else {
cnvs.style.cssText = css + "position:relative";
if (container.firstChild) {
container.insertBefore(cnvs, container.firstChild);
} else {
container.appendChild(cnvs);
}
}
container = new R._Paper;
container.width = width;
container.height = height;
container.canvas = cnvs;
container.clear();
container._left = container._top = 0;
isFloating && (container.renderfix = function () {});
container.renderfix();
return container;
};