How to hide and show features in OpenLayers 3? (Redraw?) - javascript

I'm updating a project from OL2 to OL3, but I'm stuck on how to redraw features after changing the feature style.
In OL2, this worked:
hidePoints: function(id) {
if (! this.getMap().center) {
return;
}
var i,
feature,
len = this.points.features.length;
if (id !== null) {
for( i = 0; i < len; i++ ) {
feature = this.points.features[i];
if (feature.attributes.aces_id == id) {
feature.style = null;
} else {
feature.style = { display: 'none' };
}
}
} else {
for( i = 0; i < len; i++ ) {
feature = this.points.features[i];
feature.style = { display: 'none' };
}
}
this.points.redraw();
},
In OL3, I tried updating the function to hide the points layer, but redraw() no longer exists and since the layer I am working with is an ol.layer.Vector, I can't find any updateParams options like other sources besides vectors have. Dispatch Event and changed also did not work. I was hoping changed would, but nothing happens.
hidePoints: function(id) {
if (! this.getMap().getView().getCenter()) {
return;
}
var i,
feature,
layerSourceFeatures = this.pointsLayer.getSource().getFeatures(),
len = layerSourceFeatures.length;
if (id !== null) {
for( i = 0; i < len; i++ ) {
feature = this.pointsLayer.getSource().getFeatures()[i];
if (feature.get('aces_id') == id) {
feature.style = null;
} else {
feature.style = { display: 'none' };
}
}
} else {
for( i = 0; i < len; i++ ) {
feature = this.pointsLayer.getSource().getFeatures()[i];
feature.style = { display: 'none' };
}
}
//this.pointsLayer.redraw();
//this.pointsLayer.dispatchEvent(goog.events.EventType.CHANGE);
this.pointsLayer.changed();
},
I'm also wondering if changing the style is done this way (fetching each feature to another var) or if that won't just change that feature and leave the original untouched. Plus always fetching getSource().getFeatures() seems abusive on the performance... but I can't seem to find another way.
Regardless, how is redraw performed in OL3 now to render features whose styles have been altered? A layer can be set as visible, but I don't want to hide/show all the features all the time. Sometimes I just want to hide/show a few according to their given id.

Another way to do it is using a style function and a hidden propertie on the feature:
var style = new ol.Style(...);
function Stylefunction (feature, resolution) {
var prop = feature.getProperties();
if (prop.HIDDEN)
return;
return style;
}
var layer = new ol.layer.Vector({
source: new ol.source.Vector(...),
style: Stylefunction
});
if you change the feature "HIDDEN" propertie, it instant refreshes

So while looking at the documentation over and over, I finally found what would fire the change event, much like seto suggested after.
This is the converted function from OL2 to OL3 that works for me. Redraw is no longer needed since setStyle does it all.
hidePoints: function(id) {
if (! this.getMap().getView().getCenter()) {
return;
}
var i,
feature,
layerSourceFeatures = this.pointsLayer.getSource().getFeatures(),
len = layerSourceFeatures.length;
var emptyImgStyle = new ol.style.Style({ image: '' });
// If an aces id was provided
if (id !== undefined) {
for( i = 0; i < len; i++ ) {
feature = layerSourceFeatures[i];
feature.setStyle(emptyImgStyle);
// Resetting feature style back to default function given in defaultPointStyleFunction()
if (feature.get('aces_id') == id) {
feature.setStyle(null);
}
// Hiding marker by removing its associated image
else {
feature.setStyle(emptyImgStyle);
}
}
}
// No id was provided - all points are hidden
else {
for( i = 0; i < len; i++ ) {
feature = layerSourceFeatures[i];
feature.setStyle(emptyImgStyle);
}
}
},

