openlayers pan zoom bar modification - javascript

i am new at openlayers and i want to learn how can i add pan zoom bar like http://maps.cloudmade.com/ zoombar. it shows some tag as building , country etc. when you on this pan...

You can override OpenLayers.Control.PanZoom, for example:
idecan.PanZoom = OpenLayers.Class(OpenLayers.Control.PanZoom, {
bounds: null,
initialize: function(options) {
this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
OpenLayers.Control.PanZoom.Y);
if (arguments[0].bounds)
this.bounds = arguments[0].bounds;
OpenLayers.Control.prototype.initialize.apply(this, arguments);
},
includeButtons: {
"zoomin": {
outImageSrc: "zoom-plus-mini.png",
overImageSrc: "zoom-plus-mini-over.png"
},
"zoomout": {
outImageSrc: "zoom-minus-mini.png",
overImageSrc: "zoom-minus-mini-over.png"
},
"zoomworld": {
outImageSrc: "zoom-world-mini.png",
overImageSrc: "zoom-world-mini-over.png"
}
},
makeMouseCallback: function(id, state) {
var selector = state + "ImageSrc";
var src = OpenLayers.Util.getImagesLocation() + this.includeButtons[id][selector];
return function(evt) {
var img = this.firstChild;
if (img.src != src) {
img.src = src;
}
};
},
_addButton: function(id, img, xy, sz) {
if (id in this.includeButtons) {
var src = this.includeButtons[id].outImageSrc;
var size = new OpenLayers.Size(18,18);
var btn = OpenLayers.Control.PanZoom.prototype._addButton.call(this, id, src, xy, size);
if (this.bounds) {
var bounds = this.bounds;
var getBounds = function() {
return bounds;
};
btn.getBounds = getBounds;
}
btn.className = this.displayClass + id.capitalize();
btn._btnId = id;
OpenLayers.Event.observe(btn, "mouseover", OpenLayers.Function.bindAsEventListener(this.makeMouseCallback(id, "over"), btn));
OpenLayers.Event.observe(btn, "mouseout", OpenLayers.Function.bindAsEventListener(this.makeMouseCallback(id, "out"), btn));
return btn;
}
},
buttonDown: function (evt) {
if (!OpenLayers.Event.isLeftClick(evt)) {
return;
}
switch (this.action) {
case "panup":
this.map.pan(0, -this.getSlideFactor("h"));
break;
case "pandown":
this.map.pan(0, this.getSlideFactor("h"));
break;
case "panleft":
this.map.pan(-this.getSlideFactor("w"), 0);
break;
case "panright":
this.map.pan(this.getSlideFactor("w"), 0);
break;
case "zoomin":
this.map.zoomIn();
break;
case "zoomout":
this.map.zoomOut();
break;
case "zoomworld":
if (map.center)
map.setCenter(idecan.center, idecan.zoom);
//this.map.zoomToExtent(this.getBounds());
else
this.map.zoomToMaxExtent();
break;
}
OpenLayers.Event.stop(evt);
},
CLASS_NAME: "idecan.PanZoom"
});

I'm also currently implementing a customized derivate of OpenLayer's PanZoom control. Unfortunately, the PanZoom control contains a lot of cruft code, many lines are just devoted to some hard-coded control styling that could be done much easier in CSS (e.g. why must every control button be 18x18 pixels?)
Felix' answer is a good starting point, but if you don't need to implement your PanZoom control super urgent, I'd wait until OpenLayers 2.11 or some newer version is out. The OpenLayers devs are currently refactoring many of the hard coded formatting to CSS, making the control code slimmer and more easy to understand.

Related

Phaser 3: Clone Sprite on click & drag immediately

I have a sprite that works as a button, but as you press it, it duplicates and lets you drag the duplicate. I've almost got it to work, however currently you have to click first to create a duplicate and are only able to drag after a second click. I'd like to be able to click once and immediately be able to drag.
It is important that the DUPLICATE gets dragged, as opposed to the original, since the original has all the click-functions.
create() {
sprite = scene.add.sprite(0,0, "clean", "showerhead_0000");
sprite.setInteractive({ useHandCursor: true });
sprite.on('pointerdown', () => {
dragTool(scene, options[idx], sprite);
});
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.destroy();
gameState.clean_cursor = false;
});
}
function dragTool(scene, option, sprite){
let activePointer = scene.input.activePointer;
let clone = scene.add.sprite(sprite.x,sprite.y, sprite.texture.key, sprite.frame.name);
gameState.clean_cursor = clone;
gameState.clean_cursor.setInteractive();
scene.input.setDraggable(gameState.clean_cursor);
}
Maybe I'm missing something, but a simple solutionwould be.
create two images/buttons, one normal and one as placeholder
the placeholder will be cover by the original, except when it is dragged
on drag, just drag the normal button
on the end of dragging reset the position of the normal button
this should work the same, and it is no so complicated.
Here a working example:
let Example = {
preload () {
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
},
create () {
let buttonPos = { x:0, y:0};
let buttonPlaceholder = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0, 0);
let button = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0, 0);
this.isDragging = false;
button.setInteractive({ useHandCursor: true });
this.input.setDraggable(button);
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.x = buttonPos.x;
gameObject.y = buttonPos.y;
});
}
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: [ Example ]
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
...this should be even more performant, than creating and destroying image/buttons...

