I have multiple annotations on the map - although the user may need to scroll to see them. I want the user to be able to select a button to fit them all on the map - eliminating the need to scroll/manually resize.
I have determined the min. and max. latitudes and longitudes (e.g minLat, maxLat, minLong, maxLong) for the points I want to show on the map.
I'm struggling, however, with the specific formula to use to get the longitude and latitude properties to pass to mapview.setLocation. Any pointers on what formula I can use?
I have made a function for the same requirement. You can test and let me know if it gives some error:
function setMarkersWithCenter(map,latiarray,longiarray)
{
if(latiarray.length != longiarray.length)
return;
var total_locations = latiarray.length;
var minLongi = null, minLati = null, maxLongi = null, maxLati = null;
var totalLongi = 0.0, totalLati = 0.0;
for(var i = 0; i < total_locations; i++)
{
if(minLati == null || minLati > latiarray[i]) {
minLati = latiarray[i];
}
if(minLongi == null || minLongi > longiarray[i]) {
minLongi = longiarray[i];
}
if(maxLati == null || maxLati < latiarray[i]) {
maxLati = latiarray[i];
}
if(maxLongi == null || maxLongi < longiarray[i]) {
maxLongi = longiarray[i];
}
}
var ltDiff = maxLati-minLati;
var lgDiff = maxLongi-minLongi;
var delta = ltDiff>lgDiff ? ltDiff : lgDiff;
if(total_locations>0 && delta>0)
{
map.setLocation({
animate : true,
latitude:((maxLati+minLati)/2),
longitude:((maxLongi+minLongi)/2),
latitudeDelta:delta,
longitudeDelta:delta,
});
}
}
Hope it helps.
Related
Lets say I have a table with a list of names, such as "a, b, c" and each name has several other values assigned (some of the other values can be assigned to several/all of names values, example below).
Table example:
( names - other ):
a - aa
a - ab
a - ac
b - ab
b - bb
b - cb
c - ac
c - bc
c - cc
How do I make in birt so that I could select names in one parameter box and get corresponding other values to select for another parameter? I know it's possible to do that with cascading parameter, but that doesn't allow to have multiselect for the first parameter, which in our example would be names values.
Found a solution partly here: https://forums.opentext.com/forums/developer/discussion/61283/allow-multi-value-for-cascading-parameter
and here (thanks google translate ^^): https://www.developpez.net/forums/d1402270/logiciels/solutions-d-entreprise/business-intelligence/birt/birt-4-3-1-multi-value-cascade-parameters/
Steps to do:
change"\birt\webcontent\birt\ajax\ui\dialog\BirtParameterDialog.js" file contents (there is a file to download for replacement in one of the links, but in case it goes dead I'm sharing 2 snippets from it where the changes occur:
__refresh_cascade_select : function( element )
{
var matrix = new Array( );
var m = 0;
for( var i = 0; i < this.__cascadingParameter.length; i++ )
{
for( var j = 0; j < this.__cascadingParameter[i].length; j++ )
{
var paramName = this.__cascadingParameter[i][j].name;
if( paramName == this.__isnull )
paramName = this.__cascadingParameter[i][j].value;
if( paramName == element.id.substr( 0, element.id.length - 10 ) )
{
//CHANGE//
//The two way work (String(selectedValue) or Array(SelectedValueArray))
var l = 0;
var isFirstElement = true;
var selectedValue = "";
var selectedValueArray = new Array();
for(var test = 0; test<element.options.length;test++){
if(element.options[test].selected){
if(isFirstElement){
isFirstElement = false;
selectedValue = element.options[test].value;
}
else{
selectedValue = selectedValue+","+element.options[test].value;
}
selectedValueArray[l] = element.options[test].value;
l++;
}
}
//CHANGE//
var tempText = element.options[element.selectedIndex].text;
var tempValue = element.options[element.selectedIndex].value;
// Null Value Parameter
if ( tempValue == Constants.nullValue )
{
this.__cascadingParameter[i][j].name = this.__isnull;
this.__cascadingParameter[i][j].value = paramName;
}
else if( tempValue == '' )
{
if( tempText == "" )
{
var target = element;
target = target.parentNode;
var oInputs = target.getElementsByTagName( "input" );
if( oInputs.length >0 && oInputs[1].value != Constants.TYPE_STRING )
{
// Only String parameter allows blank value
alert( birtUtility.formatMessage( Constants.error.parameterNotAllowBlank, paramName ) );
this.__clearSubCascadingParameter( this.__cascadingParameter[i], j );
return;
}
else
{
// Blank Value
this.__cascadingParameter[i][j].name = paramName;
this.__cascadingParameter[i][j].value = tempValue;
}
}
else
{
// Blank Value
this.__cascadingParameter[i][j].name = paramName;
this.__cascadingParameter[i][j].value = tempValue;
}
}
else
{
this.__cascadingParameter[i][j].name = paramName;
//CHANGE//
//The two way work (String(selectedValue) or Array(SelectedValueArray))
this.__cascadingParameter[i][j].value = selectedValueArray;
//CHANGE//
}
for( var m = 0; m <= j; m++ )
{
if( !matrix[m] )
{
matrix[m] = {};
}
matrix[m].name = this.__cascadingParameter[i][m].name;
matrix[m].value = this.__cascadingParameter[i][m].value;
}
this.__pendingCascadingCalls++;
birtEventDispatcher.broadcastEvent( birtEvent.__E_CASCADING_PARAMETER, matrix );
}
}
}
},
and this:
// exist select control and input text/password
// compare the parent div offsetTop
if( oFirstITC.parentNode && oFirstST.parentNode )
{
// Bugzilla 265615: need to use cumulative offset for special cases
// where one element is inside a group container
var offsetITC = Position.cumulativeOffset( oFirstITC );
var offsetST = Position.cumulativeOffset( oFirstST );
// compare y-offset first, then x-offset to determine the visual order
if( ( offsetITC[1] > offsetST[1] ) || ( offsetITC[1] == offsetST[1] && offsetITC[0] > offsetST[0] ) )
{
oFirstST.focus( );
}
else
{
oFirstITC.focus( );
}
}
After .js is changed cascading parameters can have multiselect on all levels.
Example:
1st DataSet "DS_country" query:
select CLASSICMODELS.OFFICES.COUNTRY
from CLASSICMODELS.OFFICES
2nd DataSet "DS_office" query:
select CLASSICMODELS.OFFICES.OFFICECODE
from CLASSICMODELS.OFFICES
where CLASSICMODELS.OFFICES.COUNTRY IN ('DS_country')
After datasets are created we can make cascading report parameters CRP_country and CRP_office (keep in mind that UI doesn't let you to choose "Allow multiple values" on the upper levels, but we can change that in property editor after the parameters are made by going to advanced tab and changing "Scalar parameter type" property value to "Multi Value")
The only thing left is to pick lower level cascading parameters (CRP_office in our example) and go to script tab and add this on "beforeOpen":
// Do that if your selections are in String type.
var stringArray = params["CRP_country"].value.toString().split(",");
var result = "";
for(var i =0 ; i < stringArray.length ; i++){
if(i==0){
result = "'"+stringArray[i]+"'";
}
else{
result = result+",'"+stringArray[i]+"'";
}
}
// For String
this.queryText = this.queryText.replace("'DS_country'", result);
//For integer (the first part is useless)
//this.queryText = this.queryText.replace("'DS_country'",
params["CRP_country"].value);
can someone show me how to query an array of strings with realm in react-native?
assume i have an array like the following:
const preferences = ["automatic","suv","blue",eco]
What I want is to get realm results where ALL strings in the attribute "specifications" of Cars is in "preferences".
E.g.: If an instance of Cars.specifications contains ["automatic","suv"]
a result should be returned.
But if an instance of Cars.specifications contained ["automatic,"suv","green"] this instance shouldn't be returned.
The length of preferences can vary.
Thank you very much.
Update:
What i tried is the following:
const query = realm.objects("Cars").filtered('specifications = preferences[0] OR specifications = preferences[1]')
As you see it is an OR operator which is surely wrong and it is hardcoded. Looping with realm really confuses me.
This code will work!
const collection = realm.objects('Cars');
const preferences = ["automatic","suv","blue","eco"];
let queryString = 'ANY ';
for (let i = 0; i < preferences.length; i++) {
if (i === 0) {
queryString += `specifications CONTAINS '${preferences[i]}'`;
}
if (i !== 0 && i + 1 <= preferences.length) {
queryString += ` OR specifications CONTAINS '${preferences[i]}'`;
}
}
const matchedResult = collection.filtered(queryString);
example of function to test if a word is inside an array of word
function inArray(word, array) {
var lgth = array.length;
word = word.toLowerCase();
for (var i = 0; i < lgth; i++) {
array[i] = (array[i]).toLowerCase();
if (array[i] == word) return true;
}
return false;
}
const preferences = ["automatic","suv","blue","eco"];
const specifications = ["automatic","suv"] ;
const specifications2 = ["automatic","suv", "boat"] ;
function test(spec,pref){
for (var i in spec){
if(!inArray(spec[i],pref)){
return false ;
}
}
return true;
}
console.log(test(specifications,preferences));
console.log(test(specifications2,preferences));
https://jsfiddle.net/y1dz2gvu/
Is it possible to check when a field is not empty and if not, make an ocg layer visible?
var ocg = FindOCG("Item 1 Arrow");
if (+event.value === '') {
ocg.state = !ocg.state;
} else {
ocg.state = !ocg.state;
}
Something like this (which doesn't work)!
Put this in the custom format script of the field in question. Replace "Square" with the name of your layer. You can see an example of it working here.
function getOCGByName(cName, nPage) {
var ocg = null;
var ocgArray = this.getOCGs(nPage);
for (var i=0; i < ocgArray.length; i++) {
if (ocgArray[i].name == cName) {
ocg = ocgArray[i];
}
}
return ocg;
}
var field = event.target;
var ocg = getOCGByName("Square", this.pageNum);
if (field.value.length > 0) {
ocg.state = true;
}
else {
ocg.state = false;
}
Note: This will only work in Adobe Acrobat and Reader and a few other viewers that are JavaScript capable.
I am trying to replace an outdated movieclip with a newer one.
To do this I'm usin JSFL to locate the old movieclips, save a reference, then add the new version in its place.
I have looked at addItem addItemToDocument and they successfully add the clip, but I'm unsure of how to add it to the specific layer and frame that the old instance of the movieclip was on.
Halps
Replacing all instances of the old movieclip with instances of the new movieclip, could be an easier solution.
All instances of the old movieclip can be found by parsing the timelines of the flash document.
Here is some code:
var _doc = (fl.getDocumentDOM() ? fl.getDocumentDOM() : fl.createDocument());
var _lib = _doc.library;
fl.outputPanel.clear();
ReplaceItemWithItem('Game Layouts/card holder', 'Game Layouts/card holder new');
function ReplaceItemWithItem(oldmcname, newmcname)
{
var item1 = GetItem(oldmcname);
var item2 = GetItem(newmcname);
if (!item1) return false;
if (!item2) return false;
if (oldmcname == newmcname)
return true;
return ReplaceAllItems(item1, item2);
}
function ReplaceAllItems(item1, item2)
{
var timelines = _doc.timelines;
var i, l = timelines.length;
var items = _lib.items;
var changed = false;
// Main timelines
for (i = 0; i < l; i++)
{
var timeline = timelines[i];
changed |= ReplaceItems(timeline, item1, item2);
}
// Timelines in library items
for (i = 0, l = items.length; i < l; i++)
{
var item = items[i];
switch (item.itemType)
{
case "movie clip":
case "graphic":
case "button":
changed |= ReplaceItems(item.timeline, item1, item2);
break;
}
}
return changed;
}
function ReplaceItems(timeline, item1, item2)
{
var changed = false;
if (timeline && item1 && item2)
{
var layers = timeline.layers;
var lay, layl = layers.length;
for (lay = 0; lay < layl; lay++)
{
var layer = layers[lay];
var frames = layer.frames;
var fr, frl = frames.length;
for (fr = 0; fr < frl; fr++)
{
var frame = frames[fr];
if (frame && frame.startFrame == fr)
{
var elements = frame.elements;
var e, el = elements.length;
for (e = 0; e < el; e++)
{
var elem = elements[e];
if (elem && elem.elementType == "instance") // Elements can be empty
{
var item = elem.libraryItem;
if (item.name == item1.name)
{
elem.libraryItem = item2;
changed = true;
}
}
}
}
}
}
}
return changed;
}
function GetItem(itemname)
{
if (!_lib.selectItem(itemname))
{
alert("'" + name + "' does not exist in the library!");
return null;
}
return _lib.getSelectedItems()[0];
}
Hope this helps!
How in the following JSON response can I check if uids is nil ?
{
height = 480;
pid = "F#dd705e6b96a6e894556c0db84870501e_d97383cc80238c38b8907d99690fa1c9";
tags = (
{
attributes = {
glasses = {
confidence = 97;
value = false;
};
smiling = {
confidence = 97;
value = false;
};
};
center = {
x = "60.83";
y = "75.21";
};
gid = "<null>";
height = "49.58";
label = "";
manual = 0;
nose = {
x = "76.21";
y = "77.16";
};
pitch = "-5.55";
recognizable = 0;
roll = "-0.45";
uids = ( // <<<<<========== UIDs Key
);
width = "66.11";
yaw = "-19.56";
}
);
url = "http://face.com/images/ph/a6e529853432599dad6da996746cb070.jpg";
width = 360;
}
When I try :
if ([[[[photo objectForKey:#"tags"] objectAtIndex:0] valueForKey:#"uids"] count] == 0)
It keeps returning FALSE all the time.
I'm able to access a lot of these keys successfully. But it's just this one key that's giving me issues.
Like, to access the url key, I am using :
[photo objectForKey:#"url"];
And it's working absolutely fine.
What am I doing wrong with the uids key ?