i got problem when trying to slowing scroll from this code :
$ionicScrollDelegate.$getByHandle('credit').scrollBottom(true).
How can i slowing down the scroll? Because now it scrolling too fast for me. I need to slowing down the scroll, just like credit scene on the Star Wars movie.
Anyhelp would be much appreciated, thanks!
$scope.viewCreditsV2 = function () {
$ionicModal.fromTemplateUrl('views/popupcredit.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
$scope.modal.show();
if ($scope.modal.isShown()){
setTimeout(function() {
// Do something after 2 seconds
$ionicScrollDelegate.$getByHandle('credit').scrollBottom(true);
}, 2000);
}
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.closeModal = function() {
// $scope.modal.hide();
$scope.modal.remove();
};
};
This question is old but somebody might use it.
Even though there are no parameters to pass options, you can still access the ScrollView object using the $ionScrollDelegate.
Following #Jeremy Wilken's answer (which helped me derive this one), you could do:
$timeout(function() {
$ionicScrollDelegate.getScrollView().options.animationDuration = 400;
console.log($ionicScrollDelegate.getScrollView().options);
});
//.....
$ionicScrollDelegate.scrollBy(0,20, true) // Animation will be slower now
I wrapped the call on a $timeout to avoid racing conditions from $ionicScrollDelegate not being created.
Ionic doesn't have a means to change the animation speed for the $ionicScrollDelegate. There is no public API to make this change.
https://github.com/driftyco/ionic/blob/master/js/views/scrollView.js#L327
You can use $anchorScroll as shown in the Angular documentation https://docs.angularjs.org/api/ng/service/$anchorScroll
Related
I have created a flexible column layout and unfortunately it does not work properly.
When I want to expand the left part, I have to click on arrow twice instead once:
I am trying to figure out, but unfortunately could not find the error.
The view of Flexible Column Layout:
<mvc:View xmlns="sap.f" xmlns:mvc="sap.ui.core.mvc" xmlns:m="sap.m" displayBlock="true" controllerName="io.example.fclpoc.controller.App"
height="100%">
<FlexibleColumnLayout id="fcl" stateChange="onStateChanged" layout="{/layout}" backgroundDesign="Solid"></FlexibleColumnLayout>
</mvc:View>
and the controller:
sap.ui.define([
"sap/ui/model/json/JSONModel",
"sap/ui/core/ResizeHandler",
"sap/ui/core/mvc/Controller",
"sap/f/FlexibleColumnLayout"
], function (JSONModel, ResizeHandler, Controller, FlexibleColumnLayout) {
"use strict";
return Controller.extend("io.example.fclpoc.controller.App", {
onInit: function () {
this.oRouter = this.getOwnerComponent().getRouter();
this.oRouter.attachRouteMatched(this.onRouteMatched, this);
this.oRouter.attachBeforeRouteMatched(this.onBeforeRouteMatched, this);
},
onBeforeRouteMatched: function (oEvent) {
var oModel = this.getOwnerComponent().getModel();
var sLayout = oEvent.getParameters().arguments.layout;
// If there is no layout parameter, query for the default level 0 layout (normally OneColumn)
if (!sLayout) {
var oNextUIState = this.getOwnerComponent().getHelper().getNextUIState(0);
sLayout = oNextUIState.layout;
}
// Update the layout of the FlexibleColumnLayout
if (sLayout) {
oModel.setProperty("/layout", sLayout);
}
},
_updateLayout: function (sLayout) {
var oModel = this.getOwnerComponent().getModel();
// If there is no layout parameter, query for the default level 0 layout (normally OneColumn)
if (!sLayout) {
var oNextUIState = this.getOwnerComponent().getHelper().getNextUIState(0);
sLayout = oNextUIState.layout;
}
// Update the layout of the FlexibleColumnLayout
if (sLayout) {
oModel.setProperty("/layout", sLayout);
}
},
onRouteMatched: function (oEvent) {
var sRouteName = oEvent.getParameter("name"),
oArguments = oEvent.getParameter("arguments");
this._updateUIElements();
// Save the current route name
this.currentRouteName = sRouteName;
},
onStateChanged: function (oEvent) {
var bIsNavigationArrow = oEvent.getParameter("isNavigationArrow"),
sLayout = oEvent.getParameter("layout");
this._updateUIElements();
// Replace the URL with the new layout if a navigation arrow was used
if (bIsNavigationArrow) {
this.oRouter.navTo(this.currentRouteName, {
layout: sLayout
}, true);
}
},
// Update the close/fullscreen buttons visibility
_updateUIElements: function () {
var oModel = this.getOwnerComponent().getModel();
var oUIState = this.getOwnerComponent().getHelper().getCurrentUIState();
oModel.setData(oUIState);
},
onExit: function () {
this.oRouter.detachRouteMatched(this.onRouteMatched, this);
this.oRouter.detachBeforeRouteMatched(this.onBeforeRouteMatched, this);
}
});
});
I looked also in the debug console:
However no errors occur. I have also compare my code with https://sapui5.hana.ondemand.com/#/entity/sap.f.FlexibleColumnLayout/sample/sap.f.sample.FlexibleColumnLayoutWithTwoColumnStart/code/webapp/controller/FlexibleColumnLayout.controller.js and could not find differences.
What am I doing wrong?
The app can be found here https://github.com/softshipper/fclpoc
Update
I have run the app in my edge browser and it does not have any extension installed. The behavior is the same.
Here is the console output of edge:
This is less a direct answer to the question "why does my app do that". It's more of a help to self-help.
Basically, if you put a break point in each of the methods in your App controller, you will see that the layout is moving in the correct position first, then it is moving back in the incorrect position (it happens so fast that you dont see without debugger).
The layout is being set several times in the whole process. sometimes changing nothing, sometimes not. In the end, one of your methods sets the wrong layout.
PS: you have a semantic error, not a syntactic one (the app does what you asked it to do), so there are no errors in the console.
I have a counter that is working perfectly fine, but it starts counting when the page is loaded - meaning that often when the user scrolls down, the counter has already stoped and therefore the effect is lost.
I've tried multiple suggestions found here on Stack Overflow, but none worked for my specific case.
Here's my code:
$('.counter').each(function() {
var $this = $(this),
countTo = $this.attr('data-count');
$({ countNum: $this.text()}).animate({
countNum: countTo
},
{
duration: 9000,
easing:'linear',
step: function() {
$this.text(Math.floor(this.countNum));
},
complete: function() {
$this.text(this.countNum);
//alert('finished');
}
});
});
Any tips I could incorporate into my code to ensure the counter starts counting only in viewport?
Many thanks in advance!
A good way to achive is using IntersectionObserver https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API to active your countdown when in viewport.
First, create an observer that will trigger when in view, and then start countdown.
const options = {
root: null,
rootMargin: '0px', //this determines when observer will trigger
threshold: 0
}
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if(entry.isIntersecting) {
observer.unobserve(entry.target)
activateCountdown(entry.target) //call you function that will activate the counter
}
})
}, options);
Now, apply this observer to all counter that exists
$('.counter').each((index, element) => {
observer.observe(element)
})
function activateCountdown(countdown) {
//here you activate your counter
}
I have a map wher we can classically switch from one style to another, streets to satellite for example.
I want to be informed that the style is loaded to then add a layer.
According to the doc, I tried to wait that the style being loaded to add a layer based on a GEOJson dataset.
That works perfectly when the page is loaded which fires map.on('load') but I get an error when I just change the style, so when adding layer from map.on('styledataloading'), and I even get memory problems in Firefox.
My code is:
mapboxgl.accessToken = 'pk.token';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v10',
center: [5,45.5],
zoom: 7
});
map.on('load', function () {
loadRegionMask();
});
map.on('styledataloading', function (styledata) {
if (map.isStyleLoaded()) {
loadRegionMask();
}
});
$('#typeMap').on('click', function switchLayer(layer) {
var layerId = layer.target.control.id;
switch (layerId) {
case 'streets':
map.setStyle('mapbox://styles/mapbox/' + layerId + '-v10');
break;
case 'satellite':
map.setStyle('mapbox://styles/mapbox/satellite-streets-v9');
break;
}
});
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'regions.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
}
function loadRegionMask() {
loadJSON(function(response) {
var geoPoints_JSON = JSON.parse(response);
map.addSource("region-boundaries", {
'type': 'geojson',
'data': geoPoints_JSON,
});
map.addLayer({
'id': 'region-fill',
'type': 'fill',
'source': "region-boundaries",
'layout': {},
'paint': {
'fill-color': '#C4633F',
'fill-opacity': 0.5
},
"filter": ["==", "$type", "Polygon"]
});
});
}
And the error is:
Uncaught Error: Style is not done loading
at t._checkLoaded (mapbox-gl.js:308)
at t.addSource (mapbox-gl.js:308)
at e.addSource (mapbox-gl.js:390)
at map.js:92 (map.addSource("region-boundaries",...)
at XMLHttpRequest.xobj.onreadystatechange (map.js:63)
Why do I get this error whereas I call loadRegionMask() after testing that the style is loaded?
1. Listen styledata event to solve your problem
You may need to listen styledata event in your project, since this is the only standard event mentioned in mapbox-gl-js documents, see https://docs.mapbox.com/mapbox-gl-js/api/#map.event:styledata.
You can use it in this way:
map.on('styledata', function() {
addLayer();
});
2. Reasons why you shouldn't use other methods mentioned above
setTimeout may work but is not a recommend way to solve the problem, and you would got unexpected result if your render work is heavy;
style.load is a private event in mapbox, as discussed in issue https://github.com/mapbox/mapbox-gl-js/issues/7579, so we shouldn't listen to it apparently;
.isStyleLoaded() works but can't be called all the time until style is full loaded, you need a listener rather than a judgement method;
Ok, this mapbox issue sucks, but I have a solution
myMap.on('styledata', () => {
const waiting = () => {
if (!myMap.isStyleLoaded()) {
setTimeout(waiting, 200);
} else {
loadMyLayers();
}
};
waiting();
});
I mix both solutions.
I was facing a similar issue and ended up with this solution:
I created a small function that would check if the style was done loading:
// Check if the Mapbox-GL style is loaded.
function checkIfMapboxStyleIsLoaded() {
if (map.isStyleLoaded()) {
return true; // When it is safe to manipulate layers
} else {
return false; // When it is not safe to manipulate layers
}
}
Then whenever I swap or otherwise modify layers in the app I use the function like this:
function swapLayer() {
var check = checkIfMapboxStyleIsLoaded();
if (!check) {
// It's not safe to manipulate layers yet, so wait 200ms and then check again
setTimeout(function() {
swapLayer();
}, 200);
return;
}
// Whew, now it's safe to manipulate layers!
the rest of the swapLayer logic goes here...
}
Use the style.load event. It will trigger once each time a new style loads.
map.on('style.load', function() {
addLayer();
});
My working example:
when I change style
map.setStyle()
I get error Uncaught Error: Style is not done loading
This solved my problem
Do not use map.on("load", loadTiles);
instead use
map.on('styledata', function() {
addLayer();
});
when you change style, map.setStyle(), you must wait for setStyle() finished, then to add other layers.
so far map.setStyle('xxx', callback) Does not allowed. To wait until callback, work around is use map.on("styledata"
map.on("load" not work, if you change map.setStyle(). you will get error: Uncaught Error: Style is not done loading
The current style event structure is broken (at least as of Mapbox GL v1.3.0). If you check map.isStyleLoaded() in the styledata event handler, it always resolves to false:
map.on('styledata', function (e) {
if (map.isStyleLoaded()){
// This never happens...
}
}
My solution is to create a new event called "style_finally_loaded" that gets fired only once, and only when the style has actually loaded:
var checking_style_status = false;
map.on('styledata', function (e) {
if (checking_style_status){
// If already checking style status, bail out
// (important because styledata event may fire multiple times)
return;
} else {
checking_style_status = true;
check_style_status();
}
});
function check_style_status() {
if (map.isStyleLoaded()) {
checking_style_status = false;
map._container.trigger('map_style_finally_loaded');
} else {
// If not yet loaded, repeat check after delay:
setTimeout(function() {check_style_status();}, 200);
return;
}
}
I had the same problem, when adding real estate markers to the map. For the first time addding the markers I wait till the map turns idle. After it was added once I save this in realEstateWasInitialLoaded and just add it afterwards without any waiting. But make sure to reset realEstateWasInitialLoaded to false when changing the base map or something similar.
checkIfRealEstateLayerCanBeAddedAndAdd() {
/* The map must exist and real estates must be ready */
if (this.map && this.realEstates) {
this.map.once('idle', () => {
if (!this.realEstateWasInitialLoaded) {
this.addRealEstatesLayer();
this.realEstateWasInitialLoaded = true
}
})
if(this.realEstateWasInitialLoaded) {
this.addRealEstatesLayer();
}
}
},
I ended up with :
map.once("idle", ()=>{ ... some function here});
In case you have a bunch of stuff you want to do , i would do something like this =>
add them to an array which looks like [{func: function, param: params}], then you have another function which does this:
executeActions(actions) {
actions.forEach((action) => {
action.func(action.params);
});
And at the end you have
this.map.once("idle", () => {
this.executeActions(actionsArray);
});
I have created simple solution. Give 1 second for mapbox to load the style after you set the style and you can draw the layer
map.setStyle(styleUrl);
setTimeout(function(){
reDrawMapSourceAndLayer(); /// your function layer
}, 1000);
when you use map.on('styledataloading') it will trigger couple of time when you changes the style
map.on('styledataloading', () => {
const waiting = () => {
if (!myMap.isStyleLoaded()) {
setTimeout(waiting, 200);
} else {
loadMyLayers();
}
};
waiting();
});
How can I increase the size of all markers when we zoom in the map?
I know we can use map.on('zoomend', function() {}); and change the icon size inside the function.But I have a lot of markers and looping through all of them and changing them individually doesn't seem like a good idea.
There is nothing wrong with looping through a set of markers on every zoomend event. Why doesn't it sound like a good idea?
An alternative to looping through markers is to extend the L.Marker class to do the work for you, something like:
L.Marker.Autoresizable = L.Marker.extend({
onAdd: {
map.on('zoomend', this._changeIcon, this);
},
onRemove: function(map) {
map.off('zoomend', this._changeIcon, this);
},
_changeIcon: function(ev) {
var zoom = this._map.getZoom();
if (zoom <= 10) {
this.setIcon(...);
} elseif (zoom > 10 && zoom <= 15) {
this.setIcon(...);
} else {
this.setIcon(...);
}
}
});
L.marker.autoresizable = function(latlng, options) {
return new L.Marker.Autoresizable(latlng, options);
}
In this case, the Leaflet code will implicitly loop through all the event listeners for the zoomend event, which is pretty much the same (performance-wise) as looping through the markers yourself.
As the title says, how to make the sap.m.ProgressIndicator not animated when changing the percent value of it?
I cannot find a method for it, and extending would probably be the way to go, but maybe somebody has already figured it out and done it?
My Google search was not successful though.
interesting question, below is the sap.m.ProgressIndication.prototype.setPercentValue function, you can see when the percent value changes the bars values is changed via an linear animation
My suggestion, the easiest way to change this behavior is to extend the control to your own control and to redefine the setPercentValue, either remove the animate function on the bar or set time to null so there is no animation
sap.m.ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
var that = this;
...
if (that.getPercentValue() != fPercentValue) {
// animation without rerendering
this.$().addClass("sapMPIAnimate");
var time = Math.abs(that.getPercentValue() - fPercentValue) * 20;
this.setProperty("percentValue", fPercentValue, true);
var $Bar = this.$("bar");
$Bar.animate({
width : fPercentValue + "%"
}, time, "linear", function() {
that._setText.apply(that);
that.$().removeClass("sapMPIAnimate");
});
}
something like
jQuery.sap.declare("my.ProgressIndicator");
jQuery.sap.require("sap.m.ProgressIndicator");
sap.m.ProgressIndicator.extend("my.ProgressIndicator", {
renderer: {}
});
my.ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
var that = this;
// validation of fPercentValue
if (typeof (fPercentValue) == "number") {
if (that.getPercentValue() != fPercentValue) {
// animation without rerendering
this.$().addClass("sapMPIAnimate");
//var time = Math.abs(that.getPercentValue() - fPercentValue) * 20;
var time = 0;
this.setProperty("percentValue", fPercentValue, true);
var $Bar = this.$("bar");
$Bar.animate({
width : fPercentValue + "%"
}, time, "linear", function() {
that._setText.apply(that);
that.$().removeClass("sapMPIAnimate");
});
}
return this;
};
There is no convenient method to suppress this behavior.
You can only extend the control and overwrite the method setPercentValue to you desired behavior.
As of UI5 1.73, the animation on percantageValue-change can be turned off by setting the property displayAnimation to false.
Determines whether a percentage change is displayed with animation.
Since: 1.73.
<ProgressIndicator displayAnimation="false" />