When zooming, circle gets 'dragged' from original position - angularjs

I'm using mapbox.js and map.css to create a map with a simple circle drawn on it, and nothing else. (working jsfiddle) On the example that I did without angular, the zoom works as it should (meaning, it stays on the same position when zooming).
When I integrated with the example and I zoom, the circle gets dragged slightly to the top left when zooming out and to the bottom right when I zoom in, in the end returning to the original position when the zoom stops.
On the angular project I'm using require to load the scripts to the page and the view that has the map is not the first one that is loaded. I am not using a directive for leaflet, just using the files. The code is exactly the same from the example to the angular project, the only difference is that I am not using a script tag in the html file as I was in the example (since the code has been moved to the controller).
I wanted the behaviour to be the same as it was in the example but at this stage I don't know what might be causing it besides the fact that is not the view that is first being loaded.
Here's the view code:
<div id="leafletMap" style="width: 500px; height: 300px;"></div>
Here's the code in my controller:
/* globals L, $ */
define(['angular'], function (angular) {
'use strict';
/**
* #ngdoc function
* #name rmsPortalApp.controller:ViewMapCtrl
* #description
* # ViewMapCtrl
* Controller of the rmsPortalApp
*/
angular.module('rmsPortalApp.controllers.ViewMapCtrl', [])
.controller('ViewMapCtrl', function ($scope, Data) {
var ownerCircleLayer;
L.Map = L.Map.extend({
openPopup: function (popup) {
// this.closePopup(); // just comment this
this._popup = popup;
return this.addLayer(popup).fire('popupopen', {
popup: this._popup
});
}
});
var map = L.map('leafletMap', {
touchZoom: true,
dragging: true
}).setView([39.678, -8.229], 6);
/* Initialize the SVG layer */
//map._initPathRoot();
/* SVG from the map object */
//var svg = d3.select("#map").select("svg");
var southWest = [85.05, -180.01];
var northEast = [-85.06, 180.05];
var bounds = L.latLngBounds(southWest, northEast);
map.setMaxBounds(bounds);
L.tileLayer('http://api.tiles.mapbox.com/v4/bmpgp.010fd6a5/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiYm1wZ3AiLCJhIjoiOWY4NGYwN2VjZDg0MGI1ZjdmMWI3ZjdlNGNmY2NmNmQifQ.FZ5cr4mO3iDKVkx9zz4Nkg', {
attribution: '© Powered By CGI',
minZoom: 3,
maxZoom: 18,
id: 'bmpgp.010fd6a5',
accessToken: 'pk.eyJ1IjoiYm1wZ3AiLCJhIjoiOWY4NGYwN2VjZDg0MGI1ZjdmMWI3ZjdlNGNmY2NmNmQifQ.FZ5cr4mO3iDKVkx9zz4Nkg'
}).addTo(map);
setOwnerCircle()
function setOwnerCircle() {
ownerCircleLayer = new L.layerGroup();
var ownerCircle = L.circle([39, -8], 3000, {
color: 'red',
opacity: 1,
weigth: 1,
fillOpacity: 0.0,
className: 'leaflet-zoom-animated'
});
ownerCircleLayer.addLayer(ownerCircle);
var circleBounds = ownerCircle.getBounds();
// Image popup
var endLat = circleBounds.getCenter().lat - 0.10000;
var endLon = circleBounds.getEast();
map.addLayer(ownerCircleLayer);
addedOwnerCircle = true;
}
})
});
EDIT:
I have tried putting it in the first view that is being loaded, it still happens.

Found the reason why it was happening:
When double checking the actual mapbox.js and mapbox.css I noticed that my css was wrong, upon replacing it with the right mapbox.css it stopped doing the dragging. Thank you for the help regardless.

Related

How can I set up the browser size before my protractor test runs?