I can't add comments because I don't have enough reputation, but instead of feature.style = null you might want to call feature.setStyle(null), because this internally triggers the changed event and should instantaneously and automatically change the style. Also feature.style = { display: 'none' } will not work in openlayers 3 because the style needs to be an ol.style.Style object (http://openlayers.org/en/v3.14.2/apidoc/ol.Feature.html#setStyle)
If you have the ID of the features, you can use the source.getFeatureById() method instead of cycling through the features.(http://openlayers.org/en/v3.14.2/apidoc/ol.source.Vector.html#getFeatureById)
Regards rendering, I think using the map's map.render() (at openlayers.org/en/v3.14.2/apidoc/ol.Map.html#render) will re-render the map.
If you just to call a function whenever the map is re-rendered, you can listen on the postrender or postcompose events on the map.
If you create a JSFiddle, I can help you further.
Edit: This example might help you - openlayers.org/en/v3.14.2/examples/dynamic-data.html?q=style

I like this approach for layer toggling (applies to other features, as well):
JAVASCRIPT
<script>
var layerBing = new ol.layer.Tile({
source: new ol.source.BingMaps({
imagerySet: 'Aerial',
key: 'YourKeyBingAccess'
}),
name: 'Bing'
});
/*
* YOUR MAP CODE GOES HERE
*/
function toggleLayer(layerObject) {
var newVisibility = !(layerObject.get('visible'));
layerObject.set('visible', newVisibility);
}
</script>
HTML
<button onclick="toggleLayer(layerBing)">Bing Satellite</button>
<div id="map" class="map"></div>

Related

how to get the marker coordinates from geoObjectCollection Yandex.Map

There is a collection of objects displayed on the map. There is an event on the click of the label. How to determine the coordinates of the label that was clicked?
.get('coords) will not work, you need to get exactly the coordinates prescribed in the collection, but how can I not understand, I tried .getCoordinates(), but I did not understand how to prescribe correctly, or do something else here...
var myGeoObject = new ymaps.GeoObjectCollection(
{
preset: 'islands#blueIcon'
});
for (var i = 0; i < coords.length; i++) {
myGeoObject.add(new ymaps.Placemark(coords[i]));
}
myMap.geoObjects.add(myGeoObject);
myGeoObject.events.add('click', function (e) {
});
myGeoObject.events.add('click', function (e) {
var click_coord = e.get('target').geometry.getCoordinates();
});

Get Href Link; if JPG to skip

I've created a loader for my website (the whole front end is custom,so as of right now i can edit about 95% of everything I have except for woocommerce plugin).
Super simple one, it follows this logic, if the anchor is an # or the page itself it wont do anything (which is what I wanted) but the woocommerce plugin to generate my image gallery is a link that isn't the page itself or a #. Which means I need to collect the path-name of the extension that if it ends on jpg png or any image file to continue; and skip over the rest of the animation and allow the plugin to run its course.
Ive use Barba JS, SWUP and other animations with woocommerce and this is the only one that doesnt interrupt or have so many conditions with woocommerce.
function fadeInPage() {
if (!window.AnimationEvent) { return; }
var fader = document.getElementById('fader');
fader.classList.add('fade-out');
}
document.addEventListener('DOMContentLoaded', function() {
if (!window.AnimationEvent) { return }
var anchors = document.getElementsByTagName('a');
******* for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].hostname !== window.location.hostname || anchors[idx].pathname === window.location.pathname) *******
{
continue;
}
anchors[idx].addEventListener('click', function(event) {
var fader = document.getElementById('fader'),
anchor = event.currentTarget;
var listener = function() {
window.location = anchor.href;
fader.removeEventListener('animationend', listener);
};
fader.addEventListener('animationend', listener);
event.preventDefault();
fader.classList.add('fade-in');
});
}
});
window.addEventListener('pageshow', function (event) {
if (!event.persisted) {
return;
}
var fader = document.getElementById('fader');
fader.classList.remove('fade-in');
});
I starred what i need changed. the animation works, the page transition works. I need the animation to recognize if the a tag ends with an jpg or png to skip and not do the animation and treat the link as if the animation wasn't there.
Never used woocommerce so I don't totally understand the use case, but you can get the file extension of a link like so:
for (var idx = 0; idx < anchors.length; idx += 1) {
let fileType = anchors[idx].href.split('.').pop();
//Do whatever
}
Or if you want to compare it to a preset list of extensions you can use a regex:
for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].href.match(/\.(jpg|png)$/)) {
//Do whatever
}
}

codemirror - detect and create links inside editor

