Related
I am having problems with ST2.3. I've upgraded from 2.1 and I've had several regressions which are now working ok. However one problem that definitely seems to be broken is the Map wrapper around the google api. My app works fine in Testing and Development modes, but as soon as it is built for production the map stops working.
The code where it seems to break on is here within the Map code on the setMapCenter function.
setMapCenter:function(e){var b=this,d=b.getMap(),a=b.getMapOptions(),c=(window.google||{}).maps;if(c){if(!e){if(d&&d.getCenter){e=d.getCenter()}else{if(a.hasOwnProperty("center")){e=a.center}else{e=new c.LatLng(37.381592,-122.135672)}}}
The breakpoint seems to be on the line: new c.LatLng(37.381592,-122.135672).
Why would it suddenly start failing on a production build?
Update
This is the stack trace, but I can't find out what actually is the problem as the code is obfuscated/minified:
Uncaught TypeError: undefined is not a function VM1471:1
Ext.define.setMapCenterVM1471:1
Ext.define.updateUseCurrentLocationVM1471:1
jVM1471:1
b.implement.initConfigVM1471:1
etc...
The weird thing is, this worked using ST2.1. It also works in ST2.3 but only in Testing/Debug mode.
My code doesn't even set the center of the map when the view is initially shown:
This is the map view:
Ext.define('MyApp.view.offices.OfficeMap', {
extend: 'Ext.Panel',
alias: 'widget.officemapview',
requires: [
'Ext.Map'
],
config: {
layout: 'fit',
items: [
{
xtype: 'map',
listeners: {
activate: function(me, newActiveItem, oldActiveItem, eOpts){
console.log("activate fired");
},
maprender: function () {
console.log("maprender fired");
var gMap = this.getMap();
this.fireEvent('googleMapRender', gMap);
}
}
}
],
officeRecord: null
}
});
This is the controller code that receives the render event from the view:
onGoogleMapRender: function (googleMap) {
var record = this.selectedOffice;
var longi = record.get("Longitude");
var lati = record.get("Latitude");
console.log("About to create google maps pos")
console.log("About to create google maps marker")
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lati, longi)
});
console.log("About to set maps map object")
marker.setMap(googleMap);
setTimeout(function () {
console.log("map setTimeout")
// weird timeout issue? - http://stackoverflow.com/questions/15041697/sencha-touch-google-map-and-centering-a-marker
googleMap.setZoom(17);
googleMap.panTo(pos);
}, 500);
The error on the following browsers are:
Chrome - Uncaught TypeError: undefined is not a function
IE - Object does not support this function
Any ideas as to what is happening here?
Maybe check in chrome in developer tools on network tab what are the difference in loading javascript files between production mode and development mode.
That is because your javascript are loaded before the google maps javascript is loaded. So when setMapCenter get the function, there is no c yet (undefined). What you can do is use some callback, like "painted" and then set your "setMapCenter".
Update
Try to do this just to test:
xtype: "map",
listeners: {
activate: function(me, newActiveItem, oldActiveItem, eOpts){
me.config.mapOptions = {
center : new google.maps.LatLng(-42,-42), // your center
zoom : 14,
//others options
}
},
maprender: function(comp, map) {
var me = this;
var map = this.getMap();
// marker test
var position = new google.maps.LatLng(-42, -42);
var marker = new google.maps.Marker({
position: position,
title : 'Hello World',
map: map
});
}
}
Ok, so I would like to have a slider that looks like this one.
Just can't figure out where we can at least have these delimiter separators? So if you see there are 7 delimiters and we have large labels on the first 4-th and the last delimeter.
How would you approach this task?
This is a rather old question but I was faced with the very same need today. Building on GenieWanted's answer, I came to this:
...
{
xtype: 'sliderfield',
maxValue: 5,
label: 'Some data',
html: '<table width="100%" align="left"><tr><td width="25%">Min</td><td width="50%" align="center">Med</td><td width="25%" align="right">Max</td></tr></table>'
}
...
which works very well for me, and avoids messing around to find the correct number of needed. Also, I suspect that results would vary from device to device using .
There is no way of adding a label inside sliderfield. However, you can indeed add HTML to acheive the required output. On the config panel, go to HTML property, and add something like this:
<div style="padding-left:1em">| | |<div>Low Average High </div></div>
The output I have got:
You just need to playaround with the alignment of your text in the HTML. That will do!
Good Luck!
You can create Custom Slider like this
Ext.ns('Ext.ux');
Ext.ux.CustomSlider = Ext.extend(Object, {
valueTextClass: 'x-slider-value-text',
showSliderBothEndValue: true,
sliderEndValueStyle: 'color: black',
constructor: function(config){
Ext.apply(this, config);
Ext.ux.CustomSlider.superclass.constructor.apply(this, arguments);
},
init: function(parent) {
var me = this;
parent.on({
painted: {
fn: function(component) {
if (me.showSliderBothEndValue) me.showSliderEndValue(this);
if (!this.valueTextEl) {
this.valueTextEl = component.element.createChild({
cls: me.valueTextClass
});
}
}
}
});
},
showSliderEndValue: function(slider) {
var sliderPosX = slider.getComponent().getThumb().element.getX();
var thumbHeight = slider.getComponent().getThumb().element.getHeight();
var sliderLength = slider.getComponent().element.getWidth();
var minValueEl = slider.getComponent().element.createChild();
minValueEl.setHtml(slider.getComponent().getMinValue());
minValueEl.applyStyles('overflow:hidden;position:absolute');
minValueEl.applyStyles(this.sliderEndValueStyle);
minValueEl.setLeft(14);
minValueEl.setTop(thumbHeight -7);
var maxValueEl = slider.getComponent().element.createChild();
maxValueEl.setHtml(slider.getComponent().getMaxValue());
maxValueEl.applyStyles('overflow:hidden;position:absolute');
maxValueEl.applyStyles(this.sliderEndValueStyle);
maxValueEl.setLeft(sliderLength-45);
maxValueEl.setTop(thumbHeight - 7);
}
});
And create slider like this
var slider = {
xtype: 'sliderfield',
flex : 6,
label: "Percentage",
name: "Percentage",
value : 50,
minValue : 0,
maxValue : 100,
labelWrap : true,
labelAlign : 'left',
increment : 10,
plugins: [new Ext.ux.CustomSlider({
showSliderBothEndValue: true
})],
listeners: {
painted: function (slider) {
var sliderPanelItems = this.parent.getInnerItems();
sliderPanelItems[1].setValue(this.getValue());
},
change: function (me,slider, thumb, newVal, oldVal, opts) {
var sliderPanelItems = this.parent.getInnerItems();
sliderPanelItems[1].setValue(newVal);
}
}
};
Result will be like this
I did this using this link
I've successfully integrated both a Flot line graph and an instance of FullCalendar into my site. They are both on separate pages (although the pages are loaded into a div via AJAX).
I've added the Flot Resize plugin and that works perfectly, re-sizing the line graph as expected. However, it seems to cause an error when resizing the calendar.
Even if I load the calendar page first, when I resize the window I get this error in the console (also, the calendar does not resize correctly):
TypeError: 'undefined' is not an object (evaluating 'r.w=o!==c?o:q.width()')
I was struggling to work out where the error was coming from, so I removed the link to the Flot Resize JS and tried again. Of course the line graph does not resize, but when resizing the calendar, it works correctly.
The div containers for the two elements have different names and the resize function is called from within the function to draw the line graph (as required).
I have tried moving the link to the Flot Resize plugin into different places (i.e. above/below the fullCalendar JS, into the template which holds the graph), but all to no avail.
Does anyone have any idea where the conflict might be and how I might solve it??
Thanks very much!
EDIT: It seems that the error is also triggered when loading the line graph (flot) page AFTER the fullcalendar page even without resizing the window.... Now I am very confused!
EDIT 2: The code which draws the line graph. The function is called on pageload and recieves the data from JSON pulled off the server. When the graph is loaded, I still get the error about shutdown() being undefined.
function plotLineGraph(theData){
var myData = theData['data'];
var myEvents = theData['events'];
var myDates = theData['dates'];
var events = new Array();
for (var i=0; i<myEvents.length; i++) {
events.push(
{
min: myEvents[i][0],
max: myEvents[i][1],
eventType: "Calendar Entry",
title: myEvents[i][2],
description: myEvents[i][3]
}
);
}
function showTooltip(x, y, contents) {
$('<div id="tooltip">' + contents + '</div>').css( {
position: 'absolute',
display: 'none',
top: y + 5,
left: x + 5,
border: '1px solid #fdd',
padding: '2px',
'background-color': 'black',
opacity: 0.80
}).appendTo("body").fadeIn(200);
}
var previousPoint = null;
$("#placeholder").bind("plothover", function (event, pos, item) {
$("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2));
if ($("#enableTooltip:checked").length == 0) {
if (item) {
if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex;
$("#tooltip").remove();
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
if(item.series.label != null){
showTooltip(item.pageX, item.pageY,
item.series.label + " of " + y);
}
}
}
else {
$("#tooltip").remove();
previousPoint = null;
}
}
});
var d1 = [
myData[0], myData[1], myData[2], myData[3], myData[4],
myData[5], myData[6], myData[7], myData[8], myData[9],
myData[10], myData[11], myData[12], myData[13], myData[14],
myData[15], myData[16], myData[17], myData[18], myData[19],
myData[20], myData[21], myData[22], myData[23], myData[24],
myData[25], myData[26], myData[27], myData[28], myData[29]
];
var markings = [
{ color: '#FFBDC1', yaxis: { from: 0, to: 2 } },
{ color: '#F2E2C7', yaxis: { from: 2, to: 3.5 } },
{ color: '#B6F2B7', yaxis: { from: 3.5, to: 5 } }
];
$.plot($("#placeholder"), [
{label: "Average Daily Rating", data: d1, color: "black"}
], {
events: {
data: events,
},
series: {
lines: { show: true },
points: { show: true }
},
legend: { show: true, container: '#legend-holder' },
xaxis: {
ticks:[
myDates[0], myDates[1], myDates[2], myDates[3], myDates[4],
myDates[5], myDates[6], myDates[7], myDates[8], myDates[9],
myDates[10], myDates[11], myDates[12], myDates[13], myDates[14],
myDates[15], myDates[16], myDates[17], myDates[18], myDates[19],
myDates[20], myDates[21], myDates[22], myDates[23], myDates[24],
myDates[25], myDates[26], myDates[27], myDates[28], myDates[29]
],
},
yaxis: {
ticks: 5,
min: 0,
max: 5
},
grid: {
backgroundColor: { colors: ["#fff", "#eee"] },
hoverable: true,
clickable: true,
markings: markings
},
selection: {
color: 'white',
mode: 'x'
},
});
$('#placeholder').resize();
$('#placeholder').shutdown();
}
EDIT 3:
The calendar is called like this:
function showCalendar() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#fullcalendar').fullCalendar({
header: {
left: 'prev',
center: 'title',
right: 'next'
},
clickable: true,
firstDay: 1,
eventSources: [
{
url: '/populate-calendar/{{theProductUuid}}/',
color: 'black',
data: {
text: 'text'
}
}
],
eventClick: function(calEvent, jsEvent, view) {
var startDate = $.fullCalendar.formatDate(calEvent.start, 'yyyy-MM-dd');
var endDate = $.fullCalendar.formatDate(calEvent.end, 'yyyy-MM-dd');
var eventId = calEvent.uuid;
$('#modal-event-title').text(calEvent.title);
$('#edit-event-name').val(calEvent.title);
$('#edit-start-date').val(startDate);
$('#edit-end-date').val(endDate);
$('#edit-event-text').val(calEvent.text);
$('#edit-event-btn').attr('data-uuid', eventId);
$('#modal-edit-event').on('click', '#delete-btn', function(){
deleteCalendarEvent(eventId);
});
$('#modal-edit-event').modal();
},
});
}
The AJAX to load the page containing the flot chart:
function loadDetailedReports(uuid){
$('#product-content').fadeOut('slow', function(){
$('#product-content').empty();
$('#whole-product-sub-nav .active').removeClass('active');
$('#detailed-reports-content').load('/detailed-reports/' + uuid + '/', function(){
$('#detailed-reports-btn').addClass('active');
$('#detailed-reports-content').fadeIn('slow', function(){
if (authorized){
setLocationHash('loadDetailedReports&' + uuid);
getChartData(uuid);
} else {
setLocationHash('');
}
});
});
});
}
And the AJAX to load the page containing the calendar:
function loadCalendar(uuid){
$('#detailed-reports-content').empty().hide();
$('#product-content').fadeOut('slow', function(){
$('#whole-product-sub-nav .active').removeClass('active');
$('#product-content').load('/calendar/' + uuid + '/', function(){
$('#calendar-btn').addClass('active');
$('#product-content').fadeIn('slow', function(){
if (authorized){
setLocationHash('loadCalendar&' + uuid);
} else {
setLocationHash('');
}
showCalendar();
});
});
});
}
The calls to .resize and .shutdown are there because I was under the impression that they are necessary to achieve the resizing function and in response to your earlier comment regarding shutdown...... They're quite possibly n00b errors........?!?!
It looks like this is triggering on line 198 of jquery-resize:
data.w = w !== undefined ? w : elem.width();
This sounds like a race-condition stemming from the way you load different content into the same div. Flot binds the resize event to the chart div, and only un-binds it if the plot is destroyed cleanly.
EDIT: Looking at your code, my first suggestion would be to get rid of the resize and shutdown calls at the end of plotLineGraph. The resize plugin doesn't require any setup; it hooks into Flot to attach automatically to any new plot. So your call to resize is actually to jQuery's resize event trigger, which may be what's causing the error.
EDIT #2: I'm still not clear on your structure, but to generalize: anywhere that you might be getting rid of #placeholder (via emptying its parent or anything like that) you should first call shutdown on the plot object. If you aren't keeping a reference to it, you can do it like this: $("#placeholder").data("plot").shutdown(); but then have to account for the fact that it's undefined prior to the creation of your first plot.
If that still doesn't work, I'd need to see a live (simplified) example to make any further suggestions.
I have a toolbar button which when clicked should update my map to my current location. I am unable to find a working example of this functionality and hoping someone can advise me. Please see below for sample code - thanks for your help
Map:
Ext.define('MyApp.view.Myap', {
extend: 'Ext.Map',
alias: 'widget.mymap',
config: {
useCurrentLocation: false,
mapOptions:{
zoom: 9,
center: new google.maps.LatLng(42.2, -72.5),
mapTypeId: google.maps.MapTypeId.ROADMAP
},
listeners: {
maprender : function(comp, map){
google.maps.event.addListenerOnce(map, "idle", function () {
var host = window.location.origin ? window.location.origin : window.location.protocol + "/" + window.location.host;
var kmlOptions = {preserveViewport: false}
var now = +new Date();
var layer = new google.maps.KmlLayer(host + '/path/to.kml?timestamp=' + now, kmlOptions);
layer.setMap(map);
return layer;
});
},
}
},
})
Toolbar Button:
Ext.define('MyApp.view.btnLocateMe', {
extend: 'Ext.Button',
alias: 'widget.btnlocateme',
config: {
ui: 'normal',
iconCls: 'locate',
iconMask: true,
text: 'Locate Me',
listeners: [
{
fn: 'onButtonTap',
event: 'tap'
}
]
},
onButtonTap: function(button, e, options) {
//Produces error: cannot call method of undefined
currentLocation: new google.maps.LatLng(this._geo.getLatitude(), this._geo.getLongitude());
MyApp.view.MyMap.map.setCenter(currentLocation);
}
});
my two cents contribution, try this
1) in MyApp.view.Myap substitute
useCurrentLocation: false,
by
useCurrentLocation : {
autoUpdate : false
},
Also you should declare currentLocation as a variable (I presume)
var currentLocation = ...
This should works. I've use a similar logic as yours in onButtonTap but inside a controller with no problems
Best regards
I have one suggestion.
Try changing current location to
new google.maps.LatLng( this.geo.getLatitude(),this.geo.getLongitude() ) ;
I think you can gather more info from this question in here.
The simplest way - switch to the another map view with option useCurrentLocation: true set in the config
my question is related to building GUIs on Sencha Touch 2 creating first the controls and then instantiating them on a panel's items. Like so:
var myButton = Ext.create('Ext.Button', {
text: 'Button',
});
And then do this in order to show it on screen:
//..some panel
items:[{myButton}, {anotherControl}]
When I try to do this on Sencha Touch 2, it just throws an error: "Uncaught SyntaxError: Unexpected identifier"
I used to do this on Sencha Touch 1.x and this is driving me crazy because in every example I find in the net, they declare the controls inside the panel using the xtype property.
A small code snippet would be great help for me.
Thanks!
You can do it like so :
Ext.define('App.view.MyView', {
xtype: 'myview',
extend: 'Ext.Panel',
config: {
layout: 'vbox'
},
constructor: function() {
var me = this;
me.callParent(arguments);
var myButton1 = Ext.create('Ext.Button', {
text: 'Button1',
});
var myButton2 = Ext.create('Ext.Button', {
text: 'Button2',
});
me.add([myButton1,myButton2]);
}
});
Hope this helps