I have the following protractor test listed below. It runs fine. But I need to add some code that opens the browser to full screen since my test is sensitive to pixel location of gridster tiles. How can this be done?
describe('DragAndDrop Test', function () {
require('protractor');
require('jasmine-expect');
beforeAll(function () {
context = new Context();
context.get();
browser.waitForAngular();
browser.driver.manage().window().maximize();
});
it('should drag and drop Application Experience tile', function () {
//a = angular.element(document).find('h3')[1]
//target is where we are dragging the box to. Box is the Box
var target = { x: 300, y: 50 };
var box = element(by.cssContainingText('h3', 'Application Experience'));
var infoSpot = element(by.cssContainingText('h3', 'Application Experience'));
//scope is going to hold the scope variables that tell us where the box is located
//get the standardItems Scope
box.evaluate('dashboards').then(function(scope) {
//make sure the box we are using is initially set in column 0 and Row 0
expect(scope['1'].widgets[0].col).toEqual(0);
expect(scope['1'].widgets[0].row).toEqual(0);
});
//drag and drop the box somewhere else.
browser.actions().dragAndDrop(box, target).perform();
browser.waitForAngular();
browser.driver.sleep(5000);
//get the updated scope
box.evaluate('dashboards').then(function(scope) {
//test to see that the box was actually moved to column 1 and row 0
expect(scope['1'].widgets[0].col).toEqual(1);
expect(scope['1'].widgets[0].row).toEqual(0);
});
});
});
var Context = function () {
this.ignoreSynchronization = true;
//load the website
this.get = function () {
browser.get('http://127.0.0.1:57828/index.html#/dashboard');
};
};
I think the better practice is to do this in your config.
onPrepare: function() {
browser.manage().window().setSize(1600, 1000);
}
or
onPrepare: function() {
browser.manage().window().maximize();
}
You already have this line in your beforeAll function, which will maximize your browser before any test is run:
browser.driver.manage().window().maximize();
However, on some operating systems, Chrome browser won't maximize the window horizontally, only vertically. You have two options:
a) Set the width explicitly to some predefined value, e.g:
browser.driver.manage().window().setSize(1200, 768);
b) Get the screen resolution with a Javascript function and set the window size accordingly.
var width = GET_WIDTH;
var height = GET_HEIGHT;
browser.driver.manage().window().setSize(width, height);

Combining <ons-sliding-menu> and <ons-carousel>

I have an app with <ons-sliding-menu> and a page with <ons-toolbar> and a horizontal <ons-carousel> covering the remaining space.
For the <ons-sliding-menu> the parameter swipe-target-width="50px" is set.
Is there a way to tell the <ons-carousel> to ignore events originating from the most left 50px and let these go to the menu?
Currently there is no option to make the carousel ignore events on one side, but perhaps you can make a trick. You can put a div at the same level than the carousel and let it take the clicks instead of the carousel in the area you need:
<div class="cover"></div>
<ons-carousel>
...
</ons-carousel>
You can change these values to fit your case:
.cover {
position: absolute;
left: 0;
height: 100%;
width: 200px;
z-index: 1;
}
Check it out here: http://codepen.io/frankdiox/pen/YqKOJE
Hope it helps!
After some experimentation, I came to the solution to inject the necessary functionality directly in the drag event handlers of the OnsCarouselElement. For this purpose I have introduced the attribute swipe-ignore-left for the <ons-carousel>. The other sites could easily be added when needed.In order to inject the functionality, load this JS-Code after loading onsenui.js:
(function () {
'use strict';
/****************************************************************
Checks the current event against the attribute swipe-ignore-left.
****************************************************************/
window.OnsCarouselElement.prototype._ignoreDrag = function (event) {
var attr = this.getAttribute('swipe-ignore-left');
if (attr === undefined) return false;
var left = parseInt(attr, 10);
if (left === undefined || left < 1) return false;
var startX = event.gesture.center.clientX - event.gesture.deltaX;
return startX < left;
};
/****************************************************************
Save the original drag-event-handlers
****************************************************************/
var originalCarouselOnDrag = window.OnsCarouselElement.prototype._onDrag;
var originalCarouselOnDragEnd = window.OnsCarouselElement.prototype._onDragEnd;
/****************************************************************
Override: OnsCarouselElement.prototype._onDrag
****************************************************************/
window.OnsCarouselElement.prototype._onDrag = function (event) {
if (this._ignoreDrag(event)) return;
originalCarouselOnDrag.apply(this, arguments);
};
/****************************************************************
Override: OnsCarouselElement.prototype._onDragEnd
****************************************************************/
window.OnsCarouselElement.prototype._onDragEnd = function (event) {
if (this._ignoreDrag(event)) return;
originalCarouselOnDragEnd.apply(this, arguments);
};
})();
To preserve for example the left 20 pixel for the <ons-sliding-menu>, this HTML is to provide:
<ons-sliding-menu ... side="left" swipeable swipe-target-width="20px" />
...
<ons-carousel ... swipeable swipe-ignore-left="20px" />

Angular $scope.$apply exceptions when maximing a Malhar widget