I am using codemirror, configured to display javascript.
I have code like this:
...
var ref = 'http://www.example.com/test.html';
var ref2 = 'http://www.example.com/test2.html';
...
When displaying the editor it would be great if I could click on the links that might be present in the editor. The link would open the page on a different tab obviously.
is there an easy way to achieve this ?
Not really easy, but what you'd do is:
Write an overlay mode that recognizes such links. Basically, this is a mode that spits out a custom token type when it finds something that looks like a link, and null otherwise. You can use the simple mode addon to make this easier. You can use this token type's CSS class (for example "link" becomes cm-link) to style your links.
Make your editor use your overlay by calling the addOverlay method.
Register a mousedown event handler on your editor (instance.getWrapperElement().addEventListener(...)).
In this handler, check whether the event's target has the link CSS class. If it does, the user is clicking a link.
If so, use the coordsChar method, using the coordinates from your mouse event, to find the position in the document that was clicked. Extract the actual link from the document text around that position, and follow it.
(Or, even better, instead of directly interfering with the click, which might be intended to put the cursor in the link or select it, show a widget containing a regular link whenever the cursor is inside of link text.)
Here is a solution I came up with:
demo here: plunkr
code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css"/>
<style>
html, body { height:100%; }
.CodeMirror .cm-url { color: blue; }
</style>
</head>
<body>
<script>
var cm = CodeMirror(document.body);
cm.setValue('hover over the links below\nlink1 https://plnkr.co/edit/5m31E14HUEhSXrXtOkNJ some text\nlink2 google.com\n');
hyperlinkOverlay(cm);
function hoverWidgetOnOverlay(cm, overlayClass, widget) {
cm.addWidget({line:0, ch:0}, widget, true);
widget.style.position = 'fixed';
widget.style.zIndex=100000;
widget.style.top=widget.style.left='-1000px'; // hide it
widget.dataset.token=null;
cm.getWrapperElement().addEventListener('mousemove', e => {
let onToken=e.target.classList.contains("cm-"+overlayClass), onWidget=(e.target===widget || widget.contains(e.target));
if (onToken && e.target.innerText!==widget.dataset.token) { // entered token, show widget
var rect = e.target.getBoundingClientRect();
widget.style.left=rect.left+'px';
widget.style.top=rect.bottom+'px';
//let charCoords=cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY }));
//widget.style.left=(e.pageX-5)+'px';
//widget.style.top=(cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY })).bottom-1)+'px';
widget.dataset.token=e.target.innerText;
if (typeof widget.onShown==='function') widget.onShown();
} else if ((e.target===widget || widget.contains(e.target))) { // entered widget, call widget.onEntered
if (widget.dataset.entered==='true' && typeof widget.onEntered==='function') widget.onEntered();
widget.dataset.entered='true';
} else if (!onToken && widget.style.left!=='-1000px') { // we stepped outside
widget.style.top=widget.style.left='-1000px'; // hide it
delete widget.dataset.token;
widget.dataset.entered='false';
if (typeof widget.onHidden==='function') widget.onHidden();
}
return true;
});
}
function hyperlinkOverlay(cm) {
if (!cm) return;
const rx_word = "\" "; // Define what separates a word
function isUrl(s) {
if (!isUrl.rx_url) {
// taken from https://gist.github.com/dperini/729294
isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
// valid prefixes
isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.'];
// taken from https://w3techs.com/technologies/overview/top_level_domain/all
isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi'];
}
if (!isUrl.rx_url.test(s)) return false;
for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true;
for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true;
return false;
}
cm.addOverlay({
token: function(stream) {
let ch = stream.peek();
let word = "";
if (rx_word.includes(ch) || ch==='\uE000' || ch==='\uE001') {
stream.next();
return null;
}
while ((ch = stream.peek()) && !rx_word.includes(ch)) {
word += ch;
stream.next();
}
if (isUrl(word)) return "url"; // CSS class: cm-url
}},
{ opaque : true } // opaque will remove any spelling overlay etc
);
let widget=document.createElement('button');
widget.innerHTML='→'
widget.onclick=function(e) {
if (!widget.dataset.token) return;
let link=widget.dataset.token;
if (!(new RegExp('^(?:(?:https?|ftp):\/\/)', 'i')).test(link)) link="http:\/\/"+link;
window.open(link, '_blank');
return true;
};
hoverWidgetOnOverlay(cm, 'url', widget);
}
</script>
</body>
</html>
Here is a starting point, but it need to be improved.
LIVE DEMO
function makeHyperLink(innerTextInside)
{
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
if(all[i].innerText == innerTextInside)
{
all[i].innerHTML="<a target='_blank' href='https://google.com'>THIS IS A LINK TO GOOGLE</a>"
}
}
}

