Using an example I found on this thread https://gis.stackexchange.com/questions/198896/mapbox-gljs-group-layers/198920#198920?newreg=120a87a082494e41b2e6ab240c94b266 I have grouped multiple layers together and created a single toggle button to turn on and off visibility.
However, the buttons need to be clicked twice to trigger the function. Is it possible to have them only clicked once for the function to work?
Here is my codepen example https://codepen.io/charlie-enright/pen/BarRgbo
//whatever layers you want to toggle go in to this function
toggleLayer(['site location markers'], 'markers');
toggleLayer(['Pen Dinas', 'Rudbaxton','Brawdy Castle', 'Caer Blaen Minog', 'Castell Bach', 'Castell Gwyn', 'Tancredston', 'Thornton Rath', 'Walesland Rath'], 'Geophys');
toggleLayer(['Pendinas 50cm DSM'], '50cm DSM');
toggleLayer(['Pendinas 50cm DTM'], '50cm DTM');
function toggleLayer(ids, name) {
var link = document.createElement('a');
link.href = '#';
link.className = 'active';
link.textContent = name;
link.onclick = function (e) {
e.preventDefault();
e.stopPropagation();
for (layers in ids){
var visibility = map.getLayoutProperty(ids[layers], 'visibility');
if (visibility === 'visible') {
map.setLayoutProperty(ids[layers], 'visibility', 'none');
this.className = '';
} else {
this.className = 'active';
map.setLayoutProperty(ids[layers], 'visibility', 'visible');
}
}
};
var layers = document.getElementById('menu');
layers.appendChild(link);
}
I'm not exactly sure why, but the first time you check the visibility of the layer var visibility = map.getLayoutProperty(ids[layers], 'visibility');, visibility is undefined.
If you check for this in the if statement below, it will toggle on the first click:
if (visibility === 'visible' || visibility === undefined) {
// ^^ if 'visible' or undefined, set visibility to 'none'
...
}
Related
Can anybody tell me which fullcalendar event callback should I use
To handle the case where : the current external event stopped dragging
and it's localised not over the external events Box neither over The Calendar?
knowing that I have both methods isEventOverDiv
//return true/false if we are (not) over the external events and isEventOverDivCal//return true/false if we are (not) over the calendar
I tried in eventDragStop: function (event, jsEvent, ui, view)
eventDragStop: function (event, jsEvent, ui, view){
// if the event is not over the external events box and neither over the calendar
if(!isEventOverDiv(jsEvent.clientX, jsEvent.clientY) && !isEventOverDivCal(jsEvent.clientX, jsEvent.clientY) ) {
// reset
var reccupuredIndexForTitle=$(this).attr('id');
$scope.ctrlendDragging(reccupuredIndexForTitle);
}
}
//return true if we are over the external events
var isEventOverDiv = function (x, y) {
var external_events = $('#external-events');
var offset = external_events.offset();
offset.right = external_events.width() + offset.left;
offset.bottom = external_events.height() + offset.top;
// Compare
if (x >= offset.left &&
y >= offset.top &&
x <= offset.right &&
y <= offset.bottom) {return true;}
return false;
};
//return true if we are over the calendar
var isEventOverDivCal = function(x, y) {
var external_events = $( '#calendar' );
var offset = external_events.offset();
offset.right = external_events.width() + offset.left;
offset.bottom = external_events.height() + offset.top;
// Compare
if (x >= offset.left
&& y >= offset.top
&& x <= offset.right
&& y <= offset .bottom) { return true;}
return false;
}
but it's not working.
update 2
in order to overcome the obstacle of putting events above the virtual scroll bar during their trip into the calendar
1- I apply from mycontroller $scope.ctrlstartDragging
(which triggers from the HTML view on ondragstart="angular.element(this).scope().ctrlstartDragging(id)" callback).
$scope.ctrlstartDragging = function(id) {
var book = document.getElementById(id);
var domRect = absolutePosition(book);
book.style.position = 'fixed';
book.style.top = domRect.top + 'px';
book.style.left = domRect.left + 'px';
book.style.width=(domRect.width) + 'px';
};
and to be able to unset css styles (position top left width)
(N.B: ondragend="angular.element(this).scope().ctrlendDragging(id)" callback)
is not fired and I don't know why but it's not a problematic in my case)
so the purpose is that I should call manually
$scope.ctrlendDragging = function(id) {
var book = document.getElementById(id);
book.style.position = 'relative';
book.style.top = 'unset';
book.style.left = 'unset';
book.style.width='unset';
};
and to do as I said, in case the user aborts to put the event on the calendar during the dragging and this event is positioned both outside the external event box and outside the calendar.
but in my case see MyPlunk I need when the revert is applied , I will need during the revert of this event to the external event box to do make a call to it with the folloiwing
// reset
var reccupuredIndexForTitle=$(this).attr('id');
$scope.ctrlendDragging(reccupuredIndexForTitle);
so I need when the revert is applied I sould apply those two lines
because if they are not applied when an user abort a dragging into the calendar
the event revert but without the unset css styles applied to .style.position top left width
I would get an one isolated external event on the top of the external events box like shown below:
Many thanks.
added the following to my controller:
var x =-1;
var y=-1;
$('#external-events').on('dragstop', function(evt)
{
isDragging = false;
x = evt.originalEvent.pageX;
y = evt.originalEvent.pageY;
if(!isDragging && x !=-1 && y!=-1 && !isEventOverDiv(x, y) && !isEventOverDivCal(x, y) )
{
// reset
var reccupuredIndexForTitle=$('.fc-event').attr('id');
$scope.ctrlendDragging(reccupuredIndexForTitle);
}
});
As you can see from the code, I used jquery on('dragstop') because I don't know why
on ondragend event is not fired
so I removed it from my view HTML ondragend="angular.element(this).scope().ctrlendDragging(id)"
and called manualy from my controller $scope.ctrlendDragging(id) to reset the current dragged event when stoped via $('#external-events').on('dragstop', function(evt)
and handled the case the current external event stopped dragging and it's localised not over the external events Box neither over The Calendar
via
if(!isDragging && x !=-1 && y!=-1 && !isEventOverDiv(x, y) && !isEventOverDivCal(x, y) )
Working codePen
update2:
Because The first solution is basic and work in hazardous conditions
It works only for the first draggable li
and it's not exact nor precise. I made an update to the following:
var domRect;
var isDragging = false;
var x =-1;
var y=-1;
$scope.positionX =-1;
$scope.positionY=-1;
var myId=-1;
$(document).ready(function() {
$scope.ctrlstartDragging = function(id) {
myId = id;
};
$scope.ctrlendDragging = function(id) {
book.style.zIndex = "9999";
};
$('#external-events').on('dragstop', function(evt)
{
$scope.$watchGroup(['positionX','positionY'],function () {
x = $scope.positionX;
y = $scope.positionY;
});
if(!isDragging && x !=-1 && y!=-1 && !isEventOverDiv(x, y) && !isEventOverDivCal(x, y) ) {
// reset
var reccupuredIndexForTitle=myId;
$scope.ctrlendDragging(reccupuredIndexForTitle);
}
});
});//end of $(document).ready(function()
Enclosed in $(document).ready(function() {
all functions that shoul be appplied in document ready:
1- $scope.ctrlstartDragging from which we get myId equal (current li) id passed
via html view ondragstart="angular.element(this).scope().ctrlstartDragging(id)"
2- $scope.ctrlendDragging n.b : I set the z-index via
book.style.zIndex = "9999"; so we could work in a modal context
3- $('#external-events').on('dragstop', function(evt) that should work in
$(document).ready(function() { or $window.load
where added a watchgroup on changes made on positionX positionY of an li
$scope.$watchGroup(['positionX','positionY'],function () {
x = $scope.positionX;
y = $scope.positionY;
});
also added
if(!isDragging && x !=-1 && y!=-1 && !isEventOverDiv(x, y) && !isEventOverDivCal(x, y) ) {
// reset
var reccupuredIndexForTitle=myId;
$scope.ctrlendDragging(reccupuredIndexForTitle);
}
which work with myId this time gotten from $scope.ctrlstartDragging
On the other Hand, I added when initialising external events
$('#external-events .fc-event').each(function() {
drag: function(){ to get the exact positionX positionY for the current dragged li element
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0, // original position after the drag
drag: function(){
var offset = $(this).offset();
var xPos = offset.left;
var yPos = offset.top;
$scope.$apply(function() {
$scope.positionX =xPos;
$scope.positionY = yPos;
});
}
});
Working codePen for li
Hope it may help somebody ;).
I'm looking for hours for a solutions but can't find anything that works for me.. I am trying to create a button which will wrap a specific text with span which works fine.
Now i am trying to make it a toggle so i will be able to unwrap the span from the text but can't get it done..
Basically the button needs to work the same as the Italic button but i couldn't find its code anywhere in my files..
How can i determine if i'm on my requested node so i can deactivate?
How can i make it work as toggle as i mentioned above?
Here is my code-
ed.addButton ('remark', {
title : 'Remark Text',
image: url + '../../images/remark-icon.png',
onClick : function() {
var state = true;
ed.focus();
ed.controlManager.setActive('remark', state);
var text = ed.selection.getContent({format : 'text'});
var selected_elem = ed.selection.getNode(); // Get selected element
var elem_type = ed.selection.getNode().nodeName; // Get element type
selected_elem = jQuery(selected_elem ).attr('class'); // Get element's class
if( elem_type !== 'SPAN') {
ed.selection.setContent('<span class="remark-text">' + text + '</span>');
}
ed.on('NodeChange', function(e) {
state = true;
ed.controlManager.setActive('remark', state);
});
}
});
Thanks for any help!
ed.addButton ('remark', {
title : 'Remark Text',
image: url + '../../images/remark-icon.png',
onClick : function() {
var state = true;
ed.focus();
ed.controlManager.setActive('remark', state);
var text = ed.selection.getContent({format : 'text'});
var selected_elem = ed.selection.getNode(); // Get selected element
var elem_type = ed.selection.getNode().nodeName; // Get element type
selected_elem = jQuery(selected_elem); // Get element's class
console.log(selected_elem);
if( elem_type !== 'SPAN') {
ed.selection.setContent('<span class="remark-text">' + text + '</span>');
}
ed.on('NodeChange', function(e) {
elem_type = ed.selection.getNode().nodeName;
if( elem_type == 'SPAN' && selected_elem.find("span").hasClass("remark-text") ) {
state = true;
ed.controlManager.setActive('remark', state);
}
else {
state = false;
ed.controlManager.setActive('remark', state);
}
});
}
});
I'm trying to do something simple: using keys to move a character on the screen with Meteor
I got it working using a Collection to store the character's position, but the keyup event is only working inside of a form/input
I'd like to capture the client keypress everywhere.
Template.main.events({
'keyup': function(evt, tmpl){
evt.preventDefault();
// Move up
if(evt.keyCode === 38){
console.log('Moving up');
}
);
This code only works when the focus in on an input :/
Add events to Template.body the reference
Template.body.events({
'keyup': function(evt, tmpl){
evt.preventDefault();
// Move up
if(evt.keyCode === 38){
console.log('Moving up');
}
);
Or to $(window):
var keyupFunc = function(evt){
if(evt.keyCode === 38){
console.log('Moving up');
}
}
Template.main.created = function(){
$(window).on("keyup", keyupFunc);
}
Template.main.destroyed = function(){
$(window).off("keyup", keyupFunc);
}
I can set css properties on an element in a directive. But I cannot retrieve css properties on an element using the same method, it just returns an empty string.
i.e: var test = element.css("background-size"); //does not work!
What am I doing wrong? See my link handler in my directive below:
link: function($scope, element, attrs) {
//debugger;
//handler for close button:
//its the first child within the parent element:
$scope.closeBtn = angular.element(element.children()[0]);
//save the background image so we can toggle its visibility:
$scope.backgroundImg = element.css("background","url(../../a0DK0000003XvBYMA0/assets/images/tabbed_panel_bkgd.png) no-repeat") ;//className:
element.css("background-position","0px 35px");
element.css("background-size", "924px 580px");
//above I was able to set css properties, but why can't I retrieve css properties like this??:
var test = element.css("background-size");
$scope.closeBtn.bind('click',function(){
TweenLite.to(element, .75, {top:"635px",ease:Power2.easeOut,
onComplete:function(){
$scope.opened = false;
$scope.closeBtn.css('opacity',0);
} });
})
//hander to raise tab panel:
element.bind('click', function() {
if(!$scope.opened){
//debugger;
$scope.closeBtn.css('opacity',1);
TweenLite.to(element, .75, {top:"150px",ease:Power2.easeOut});
$scope.opened = true;
}
});
}
I took a step back from my question and realized if I am trying to retrieve css properties like used to do with JQuery then I am probably not applying a solution in the "angular way". My original problem is that I needed to store css properties so I coule re apply them later. So instead of that approach, I used the ng-class directive to toggle the classes so I would not have to store anything.
<html>
<body>
<tabbed-Panel ng-class="btmTabPanelClass" >
<div ng-show="opened" class="tabPanelCloseBtn"> </div>
<tabs>
<pane ng-repeat="pane in panes" heading="{{pane.title}}" active="pane.active">
<div class ="tabPanelContent" ng-include src="activeContent()"></div>
</pane>
</tabs>
</tabbed-Panel>
</div
</body>
</html>
angular.module('directives', ['baseModule','ui.bootstrap'])
.directive('tabbedPanel',['$animator',function($animator) {
//debugger;
return {
//scope:{},
restrict:"E",
//add controller to here
controller:function($scope){
//debugger;
$scope.bTabClicked = 0;
$scope.curTabIdx = 0;
$scope.opened = false;
$scope.closeBtn = null;
$scope.arClasses = ["bottomTabPanel", " bp_off"];
$scope.btmTabPanelClass = $scope.arClasses[0] + $scope.arClasses[1] ;
//get the tabs from the flows.json so we can create a model for the tab panel!
$scope.panes = $scope.flows[$scope.getCurFlowIdx()].array_data[$scope.getCurPageIdx()].tab_data;
//first tab is active by default:
//$scope.panes[0].active = true;
//set the content for the current tab:
$scope.activeContent = function() {
for (var i=0;i<$scope.panes.length;i++) {
if ($scope.panes[i].active) {
$scope.curTabIdx = i;
return $scope.panes[i].content;
}
}
};
//tab click watcher (to make sure user clicks on tab and not tab container):
$scope.$watch('activeContent()', function(paneIndex) {
++$scope.bTabClicked;
});
//--------------------------------------------------
},
link: function($scope, element, attrs) {
//debugger;
//handler for close button:
//its the first child within the parent element:
$scope.closeBtn = angular.element(element.children()[0]);
$scope.closeBtn.bind('click',function(){
// set all tabs to inactive:
$scope.bTabClicked = 0;
for (var i=0;i<$scope.panes.length;i++)
$scope.panes[i].active = false;
TweenLite.to(element, .75, {top:"635px",ease:Power2.easeOut,
onComplete:function(){
$scope.opened = false;
$scope.btmTabPanelClass = $scope.arClasses[0] + $scope.arClasses[1] ;
$scope.$apply(); //force binding to update
$scope.bTabClicked = 0;
} });
})
/*hander to raise tab panel:*/
element.bind('click', function() {
if(!$scope.opened && $scope.bTabClicked){
//debugger;
TweenLite.to(element, .75, {top:"150px",ease:Power2.easeOut});
$scope.opened = true;
$scope.btmTabPanelClass = $scope.arClasses[0] ;
$scope.$apply(); //force binding to update
}
else
$scope.bTabClicked = 0;
});
}
};
}]);
You can access the CSS style of an Angular element in a directive's link function by
var style = window.getComputedStyle(element[0]),
And then access the value of any CSS rule like such:
var color = style.getPropertyValue('color');
I want to capture the event of a user pressing enter on an input of type="text" when they are filling out a form. This is done all over the web, yet the answer eludes me.
This is what I have so far:
In the html file, I have a text input like so:
<input type="text" size=50 class="newlink">
In the Javascript file, I am trying to capture the the user pressing enter to effectively submit the form. I am then grabbing the text from the input and going to stash it in the database:
Template.newLink.events = {
'submit input.newLink': function () {
var url = template.find(".newLink").value;
// add to database
}
};
The submit event is emitted from forms, not single input elements.
The built in event map for meteor is documented here: http://docs.meteor.com/#eventmaps.
You'll have to listen for a keyboard event (keydown, keypress, keyup). Within the event handler, check, if it's the return/enter key (Keycode 13), and proceed on success.
Template.newLink.events = {
'keypress input.newLink': function (evt, template) {
if (evt.which === 13) {
var url = template.find(".newLink").value;
// add to database
}
}
};
You could look into how this is achieved in the todos example (client/todos.js).
It uses a generic event handler for input fields (as seen below). You can browse the rest of the code for usage.
////////// Helpers for in-place editing //////////
// Returns an event map that handles the "escape" and "return" keys and
// "blur" events on a text input (given by selector) and interprets them
// as "ok" or "cancel".
var okCancelEvents = function (selector, callbacks) {
var ok = callbacks.ok || function () {};
var cancel = callbacks.cancel || function () {};
var events = {};
events['keyup '+selector+', keydown '+selector+', focusout '+selector] =
function (evt) {
if (evt.type === "keydown" && evt.which === 27) {
// escape = cancel
cancel.call(this, evt);
} else if (evt.type === "keyup" && evt.which === 13 ||
evt.type === "focusout") {
// blur/return/enter = ok/submit if non-empty
var value = String(evt.target.value || "");
if (value)
ok.call(this, value, evt);
else
cancel.call(this, evt);
}
};
return events;
};
I used this js function once to suppress the user using the return key in the text field to submit the form data. Perhaps you could modify it to suit the capture?
function stopRKey(evt) { // Stop return key functioning in text field.
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) { return false; }
}
document.onkeypress = stopRKey;
You can also use event.currentTarget.value
Template.newLink.events = {
'keypress input.newLink': function (evt) {
if (evt.which === 13) {
var url = event.currentTarget.value;
// add to database
}
}
};