I am working in the Malhar widget framework, which is based on jQuery sortable widgets. ex/ https://github.com/DataTorrent/malhar-angular-dashboard
I am working on some DOM manipulation on each widget (maximize/minimize/refresh), and running into some Angular $scope.$apply exceptions below.
Function details:
The $scope.grabSouthResizer function (working fine) is the Mahlar function that came with the framework; I just modified it slight to also refresh the Kendo UI charts.
The $scope.maxResizer function is my custom function, which is throwing $rootScope:inprog exceptions every time is hits my $scope.$apply();.
$scope.grabSouthResizer = function (e) {
var widgetElm = $element.find('.widget');
e.stopPropagation();
e.originalEvent.preventDefault();
// get the starting horizontal position
// .. code ommitted for brevity
// sets new widget width on mouseup
var mouseup = function (e) {
// calculate height change
var curY = e.clientY;
var pixelChange = curY - initY;
var widgetContainer = widgetElm.find('.widget-content');
var diff = pixelChange;
var height = parseInt(widgetContainer.css('height'), 10);
var newHeight = (height + diff);
$scope.widget.setHeight(newHeight + 'px');
$scope.$emit('widgetChanged', $scope.widget);
$scope.$apply(); // *** NO EXCEPTIONS THROWN ***
$scope.$broadcast('widgetResized', {
height: newHeight
});
// kendo chart - refresh height
var chart = widgetElm.find('.k-chart').data("kendoChart");
if (chart != undefined) {
chart.setOptions({ chartArea: { height: newHeight - (newHeight * .10) } });
chart.resize($(".k-chart"));
}
};
};
$scope.maxResizer = function (e) {
// TODO: properly restore the window to original position..
var widgetElm = $element.find('.widget');
e.stopPropagation(); // testing - same as grabSouthResizer() below
e.originalEvent.preventDefault();
var pixelHeight = widgetElm.height();
var pixelWidth = widgetElm.width();
// fyi: '.k-tree' will auto-resize, so no need to find that
var chart = widgetElm.find('.k-chart').data("kendoChart");
var treelist = widgetElm.find('.k-treelist').data("kendoTreeList");
// height differential (reduce height of container if inner widget is a treelist)
var ht_diff = (chart != undefined ? 200 : 600);
var newHeight = window.innerHeight - ht_diff;
if (!widget.maximized) {
// widget container maximize
widget.maximized = true;
$scope.widget.setWidth(window.innerWidth);
$scope.widget.setHeight(newHeight); //window.innerHeight - ht_diff);
$scope.$emit('widgetChanged', widget);
$scope.$apply(); // *** THROWS $rootScope:inprog EXCEPTIONS !!! ***
$scope.$broadcast('widgetResized', {
width: window.innerWidth,
height: newHeight
});
if (chart != undefined) {
// refresh Kendo chart
chart.setOptions({ chartArea: { height: widgetElm.height()*.9, width: widgetElm.width()*.95 } });
chart.resize($(".k-chart"));
}
}
kendoRefreshTimer(); // this work-around used instead of $scope.$apply()
}
var timer;
function kendoRefreshTimer() {
timer = $timeout(function () {
refreshKendo();
}, 1);
}
function refreshKendo() {
// Kendo chart refresh here...
}
Big question: why is $scope.$apply(); causing errors in my maxResizer function, but not in the Malhar original grabSouthResizer function ? I also understand that $scope.$apply() is NOT recommended, but it seems to be widely used as a work-around.
I would create an online plunk, but I still haven't set up this Malhar widget framework online as of yet. It's a bit complicated to set up.
Your advice is appreciated.
regards,
Bob
* UPDATE *
I updated my post to show how I've worked around this scope.apply issue by using a $timeout function, but I don't like the split-second delay in the UI. i.e. You can see the Kendo chart resizing itself, so it doesn't look so smooth.

AngularJS ng-Grid and ngGridFlexibleHeightPlugin not working as I expect

