Currently having a problem trying to get YUI Tooltips to display on top of a YUI Panel after it is shown that were previously created. The problem is is that the Panel cannot be registered to the overlay manager because it would require a TON of code to be changed and tested extending a hard deadline. The only way to get this to work is to setup the Tooltips after the Panel is shown. Problem there is the amount of code changes that would have to be done to attach another function call. My problem is that I was hoping that I could use the event handling to use "showEvent" but I cannot seem to get it to work (I apologize for word count):
var panel_obj = new YAHOO.widget.Panel('someID', {
width: "700px",
height: "500px",
close: true,
draggable: false,
modal: true,
constraintoviewport: true,
visible: false,
fixedcenter: true
});
panel_obj.render();
var tooltip_name = 'newTooltip1';
var element_id = 'htmlElementIDToBecomeTooltip';
function createTooltip() {
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltip_name, {
context: element_id,
xyoffset: [15, -15],
zIndex: 999
});
}
function successfulScenario() {
panel_obj.show();
createTooltip();
}
function failedScenario1() {
YAHOO.util.Event.addListener(
'someID',
"showEvent",
createTooltip
);
}
function failedScenario2() {
createTooltip();
panel_obj.show();
}
The only way I have seem to get it working is by running something like successfulScenario(). I'm coming from a jQuery background so I'm still learning YUI. I would love to be able to just extend (subclass) YAHOO.widget.Panel's show() function to call createTooltip but I'm not that much of a guru or I would probably need to change a very large codebase to do it.
try using the "container" property for the tooltip config (so the container would be the panel's element):
function createTooltip() {
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltip_name, {
container: panel_obj.element,
context: element_id,
xyoffset: [15, -15]
});
}
This is the quick solution, using the show event and/or extending the class would be nice but gotta run, if you still need help, I'll check back (also check the example that i made with your code http://jsfiddle.net/3GWaM/2/ ).
function createTooltip() {
var tooltipEl = document.createElement('DIV');
panel_obj.get('element').appendChild(tooltipEl);
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltipEl, {
context: element_id,
xyoffset: [15, -15],
zIndex: 999
});
}
This will ensure the that the tool tip div is created inside the dialog box, instead of in the document body, ensuring it does not appear below the dialog box.
Also, if you want to extend the panel class just do the following
function MyPanel(el, config) {
MyPanel.superclass.constructor.apply(this, arguments);
this.createToolTip();
}
YAHOO.lang.extend(MyPanel, YAHOO.widget.Panel , {
createToolTip: function () {
// create tool tip here
this.on('show', this.showTooltip, this, true);
},
showToolTip: function () {this.toolTip.show();}
});
function getPanelIDFromElementID (element_id) {
var parent_panel = YAHOO.util.Dom.getAncestorByClassName(element_id, 'yui-panel');
var parent_id = null;
if (parent_panel) {
parent_id = parent_panel.id;
}
return parent_id;
}
function createTooltips() {
var tooltip_elements = YAHOO.util.Dom.getElementsByClassName('tooltip');
for (var i = 0; i < tooltip_elements.length; i++) {
var ele_id = tooltip_elements[i].getAttribute('id');
var name = ele_id.charAt(0).toLowerCase() + ele_id.slice(1);
var nameArray = name.split("_");
for (var x=1; x < nameArray.length; x++) {
nameArray[x] = nameArray[x].charAt(0).toUpperCase() + nameArray[x].slice(1);
}
var elementName = nameArray.join('');
window[elementName] = new YAHOO.widget.Tooltip(elementName, {
context: escape(ele_id),
xyoffset: [15, -15],
zIndex: 999,
container: getPanelIDFromElementID(ele_id)
});
}
}
Related
I have a simple block its element is dynamically added to DOM, I want the user to be able to create a block and it should be draggable using jsplumb library.
Unfortunately, now I can create element but their not draggable but if I add them manually to the dom, it's draggable.
Here is what I have so far
function addMovieButton() {
var newMovieBlockButton = $("<div class='movie-button w'>Button New<div class='ep' action='begin'></div><div>");
}
Here is plumb.js
jsPlumb.ready(function () {
// setup some defaults for jsPlumb.
var instance = jsPlumb.getInstance({
Endpoint: ["Dot", {radius: 5}],
Connector:"StateMachine",
HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 },
ConnectionOverlays: [
[ "Arrow", {
location: 1,
id: "arrow",
length: 14,
foldback: 0.8
} ],
[ "Label", { label: "FOO", id: "label", cssClass: "aLabel" }]
],
Container: "canvas"
});
instance.registerConnectionType("basic", { anchor:"Continuous", connector:"StateMachine" });
window.jsp = instance;
var canvas = document.getElementById("canvas");
var windows = jsPlumb.getSelector(".statemachine-demo .w");
var windows_movie = jsPlumb.getSelector(".statemachine-demo .movie-block ");
// bind a click listener to each connection; the connection is deleted. you could of course
// just do this: jsPlumb.bind("click", jsPlumb.detach), but I wanted to make it clear what was
// happening.
instance.bind("click", function (c) {
instance.deleteConnection(c);
});
// bind a connection listener. note that the parameter passed to this function contains more than
// just the new connection - see the documentation for a full list of what is included in 'info'.
// this listener sets the connection's internal
// id as the label overlay's text.
instance.bind("connection", function (info) {
info.connection.getOverlay("label").setLabel(info.connection.id);
});
// bind a double click listener to "canvas"; add new node when this occurs.
jsPlumb.on(canvas, "dblclick", function(e) {
// newNode(e.offsetX, e.offsetY);
});
//
// initialise element as connection targets and source.
//
var initNode = function(el) {
// initialise draggable elements.
instance.draggable(el);
instance.makeSource(el, {
filter: ".ep",
anchor: "Continuous",
connectorStyle: { stroke: "#5c96bc", strokeWidth: 2, outlineStroke: "transparent", outlineWidth: 4 },
connectionType:"basic",
extract:{
"action":"the-action"
},
maxConnections: 6,
onMaxConnections: function (info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
}
});
instance.makeTarget(el, {
dropOptions: { hoverClass: "dragHover" },
anchor: "Continuous",
allowLoopback: true
});
// this is not part of the core demo functionality; it is a means for the Toolkit edition's wrapped
// version of this demo to find out about new nodes being added.
//
instance.fire("jsPlumbDemoNodeAdded", el);
};
// suspend drawing and initialise.
instance.batch(function () {
for (var i = 0; i < windows.length; i++) {
initNode(windows[i], true);
console.log(windows[i]);
}
for (var j = 0; j < windows_movie.length; j++) {
initNode(windows_movie[j], true);
console.log(windows_movie[j]);
}
});
jsPlumb.fire("jsPlumbDemoLoaded", instance);
});
Here is live demo live demo
Here is plunker full source code
On the demo above just right click to add movie block for testing
Why does draggable not working for dynamically created elements?
here is a sample page I made a while ago when I first discovered 'jsplumb', it does exactly what you want so you might wanna use it or build on top of it.
Remember, indeed you should call the draggable method after the elements are added to the DOM, my example is so simple:
it doesn't need the jsplumb.fire
it doesn't need the .ready binding
it doesn't need the 'batch' processing offered by jsplumb
so you get to avoid problems like the scope of ready and other I'm still trying to master.
As part of my practice with phaser, I'm trying to create a basic clicker game. However, I can not get the button to display the image I wanted.
Here's my main gameplay.js:
class Gameplay extends Phaser.State {
init()
{
var btnUp = this.game.add.sprite(0, 0, 'btn_beerUp');
var btnDn = this.game.add.sprite(0, 0, 'btn_beerDn');
this.clickButton = this.game.add.button(this.game.world.centerX - 100, this.game.world.centerY + 230, 'game', this.pauseGame, this, btnUp.key, btnUp.key, btnDn.key);
this.clickButton.anchor.set(0.5, 0.5);
}
And here's my preloader.js (where ideally, all images are loaded):
class Preload extends Phaser.State {
create() {
this.game.load.image('btn_beerDn', 'res/img/btn_beerClickerDn.png');
this.game.load.image('btn_beerUp', 'res/img/btn_beerClickerUp.png');
}
It doesn't work as expected. The game simply adds the btnUp and btnDn as images in the scene, and does nothing for the button.
I've also tried the following:
this.clickButton = this.game.add.button(blah-blah, 'btn_beerUp', 'btn_beerUp', 'btn_beerDn');
this.clickButton = this.game.add.button(blah-blah, 'res/img/btn_beerClickerUp.png', 'res/img/btn_beerClickerUp.png', 'res/img/btn_beerClickerDn.png');
But none of them work - the button still displays a button with an "x".
The samples online mostly deal with atlas sheets from what I can look up. While I will eventually progress to using an atlas sheet for buttons, it seems silly that I can't get simply using a png working.
Any suggestions?
Per the documentation, if you're not going to pass in a frame or frame name you'll have to use loadTexture instead.
If you look at the Action On Click example you'll see how you add actions for each of the button states.
In your case you'll want to change this line:
this.clickButton = this.game.add.button(this.game.world.centerX - 100, this.game.world.centerY + 230, 'game'
, this.pauseGame, this, btnUp.key, btnUp.key, btnDn.key);
To something like the following:
this.clickButton = this.game.add.button(this.game.world.centerX - 100, this.game.world.centerY + 230, 'game'
, this.pauseGame, this);
this.clickButton.onInputOut.add(this.out, this);
// TODO add your other input events.
out: function () {
this.clickButton.loadTexture(btnUp.key);
}
// TODO add functions for your other input events.
Full working example:
var mainState = {
preload: function() {
// Load the three sprites that they can choose between.
this.load.crossOrigin = 'anonymous';
this.load.image('ball', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-blue.png');
this.load.image('ball2', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-green.png');
this.load.image('ball3', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-red.png');
},
create: function() {
// This won't work, since the passed items aren't valid frameNames.
//this.clickButton = this.game.add.button(this.game.world.centerX, this.game.world.centerY, 'ball', this.buttonClick, this, 'ball2', 'ball', 'ball3', 'ball');
// This follows what the documentation states, if you're not using a spritesheet.
this.clickButton = this.game.add.button(this.game.world.centerX, this.game.world.centerY, 'ball', this.buttonClick, this);
this.clickButton.onInputOver.add(this.buttonOver, this);
this.clickButton.onInputOut.add(this.buttonOut, this);
this.clickButton.onInputDown.add(this.buttonDown, this);
this.clickButton.onInputUp.add(this.buttonUp, this);
this.clickButton.anchor.setTo(0.5);
},
update: function() {
},
buttonClick: function() {
alert('clicked');
},
buttonOver: function() {
this.clickButton.loadTexture('ball2');
},
buttonOut: function() {
this.clickButton.loadTexture('ball');
},
buttonDown: function() {
this.clickButton.loadTexture('ball3');
},
buttonUp: function() {
this.clickButton.loadTexture('ball');
}
};
var game = new Phaser.Game(200, 200);
game.state.add('main', mainState);
game.state.start('main');
<script src="https://cdn.jsdelivr.net/npm/phaser-ce#2.7.10"></script>
Also saved as a JSFiddle.
I'm going crazy here trying o work out why the scoping of my variable won't pick up the right value from a loop of 60 items from a DB in my Appcelerator project.
My map marker displays the correct label, but when I click it, no matter what combo of scoping I try, I cannot get the correct value in the alert. It just returns the 60th entry every time.
Likely a schoolboy error, but this is driving me nuts.
This is my function
function loadAnimals() {
var db = Ti.Database.open('myDB');
var getSpecies = db.execute('select * from species');
while (getSpecies.isValidRow()) {
var speciesID = getSpecies.fieldByName('speciesnid');
var speciesName = getSpecies.fieldByName('speciesname');
var speciesDesc = getSpecies.fieldByName('speciesdescription');
var speciesLatitude = getSpecies.fieldByName('specieslatitude');
var speciesLongitude = getSpecies.fieldByName('specieslongitude');
var speciesConStatus = getSpecies.fieldByName('speciesconservationstatus');
var speciesMarkerFilename = getSpecies.fieldByName('speciesiconfilename');
var speciesMarkerIcon = getSpecies.fieldByName('speciesmapicon');
var speciesMarkerURI = getSpecies.fieldByName('speciesmapiconurl');
var speciesImageFullPath = speciesMarkerURI.replace("public://", "http://myurl.com/");
var speciesImageFullPath = speciesImageFullPath.replace(" ", "%20");
var imageFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerIcon);
var iconFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerFilename);
var annotationView = Ti.UI.createView({
backgroundColor: '#222222',
width: 150,
height: 75,
layout:'vertical'
});
var addtoTourView = Ti.UI.createView({
height:20,
backgroundColor:'#6ea108'
});
var addtoTourTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'ADD TO TOUR',
width: 150,
height: 15,
top:3,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'bold'
}
});
var annotationTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'test',
width: 150,
height:15,
top:0,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'normal'
}
});
var blankView = Ti.UI.createView({
backgroundColor: '#222222',
width: 1,
height: 73,
borderRadius: 0
});
annotationView.add(addtoTourView);
addtoTourView.add(addtoTourTitle);
annotationView.add(annotationTitle);
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID,
rightView: annotationView,
leftView: blankView
}));
addtoTourView.addEventListener('click', function(e) {
//alert(speciesName + ' has dded to Tour');
var dialog = Ti.UI.createAlertDialog({
message: 'Added to your Tour',
ok: 'Continue',
title: speciesName //this is the 60th entry, not the correct one
});
dialog.show();
// do the insert into the DB
var db = Ti.Database.open('myDB');
db.execute('INSERT INTO tour (speciesnid) VALUES (?)', speciesID); // same with this ID, needs to the correct ID
db.close();
});
annotationTitle.text = speciesName;
//load up the next record
getSpecies.next();
};
// close the database
getSpecies.close();
// add markers to map
mapview.annotations = annotations;
};// end of loadAnimals fucntion
Can anyone suggest what I'm doing wrong?
Michaels solution sounds right.
Let me post what I was gonna say anyway. I focus on explaining the scope problem, on why your code doesn't do what you expected.
In javascript the scope is bound to the function. When you declare a variable within a loop (for/while/do...) things can get a little confusing. You are not creating new variables, you are just overriding the value of the first (and only) variable with that name.
So, you have 1 variable in function loadAnimals, called speciesName. In the while-loop you just override the value of that variable. After the 60'th iteration, the variable just remembers the last thing you set it to.
When the client clicks on the marker, the loop is finished, the value has been set a long time ago.
Notice: there are probably solutions provided by your map service, but I don't know about that.
1 solution: 'this'.
The 'this' variable tells you what has been affected. Inside a onClick callback, this is the element that was clicked on.
The solution to your problem will probably involve 'this'. But I'm not sure exactly how.
Here an example of what I mean.
<h2>Click on the animal</h2>
<p>dog</p>
<p>cat</p>
<p>hamster</p>
<script>
function loadAnimals() {
var speciesName = '';
var animalElements = document.getElementsByTagName('p');
for (var i=0; i<animalElements.length; i++) {
speciesName = animalElements[i].innerHTML ; // notice, this variable will be overridden, so this variable is useless within the onClick callback.
animalElements[i].addEventListener('click', function(e) {
// variable 'this' is the <p> that was clicked on.
var value_clicked_on = this.innerHTML;
alert(value_clicked_on);
});
}
}
window.onload = loadAnimals;
</script>
When creating your annotations array to add to to the map add your title to the annotation paramters as well as the speciesID which you are setting with the key - myid.
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID, // We'll be querying this
myname: speciesName, // and also this
rightView: annotationView,
leftView: blankView
}));
Then add your event listener once onto the map object instead of each individual annotation object. This manages memory more efficiently and is the correct way to add it. Don't add the event listener on for every annotation, this is bad practise.
// Handle click events on any annotations on this map.
mapview.addEventListener('click', function(evt) {
Ti.API.info("speciesID " + evt.annotation.myid + " clicked, speciesName: " + evt.annotation.myname);
});
On this single event listener you can now create your alert dialog and DB insert by accessing each annotations individual properties by inspecting
evt.annotation
On the Map object you can do the following as well:
The click event includes a value which you can interrogate clicksource
This clicksource will let you know the source - pin, annotation, leftButton, rightButton, leftView, rightView, title, or subtitle which you can use in the event listener.
Also available is the source object that fired the event - source. You can then test if the clicksource is not null and the source is coming from the "ADD TO TOUR" element that you want to place the trigger on. still getting all your annotation properties from evt.annotation
Though I have successfully colored the bars of google chart individually but not able to keep them when we hover mouse over it. It is getting reset back to blue(which is default).
Here is the jsfiddle of what I have done jsfiddle.
I tried to control the hover behaviour with multiple ways like below.
This I am keeping outside (document.ready) but inside script tag.
1)
$('#chart_div').hover(
function() {
$('#chart_client').hide(); // chart_client is another google chart div.
}, function() { // just for testing I was doing hide/show of that.
$('#chart_client').show();
}
);
2)
$("#chart_div").on({
mouseenter: function () {
$('#chart_client').hide();
},
mouseleave:function () {
$('#chart_client').show();
}
},'rect');
3)
google.visualization.events.addListener('#chart_div', 'ready', function () {
$('#chart_div rect').mouseover(function (e) {
alert('hello');
});
});
I must be doing something wrong, could you please tell me what and where.
I solved it using below code. Earlier I was trying to create charts using dynamically adding rows into chart(please visit my jsfiddle) but with this below approach I am first preparing data(converting dynamic to static) and adding that static data in to chart's 'arrayToDataTable' method.
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawUserKeywordChart);
function drawUserKeywordChart() {
var val = 'Tax:47;Finance:95;Awards:126;Bank:137;Debt:145;';
var length = val.length;
var array = [];
//preparing data
while(length>0){
var sepAt = val.indexOf(";");
var value = parseInt(val.substring(val.indexOf(":")+1, sepAt));
array.push(val.substring(0, val.indexOf(":")));
array.push(value);
val = val.substring(val.indexOf(";")+1, length);
length = val.length;
}
var data = google.visualization.arrayToDataTable([
['Keyword', 'Occurences', { role: 'style' }],
[array[0], array[1], '#8AA3B3'],
[array[2], array[3], '#A9B089'],
[array[4], array[5], '#848C49'],
[array[6], array[7], '#44464A'],
[array[8], array[9], '#704610'],
]);
var options = {
title: 'Keyword Matches',
width: 660,
height: 450,
titleTextStyle:{bold:true,fontSize:20},
legend:{position:'none'}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_keyword1'));
chart.draw(data, options);
}
Please advice if you find anything wrong here or you have better approach than this.
I'm implementing an OpenLayers SelectFeature control, and trying to position an JQuery UI dialog widget right on top of the selected feature. To use the JQuery UI Position utility, it requires either a DOM element or an Event.
The onSelect callback of the SelectFeature control gives me an OpenLayers.Feature.Vector object representing the selected feature. From this, how do I get either the DOM element of the selected feature, or the Event object of the click event?
var selectControl = new OpenLayers.Control.SelectFeature(clientsLayer, {
hover : false,
clickout: false,
multiple: false,
onSelect: function(feature) {
// how do I get the DOM element of the feature
// or alternately, the click event of the selection?
}
});
You are doing it right.
If you do a console.log(feature) You'll see that it returns an object with CLASS_NAME =
"OpenLayers.Feature.Vector"
onSelect: function(feature) {
console.log(feature);
}
Update:
I see.
You could add event listeners
var selectControl = new OpenLayers.Control.SelectFeature(clientsLayer, {
hover: false,
clickout: false,
multiple: false,
eventListeners: {
featurehighlighted: function (event) {
console.log(event);
console.log(event.feature);
}
}
});
Is it something like this you look for ?
onSelect: function onFeatureSelect(event) {
var feature = event.feature;
if ( feature.layer.name == 'theone') {
...
}
}
Note I have also posted this answer at How do I get the DOM element from openlayers vector feature
If you want to find the position of the mouse or feature on hover so you can display a custom overlay, create a custom hover control and define the featurehighlighted function as follows:
var featureHoverControl = new OpenLayers.Control.SelectFeature([myLayer], {
id: 'featureHoverControl',
hover: true,
autoActivate: true,
highlightOnly: true,
renderIntent: "temporary",
eventListeners: {
featurehighlighted: function(e) {
// either use the mouse's position when the event was triggered
var mouseXPosition = this.handlers.feature.evt.x;
var mouseYPosition = this.handlers.feature.evt.y;
// or retrieve the feature's center point
var featureCenterLonLat = e.feature.geometry.bounds.getCenterLonLat();
var featureCenterPoint = map.getPixelFromLonLat(featureCenterLonLat);
// display your custom popup here
// e.g. showTooltip(e.feature.attributes.name, featureCenterPoint.x, featureCenterPoint.y)
}
,
featureunhighlighted: function(e) {
// hide your custom popup here
// e.g. hideTooltip()
}
}
});
map.addControl(featureHoverControl);
If you require access to the SVG element representing your layer/feature (in the event you are using a third-party library and you don't feel like modifying the source code), use either of the following lines (depending if you require the layer or feature):
var layerElement = map.getLayersByName("My Layer")[0].features.root;
var layerElementId = map.getLayersByName("My Layer")[0].features.root.id;
var featureElementId = map.getLayersByName("My Layer")[0].getFeaturesByAttribute("name","My Feature Name")[0].geometry.components[0].id;
Note that since this only grabs the element's id, you'll still need to use an appropriate method to grab a reference to the element itself. Something like either of the following:
var elementReference1 = document.getElementById(featureElementId);
var elementReference2 = jQuery('#'+featureElementId)[0];