Javascript modification of CSS class url change for background image

I am trying to get a background image to change based on a setting in the database, for right now I'm just trying to get a a way of simply modifying the image used without using the data base but I'm hitting a snag. Without the javascript the image appears fine, with the javascript it is simply not there; leading me to believe there is an issue finding the path written to the css.
Thanks in advance for any help!
<script type="text/javascript" language="javascript">
function changecss(myclass, element) {
var CSSRules
var link1 = "url('../../graphics/MainMenuBG0.gif')";
var link2 = "url('../../graphics/MainMenuBG1.gif')";
if (document.all) {
CSSRules = 'rules';
}
else if (document.getElementById) {
CSSRules = 'cssRules';
}
for (var i = 0; i < document.styleSheets[0][CSSRules].length; i++) {
if (document.styleSheets[0][CSSRules][i].selectorText == myclass) {
if (document.styleSheets[0][CSSRules][i].style[element] == link1) {
document.styleSheets[0][CSSRules][i].style[element] = link2;
} else {
document.styleSheets[0][CSSRules][i].style[element] = link1;
}
}
}
}
</script>
You should try something like this :
if (document.styleSheets[0][CSSRules][i].style.getProperty('background-image') == link1) {
document.styleSheets[0][CSSRules][i].style.setProperty('background-image', link2);
} else {
document.styleSheets[0][CSSRules][i].style.setProperty('background-image', link1);
}

One Marker Animation At A time Google Maps Api 3

I'm working on a Map app and I'm having trouble getting marker animated at a time. I'd like to have it so that when a new marker is clicked, the other's animation is removed. I'm a js noob and have been wracking my head. As of now, I have the markers in an array so that I can remove the animation ..but how can I remove the animation of every other marker when setting the animation for another one?..below is the code I've been playing with
for (i in markersArray) {
if (markersArray[i].getAnimation() != null) {
markersArray[i].setAnimation(null);
}
if (marker[i].getAnimation() != null) {
marker[i].setAnimation(null);
} else {
marker[i].setAnimation(google.maps.Animation.BOUNCE);
}
}
The code that you posted seems fine and if it works for you, great. However, if you only want one marker animated at a time, then it might be more efficient, and easier, to just keep a variable of the last animated marker. For example, in your click event or when you add a marker, you could do something like this:
previous_animation.setAnimation(null);
new_marker.setAnimation(google.maps.Animation.BOUNCE);
previous_animation = new_marker;
I ended up coming up with the following code after assigning a unique id to each marker...worked like a charm
for( var i in marker ){
marker[i].setAnimation(null);
if( marker[i].id == item.id ) marker[i].setAnimation(google.maps.Animation.BOUNCE);
}
var new_marker = this;
if(prev_marker) {
if (prev_marker.getAnimation() != null) {
prev_marker.setAnimation(null);
new_marker.setAnimation(google.maps.Animation.BOUNCE);
prev_marker = new_marker;
}
} else {
new_marker.setAnimation(google.maps.Animation.BOUNCE);
prev_marker = new_marker;
}
i prefer #Nick Canzoneri style. Modified it a bit
This is what that i got working, I have my markers in a global variable. Which keeps my markers accessible at all time.
google.maps.event.addListener(marker, 'click', function(event) {
$("input#pickup-"+ marker.id +"").prop('checked', true);
for (var i = window.markers.length - 1; i >= 0; i--) {
window.markers[i].setAnimation();
if(window.markers[i].id === this.id) {
marker.setAnimation(google.maps.Animation.BOUNCE);
}
};
})

Categories

Resources