How to add an event handler function to a prototype in javascript?

Thanks to all who helped me out earlier tonight with my little project.
I am attempting to re-write a simple procedural program I wrote a few weeks ago using OOP javascript. The program is a reaction tester that presents a random shape to the user and measures how quickly the user clicks the shape and presents the speed. Earlier I finally managed to actually get a randomly sized and colored square to appear on the page. Now I am trying to write an event handler function that will set the css display property to none when the shape is clicked so that the shape disappears. However, the event handler function doesn't work and I have tried it a few different ways so far. See my entire code below:
function Shape () {
this.x = Math.floor(Math.random()*1200);
this.y = Math.floor(Math.random()*500);
this.draw();
}
Shape.prototype.draw = function() {
var shapeHtml = '<div id="shape-div"></div>';
var widthAndHeight = Math.floor(Math.random()*400);
this.shapeElement = $(shapeHtml);
this.shapeElement.css({
'width': widthAndHeight,
'height': widthAndHeight,
position: "relative",
left: this.x,
top: this.y
});
this.shapeElement.css({
display: "block"
});
//Just below is where I am trying to create a function to make the shape disappear when clicked
this.shapeElement.click(function() {
this.shapeElement.css("display", "none");
});
$("body").append(this.shapeElement);
}
"use strict";
Shape.prototype.colour = function() {
var colours = '0123456789ABCDEF'.split('');
var randomColour = "#";
for (i = 0; i < 6; i++) {
randomColour+=colours[Math.floor(Math.random()*16)];
};
this.shapeElement.css({backgroundColor: randomColour});
}
$(document).ready(function() {
var square = new Shape();
square.draw();
square.colour();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This just won't work. I am making the transition to OOP and finding it really difficult to do things that were a cinch using procedural programming. Is this typical? Thanks again for the help.
You could try replasing:
this.shapeElement.click(function() {...
for
this.shapeElement.on("click",function() {...
You are adding this element to the DOM after it loads.
Also, check your console, because inside the event listener this.shapeElement.css("display", "none"); probably gives you an error, this in that context is the element calling the event... I believe you could use:
$(this).css({"display": "none"});
Whenever you use function(){, the inside of that function acquires a new calling context (a new this) depending on how it was called. But in your handler, you don't want a new this value - you want to inherit the this of the instantiated Shape. You can use an arrow function instead, or you can remember that this on a handler references the clicked element:
function Shape () {
this.x = Math.floor(Math.random()*1200);
this.y = Math.floor(Math.random()*500);
this.draw();
}
Shape.prototype.draw = function() {
var shapeHtml = '<div id="shape-div"></div>';
var widthAndHeight = Math.floor(Math.random()*400);
this.shapeElement = $(shapeHtml);
this.shapeElement.css({
'width': widthAndHeight,
'height': widthAndHeight,
position: "relative",
left: this.x,
top: this.y
});
this.shapeElement.css({
display: "block"
});
//Just below is where I am trying to create a function to make the shape disappear when clicked
this.shapeElement.click(function() {
$(this).css("display", "none");
});
$("body").append(this.shapeElement);
}
"use strict";
Shape.prototype.colour = function() {
var colours = '0123456789ABCDEF'.split('');
var randomColour = "#";
for (i = 0; i < 6; i++) {
randomColour+=colours[Math.floor(Math.random()*16)];
};
this.shapeElement.css({backgroundColor: randomColour});
}
$(document).ready(function() {
var square = new Shape();
square.draw();
square.colour();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to build Image Editor using HTML5 and Raphael JS?

I am building a web application and for this I am building a basic Image Editor using HTML5 and Raphael js. I have implemented some features like:
Resize Flip horizontal and/or vertical Drag
Some more features I need to implement are :
Crop Undo/Redo Changing background colour and opacity.
I am mainly looking for crop and undo functionality. Can anyone help me to achieve this using RaphaelJs and HTML5?
My Code:
var r, c, d;
var paper = Raphael("editor", 600,450);
var canvas = document.getElementById('editor');
canvas.style.backgroundColor='gray';
$scope.current;
var someFunction = function(e) {
e.data('dragged', false);
e.drag(dragmove, dragstart, dragend);
for(var i in elements) {
var thisShape = elements[i];
var ft = paper.freeTransform(thisShape,{draw:['bbox']});
ft.hideHandles();
thisShape.click(function(){
paper.forEach(function(el) {
if(el.freeTransform.handles.bbox != null)
el.freeTransform.hideHandles();
});
this.freeTransform.showHandles();
});
}
};
function dragmove(dx, dy, x, y, e) {
this.transform(this.current_transform+'T'+dx+','+dy);
}
function dragstart(x, y, e) {
this.current_transform = this.transform();
}
function dragend(e) {
this.current_transform = this.transform();
};
var elements = [];
$scope.raph = function () {
c= paper.circle(40,40,40).click(function() {
someFunction(this);
$scope.current= this;
});
r = paper.rect(50, 60, 100,100,25).click(function() {
someFunction(this);
$scope.current= this;
});
d = paper.rect(70, 60, 100,100,25).click(function() {
someFunction(this);
$scope.current= this;
});
elements.push(c,r,d);
c.attr({
fill:'red',
cursor:'pointer'
});
r.attr({
fill:'green',
cursor:'pointer'
});
d.attr({
fill:'blue',
cursor:'pointer'
});
};
$scope.back = function () {
$scope.current.toBack();
}
$scope.front = function () {
$scope.current.toFront();
}
$scope.clear = function () {
paper.clear();
};
$scope.flips = function () {
$scope.current.rotate(180);
};
//function for cloning element
$scope.clones = function () {
var n = $scope.current.clone();
n.attr("x",$scope.current.attr("x")+100);
$scope.current = n;
elements.push(n);
n.click(function() {
someFunction(this);
});
};
$scope.changing= function (e) {
$scope.opacity=event.target.value;
if($scope.current != null){
$scope.current.attr({
opacity:$scope.opacity
})
}
}
UPDATE: just use Fabric.js http://fabricjs.com/kitchensink/, although you'll probably need to add Darkroom http://mattketmo.github.io/darkroomjs/ for cropping.
Some suggestions for RaphaelJS:
resize: http://raphaeljs.com/reference.html#Element.transform c.transform('S1.5,1.5')
flip: resize with a negative scale in either direction (S-1,1)
drag: http://raphaeljs.com/reference.html#Element.drag, also consider set overloads like http://wesleytodd.com/2013/4/drag-n-drop-in-raphael-js.html
changing colors and stuff: http://raphaeljs.com/reference.html#Element.attr
undo -- you'll have to save a list of operations/previous states to reverse?
crop -- most likely you'd create the UI in raphael using a mask/overlay (layers: http://raphaeljs.com/reference.html#Element.toBack) to send instructions to a server-side API to handle the heavy work. You can manipulate raster images in the browser, but if people are uploading photos it could quickly overload the memory limitations (think: unedited 12MP photo)
Check out stuff like Sketchpad http://ianli.com/sketchpad/ or the commented Darkroom http://mattketmo.github.io/darkroomjs/ for ideas.
You can always try exploring the sourcecode for existing web editors, like Google+... (that was mostly a joke).

Multiple instances of InfoVis RGraph visualisations

I am developing an application that has multiple tabs (using jQuery UI). These can be opened and closed by the user. Within each tab is an rGraph visualisation from the JavaScript InfoVis Toolkit (http://philogb.github.io/jit/static/v20/Jit/Examples/RGraph/example1.html). (The code for both the tabs and the visualisations are very similar to the examples on their respective websites)
Whenever I create a new tab, the rGraph is generated correctly. This seems to scale quite nicely and I can click back and forth through multiple tabs without any problems. However, if I interact with an rGraph in any way (e.g. by clicking on a node to move it around), the existing rGraphs in the other tabs stop working. When I click on any of the existing rGraphs, it produces the error: TypeError: node is undefined. In other words, new instances work fine but clicking on the newest one breaks the previous ones.
Is there anything that can be done about this?
Note: There does appear to be some allowance for multiple instances in the docs - you can create each instance with a different variable name, e.g. var graph1 = new ... var graph2 = new ... etc. This does indeed work, but as the tabs (and therefore the graphs) are dynamically generated, I cannot assign specific variable names like this. I tried doing the following:
var graphs = {};
graphs[unique_id_i_pass_in] = new Graph();
...but this didn't seem to make any difference.
EDIT: Here is the code I am using to call the rGraphs (document_id is the unique variable I am passing in for each graph):
var doc_rgraph = {};
//init RGraph
doc_rgraph[document_id] = new $jit.RGraph({
//Where to append the visualization
injectInto: 'document_vis_'+document_id,
//Optional: create a background canvas that plots
//concentric circles.
background: {
CanvasStyles: {
//Colour of the background circles
strokeStyle: '#C5BE94'
}
},
//Add navigation capabilities:
//zooming by scrolling and panning.
Navigation: {
enable: true,
panning: true,
zooming: 10
},
//Set Node and Edge styles.
Node: {
//Colour of the actual nodes
color: '#660000'
},
Edge: {
//Color of lines between nodes
color: '#660000',
lineWidth:1.5
},
onBeforeCompute: function(node){
Log.write("Centering " + node.name + "...");
},
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
domElement.onclick = function(){
doc_rgraph[document_id].onClick(node.id, {
onComplete: function() {
Log.write("Done");
}
});
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
style.cursor = 'pointer';
if (node._depth == 0) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#000000";
style.backgroundColor = "#F05322";
style.padding = "1px 3px";
} else if (node._depth == 1) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#FFFFFF";
style.backgroundColor = "#164557";
style.padding = "1px 3px";
} else if(node._depth == 2){
style.fontSize = "0.7em";
//Text colour of ring 2 nodes
style.color = "#333333";
style.backgroundColor = "#CAC399";
} else {
style.display = 'none';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + 'px';
},
onComplete: function(){
Log.write("Done");
}
});
//load JSON data
doc_rgraph[document_id].loadJSON(document_data[document_id]);
//trigger small animation
doc_rgraph[document_id].graph.eachNode(function(n) {
var pos = n.getPos();
pos.setc(-200, -200);
});
doc_rgraph[document_id].compute('end');
doc_rgraph[document_id].fx.animate({
modes:['polar'],
duration: 1000
});
//end

spritesheet animation

I'm trying to get a script to run but I'm having a little trouble. I've only used javascript once before, but now i have to make a character animation walk back and forth on a web page and continue until the page is closed. My debugger says there is a reference error on line 57, but i'm sure thats not the only problem. If anyone could take a look at the code and see if anything pops out at them, I would be grateful.
goog.provide('mysprites');
goog.require('lime');
goog.require('lime.Director');
goog.require('lime.Layer');
goog.require('lime.Sprite');
goog.require('lime.fill.Frame');
goog.require('lime.animation.KeyframeAnimation');
goog.require('lime.animation.MoveBy');
goog.require('lime.SpriteSheet');
goog.require('lime.animation.MoveTo');
goog.require('lime.animation.Sequence');
goog.require('lime.animation.Loop');
goog.require('lime.animation.Delay');
goog.require('lime.parser.JSON');
goog.require('lime.ASSETS.spaceman.json');
mysprites.WIDTH = 600;
mysprites.HEIGHT = 400;
mysprites.start = function() {
//director
mysprites.director = new lime.Director(document.body, mysprites.WIDTH, mysprites.HEIGHT);
mysprites.director.makeMobileWebAppCapable();
var gamescene = new lime.Scene;
layer = new lime.Layer();
gamescene.appendChild(layer);
// load the spritesheet
mysprites.ss = new lime.SpriteSheet('assets/spaceman.png',lime.ASSETS.spaceman.json,lime.parser.JSON);
var sprite = mysprites.makeMonster().setPosition(100,100);
layer.appendChild(sprite);
//move
var moveRight = new lime.animation.MoveTo(874, 100)
.setSpeed(1)
.setEasing(lime.animation.Easing.LINEAR);
var moveLeft = new lime.animation.MoveTo(100, 100)
.setSpeed(1)
.setEasing(lime.animation.Easing.LINEAR);
// show animation
var anim = new lime.animation.KeyframeAnimation();
anim.delay= 1/10;
for(var i=0;i<=9;i++){
anim.addFrame(mysprites.ss.getFrame('spaceman-'+'w'+'0'+i+'.png'));
}
monster.runAction(anim);
var anim2 = new lime.animation.KeyframeAnimation();
anim.delay= 1/10;
for(var i=0;i<=9;i++){
anim.addFrame(mysprites.ss.getFrame('spaceman-'+'e'+'0'+i+'.png'));
}
monster.runAction(anim2);
goog.events.listen(moveRight,lime.animation.Event.STOP, function () {
setTimeout(function () {
monster.runAction(moveLeft);
}, 500);
});
goog.events.listen(moveLeft,lime.animation.Event.STOP, function () {
setTimeout(function () {
monster.runAction(moveRight);
}, 500);
});
};
mysprites.makeMonster = function(){
var sprite = new lime.Sprite().setPosition(200,200)
.setFill(mysprites.ss.getFrame('spaceman-s00.png'));
//layer.appendChild(sprite);
return sprite;
};
goog.exportSymbol('mysprites.start', mysprites.start);
I think you'd better to ask your question here https://groups.google.com/forum/#!forum/limejs
Please check the following things:
If all the spritesheet items referenced in KeyframeAnimation are present in your spritesheet
Try to use setDelay, setLooping API methods instead of direct assignment
I do not see monster variable definition...

Categories