I am trying to use Angular ng-grid to show some dynamic content. The grid will have 0 - 25 rows. I want to have a minimum size and then have the ng-grid auto adjust the height as items get added to the array. For some reason the auto size stops after adding 6-7 items (it even seems to depend on your resolution).
Can anyone help? What am I missing? I have a Plunker below that shows the issue.
http://plnkr.co/edit/frHbLTQ68GjMgzC59eSZ?p=preview
If you are still having issues I would suggestion not using the ng-grid and create your layout directly in html (Use DIVs, column width formatting, styles, etc...). Then populate your new layout using your $scope. Between variables, models and ng-repeat you should be able to do everything you need.
The code bellow is a modification to the plugin. It works by checking number of items in the grid data and calculating the height based on that. The options passed in to the plugin are height of row and header height.
ngGridCustomFlexibleHeightPlugin = function (opts) {
var self = this;
self.grid = null;
self.scope = null;
self.init = function (scope, grid, services) {
self.domUtilityService = services.DomUtilityService;
self.grid = grid;
self.scope = scope;
var recalcHeightForData = function () { setTimeout(innerRecalcForData, 1); };
var innerRecalcForData = function () {
var gridId = self.grid.gridId;
var footerPanelSel = '.' + gridId + ' .ngFooterPanel';
var extraHeight = self.grid.$topPanel.height() + $(footerPanelSel).height();
var naturalHeight = (grid.data.length - 1) * opts.rowHeight + opts.headerRowHeight;
self.grid.$viewport.css('height', (naturalHeight + 2) + 'px');
self.grid.$root.css('height', (naturalHeight + extraHeight + 2) + 'px');
// self.grid.refreshDomSizes();
if (!self.scope.$$phase) {
self.scope.$apply(function () {
self.domUtilityService.RebuildGrid(self.scope, self.grid);
});
}
else {
// $digest or $apply already in progress
self.domUtilityService.RebuildGrid(self.scope, self.grid);
}
};
scope.$watch(grid.config.data, recalcHeightForData);
};
};
I find using this piece of code on the stylesheet solved my problem. I disabled the plugin but it works either way.
.ngViewport.ng-scope{
height: auto !important;
overflow-y: hidden;
}
.ngTopPanel.ng-scope, .ngHeaderContainer{
width: auto !important;
}
.ngGrid{
background-color: transparent!important;
}
I hope it helps someone

Leaflet + Sencha NO touch + Sencha architect integration: mixed up tiles

I am trying to integrate Sencha 4.1 (ExtJS) with the Leaflet mapping library while using Sencha Architect.
When the page loads, the tiles are mixed up and appear offset. I need to drag the page up to be able to see the tiles.
The full project is available here: https://github.com/breizo/SenchaLeaflet.
Here is an excerpt of the custom component created (see full code here: https://github.com/breizo/SenchaLeaflet/blob/master/ux/LeafletMap.js).
constructor: function () {
this.callParent(arguments);
this.on({
resize: 'doResize',
scope: this
});
var ll = window.L;
if (!ll) {
this.setHtml('Leaflet library is required');
}
}
onRender: function() {
this.callParent(arguments);
var renderTo = arguments[0].dom.id;
debugger;
var me = this,
ll = window.L,
element = me.mapContainer,
mapOptions = me.getMapOptions(),
map,
tileLayer;
if (ll) {
// if no center property is given -> use default position
if (!mapOptions.hasOwnProperty('center') || !(mapOptions.center instanceof ll.LatLng)) {
mapOptions.center = new ll.LatLng(47.36865, 8.539183); // default: Zuerich
}
me.setTileLayer(new ll.TileLayer(me.getTileLayerUrl(), me.getTileLayerOptions()));
tileLayer = me.getTileLayer();
mapOptions.layers = [tileLayer];
me.setMap(new ll.Map(renderTo, mapOptions));
map = me.getMap();
// track map events
map.on('zoomend', me.onZoomEnd, me);
map.on('movestart', me.onMoveStart, me);
map.on('moveend', me.onMoveEnd, me);
me.fireEvent('maprender', me, map, tileLayer);
}
},
When debugging it appears that when onRender is called, the parent container of the map is not properly sized yet, in particular its height is only enough to contain the attrib text, about 16 pix. WHen the doResize is called, the container is properly sized, but it doesn't change the end result: the tiles are mixed up and offset.
I tried various changes to the container, but nothing worked...
1) Problem with mixed layers is caused by CSS. Your leaflet.css has wrong path in html, so it's not attached in the document. To fix mixing issue set correct path to css file, or attach it from CDN:
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.4/leaflet.css" />
2) Wrong map offset is caused by extjs generated div:
<div class="x-llmap x-fit-item x-llmap-default" ...></div>
It pushes map container to the bottom and wrong offset calculations are made. You can also fix this using inline style or CSS:
.leaflet-map-pane {
top: 0;
}

Resources